embox

Форк
0
/
ip_input.c 
186 строк · 5.0 Кб
1
/**
2
 * @file
3
 * @brief The Internet Protocol (IP) module.
4
 *
5
 * @date 17.03.09
6
 * @author Alexandr Batyukov
7
 * @author Nikolay Korotky
8
 * @author Vladimir Sokolov
9
 * @author Ilia Vaprol
10
 */
11

12
#include <arpa/inet.h>
13
#include <string.h>
14
#include <errno.h>
15

16
#include <util/log.h>
17

18
#include <net/l3/ipv4/ip.h>
19
#include <net/l3/ipv4/ip_options.h>
20
#include <net/l3/icmpv4.h>
21
#include <net/l4/udp.h>
22
#include <net/socket/raw.h>
23
#include <net/inetdevice.h>
24
#include <net/l3/route.h>
25
#include <net/l3/ipv4/ip_fragment.h>
26
#include <net/netfilter.h>
27
#include <net/l2/ethernet.h>
28
#include <net/lib/ipv4.h>
29

30
#include <embox/net/proto.h>
31
#include <embox/net/pack.h>
32

33
EMBOX_NET_PACK(ETH_P_IP, ip_rcv);
34

35
static int ip_rcv(struct sk_buff *skb, struct net_device *dev) {
36
	net_device_stats_t *stats = &dev->stats;
37
	const struct net_proto *nproto;
38
	iphdr_t *iph = ip_hdr(skb);
39
	__u16 old_check;
40
	size_t ip_len;
41
	int optlen;
42
	sk_buff_t *complete_skb;
43

44
	/**
45
	 *   RFC1122: 3.1.2.2 MUST silently discard any IP frame that fails the checksum.
46
	 *   Is the datagram acceptable?
47
	 *   1.  Length at least the size of an ip header
48
	 *   2.  Version of 4
49
	 *   3.  Checksums correctly. [Speed optimisation for later, skip loopback checksums]
50
	 *   4.  Doesn't have a bogus length
51
	 */
52
	if (skb->len < dev->hdr_len + IP_MIN_HEADER_SIZE
53
			|| IP_HEADER_SIZE(iph) < IP_MIN_HEADER_SIZE
54
			|| skb->len < dev->hdr_len + IP_HEADER_SIZE(iph)) {
55
		log_debug("ip_rcv: invalid IPv4 header length");
56
		stats->rx_length_errors++;
57
		skb_free(skb);
58
		return 0; /* error: invalid header length */
59
	}
60

61

62
	if (iph->version != 4) {
63
		log_debug("ip_rcv: invalid IPv4 version");
64
		stats->rx_err++;
65
		skb_free(skb);
66
		return 0; /* error: not ipv4 */
67
	}
68

69
	old_check = iph->check;
70
	ip_set_check_field(iph);
71
	if (old_check != iph->check) {
72
		log_debug("ip_rcv: invalid checksum %hx(%hx)",
73
				ntohs(old_check), ntohs(iph->check));
74
		stats->rx_crc_errors++;
75
		skb_free(skb);
76
		return 0; /* error: invalid crc */
77
	}
78

79
	ip_len = ntohs(iph->tot_len);
80
	if (ip_len < IP_HEADER_SIZE(iph)
81
			|| skb->len < dev->hdr_len + ip_len) {
82
		log_debug("ip_rcv: invalid IPv4 length");
83
		stats->rx_length_errors++;
84
		skb_free(skb);
85
		return 0; /* error: invalid length */
86
	}
87

88
	/* Setup transport layer (L4) header */
89
	skb->h.raw = skb->nh.raw + IP_HEADER_SIZE(iph);
90

91
	/* Validating */
92
	if (0 != nf_test_skb(NF_CHAIN_INPUT, NF_TARGET_ACCEPT, skb)) {
93
		log_debug("ip_rcv: dropped by input netfilter");
94
		stats->rx_dropped++;
95
		skb_free(skb);
96
		return 0; /* error: dropped */
97
	}
98

99
	/* Forwarding */
100
	assert(skb->dev);
101
	if (!inetdev_get_by_dev(skb->dev)) {
102
		log_debug("ip_rcv: dropped by input  because inet_dev is not set");
103
		skb_free(skb);
104
		return 0; /* didn't set inet dev yet */
105
	}
106

107
	if (inetdev_get_by_dev(skb->dev)->ifa_address != 0) {
108
		/**
109
		 * FIXME
110
		 * This check needed for BOOTP protocol
111
		 * disable forwarding if interface is not set yet
112
		 */
113
		/**
114
		 * Check the destination address, and if it doesn't match
115
		 * any of own addresses, retransmit packet according to the routing table.
116
		 */
117
#if defined(NET_NAMESPACE_ENABLED) && (NET_NAMESPACE_ENABLED == 1)
118
		if (!ip_is_local_net_ns(iph->daddr, IP_LOCAL_BROADCAST,
119
					skb->dev->net_ns)) {
120
#else
121
		if (!ip_is_local(iph->daddr, IP_LOCAL_BROADCAST)) {
122
#endif
123
			if (0 != nf_test_skb(NF_CHAIN_FORWARD, NF_TARGET_ACCEPT, skb)) {
124
				log_debug("ip_rcv: dropped by forward netfilter");
125
				stats->rx_dropped++;
126
				skb_free(skb);
127
				return 0; /* error: dropped */
128
			}
129
			return ip_forward(skb);
130
		}
131
	}
132

133
	memset(skb->cb, 0, sizeof(skb->cb));
134
	optlen = IP_HEADER_SIZE(iph) - IP_MIN_HEADER_SIZE;
135
	if (optlen > 0) {
136
		/* NOTE : maybe it'd be better to copy skb here,
137
		 * 'cause options may cause modifications
138
		 * but smart people who wrote linux kernel
139
		 * say that this is extremely rarely needed
140
		 */
141
		ip_options_t *opts = (ip_options_t*)(skb->cb);
142

143
		memset(skb->cb, 0, sizeof(skb->cb));
144
		opts->optlen = optlen;
145
		if (ip_options_compile(skb, opts)) {
146
			log_debug("ip_rcv: invalid options");
147
			stats->rx_err++;
148
			skb_free(skb);
149
			return 0; /* error: bad ops */
150
		}
151
		if (ip_options_handle_srr(skb)) {
152
			log_debug("ip_rcv: can't handle options");
153
			stats->tx_err++;
154
			skb_free(skb);
155
			return 0; /* error: can't handle ops */
156
		}
157
	}
158

159
	/* It's very useful for us to have complete packet even for forwarding
160
	 * (we may apply any filter, we may perform NAT etc),
161
	 * but it'll break routing if different parts of a fragmented
162
	 * packet will use different routes. So they can't be assembled.
163
	 * See RFC 1812 for details
164
	 */
165
	if (ntohs(skb->nh.iph->frag_off) & (IP_MF | IP_OFFSET)) {
166
		if ((complete_skb = ip_defrag(skb)) == NULL) {
167
			return 0;
168
		} else {
169
			skb = complete_skb;
170
			iph = ip_hdr(complete_skb);
171
		}
172
	}
173

174
	/* When a packet is received, it is passed to any raw sockets
175
	 * which have been bound to its protocol or to socket with concrete protocol */
176
	raw_rcv(skb);
177

178
	nproto = net_proto_lookup(ETH_P_IP, iph->proto);
179
	if (nproto != NULL) {
180
		return nproto->handle(skb);
181
	}
182

183
	log_debug("ip_rcv: unknown protocol %d", iph->proto);
184
	skb_free(skb);
185
	return 0; /* error: nobody wants this packet */
186
}
187

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.