Skip to content

Commit d44b723

Browse files
jukkarhenrikbrixandersen
authored andcommitted
net: Refactor IP checks just before sending packets
* Check IPv4 TTL or IPv6 hop limit and drop the packet if the value is 0 * Check the IP addresses so that we do the loopback check at runtime if the packet is destined to loopback interface. * Update the statistics properly for dropped packets. * Do not update sent packets if we drop packets. Signed-off-by: Jukka Rissanen <[email protected]>
1 parent 27d4c5d commit d44b723

File tree

1 file changed

+98
-34
lines changed

1 file changed

+98
-34
lines changed

subsys/net/ip/net_core.c

Lines changed: 98 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,6 @@ static void init_rx_queues(void)
203203
net_post_init();
204204
}
205205

206-
/* If loopback driver is enabled, then direct packets to it so the address
207-
* check is not needed.
208-
*/
209-
#if defined(CONFIG_NET_IP) && defined(CONFIG_NET_IP_ADDR_CHECK) && !defined(CONFIG_NET_LOOPBACK)
210-
/* Check if the IPv{4|6} addresses are proper. As this can be expensive,
211-
* make this optional.
212-
*/
213-
214206
static inline void copy_ll_addr(struct net_pkt *pkt)
215207
{
216208
memcpy(net_pkt_lladdr_src(pkt), net_pkt_lladdr_if(pkt),
@@ -219,15 +211,47 @@ static inline void copy_ll_addr(struct net_pkt *pkt)
219211
sizeof(struct net_linkaddr));
220212
}
221213

222-
static inline int check_ip_addr(struct net_pkt *pkt)
214+
/* Check if the IPv{4|6} addresses are proper. As this can be expensive,
215+
* make this optional. We still check the IPv4 TTL and IPv6 hop limit
216+
* if the corresponding protocol family is enabled.
217+
*/
218+
static inline int check_ip(struct net_pkt *pkt)
223219
{
224-
uint8_t family = net_pkt_family(pkt);
220+
uint8_t family;
221+
int ret;
222+
223+
if (!IS_ENABLED(CONFIG_NET_IP)) {
224+
return 0;
225+
}
226+
227+
family = net_pkt_family(pkt);
228+
ret = 0;
225229

226230
if (IS_ENABLED(CONFIG_NET_IPV6) && family == AF_INET6) {
231+
/* Drop IPv6 packet if hop limit is 0 */
232+
if (NET_IPV6_HDR(pkt)->hop_limit == 0) {
233+
NET_DBG("DROP: IPv6 hop limit");
234+
ret = -ENOMSG; /* silently drop the pkt, not an error */
235+
goto drop;
236+
}
237+
238+
if (!IS_ENABLED(CONFIG_NET_IP_ADDR_CHECK)) {
239+
return 0;
240+
}
241+
242+
#if defined(CONFIG_NET_LOOPBACK)
243+
/* If loopback driver is enabled, then send packets to it
244+
* as the address check is not needed.
245+
*/
246+
if (net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(DUMMY)) {
247+
return 0;
248+
}
249+
#endif
227250
if (net_ipv6_addr_cmp((struct in6_addr *)NET_IPV6_HDR(pkt)->dst,
228251
net_ipv6_unspecified_address())) {
229-
NET_DBG("IPv6 dst address missing");
230-
return -EADDRNOTAVAIL;
252+
NET_DBG("DROP: IPv6 dst address missing");
253+
ret = -EADDRNOTAVAIL;
254+
goto drop;
231255
}
232256

233257
/* If the destination address is our own, then route it
@@ -270,14 +294,36 @@ static inline int check_ip_addr(struct net_pkt *pkt)
270294
*/
271295
if (net_ipv6_is_addr_loopback(
272296
(struct in6_addr *)NET_IPV6_HDR(pkt)->src)) {
273-
NET_DBG("IPv6 loopback src address");
274-
return -EADDRNOTAVAIL;
297+
NET_DBG("DROP: IPv6 loopback src address");
298+
ret = -EADDRNOTAVAIL;
299+
goto drop;
275300
}
301+
276302
} else if (IS_ENABLED(CONFIG_NET_IPV4) && family == AF_INET) {
303+
/* Drop IPv4 packet if ttl is 0 */
304+
if (NET_IPV4_HDR(pkt)->ttl == 0) {
305+
NET_DBG("DROP: IPv4 ttl");
306+
ret = -ENOMSG; /* silently drop the pkt, not an error */
307+
goto drop;
308+
}
309+
310+
if (!IS_ENABLED(CONFIG_NET_IP_ADDR_CHECK)) {
311+
return 0;
312+
}
313+
314+
#if defined(CONFIG_NET_LOOPBACK)
315+
/* If loopback driver is enabled, then send packets to it
316+
* as the address check is not needed.
317+
*/
318+
if (net_if_l2(net_pkt_iface(pkt)) == &NET_L2_GET_NAME(DUMMY)) {
319+
return 0;
320+
}
321+
#endif
277322
if (net_ipv4_addr_cmp((struct in_addr *)NET_IPV4_HDR(pkt)->dst,
278323
net_ipv4_unspecified_address())) {
279-
NET_DBG("IPv4 dst address missing");
280-
return -EADDRNOTAVAIL;
324+
NET_DBG("DROP: IPv4 dst address missing");
325+
ret = -EADDRNOTAVAIL;
326+
goto drop;
281327
}
282328

283329
/* If the destination address is our own, then route it
@@ -308,16 +354,25 @@ static inline int check_ip_addr(struct net_pkt *pkt)
308354
* localhost subnet too.
309355
*/
310356
if (net_ipv4_is_addr_loopback((struct in_addr *)NET_IPV4_HDR(pkt)->src)) {
311-
NET_DBG("IPv4 loopback src address");
312-
return -EADDRNOTAVAIL;
357+
NET_DBG("DROP: IPv4 loopback src address");
358+
ret = -EADDRNOTAVAIL;
359+
goto drop;
313360
}
314361
}
315362

316-
return 0;
363+
return ret;
364+
365+
drop:
366+
if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
367+
if (family == AF_INET6) {
368+
net_stats_update_ipv6_drop(net_pkt_iface(pkt));
369+
} else {
370+
net_stats_update_ipv4_drop(net_pkt_iface(pkt));
371+
}
372+
}
373+
374+
return ret;
317375
}
318-
#else
319-
#define check_ip_addr(pkt) 0
320-
#endif
321376

322377
/* Called when data needs to be sent to network */
323378
int net_send_data(struct net_pkt *pkt)
@@ -332,22 +387,20 @@ int net_send_data(struct net_pkt *pkt)
332387
return -EINVAL;
333388
}
334389

335-
#if defined(CONFIG_NET_STATISTICS)
336-
switch (net_pkt_family(pkt)) {
337-
case AF_INET:
338-
net_stats_update_ipv4_sent(net_pkt_iface(pkt));
339-
break;
340-
case AF_INET6:
341-
net_stats_update_ipv6_sent(net_pkt_iface(pkt));
342-
break;
343-
}
344-
#endif
345-
346390
net_pkt_trim_buffer(pkt);
347391
net_pkt_cursor_init(pkt);
348392

349-
status = check_ip_addr(pkt);
393+
status = check_ip(pkt);
350394
if (status < 0) {
395+
/* Special handling for ENOMSG which is returned if packet
396+
* TTL is 0 or hop limit is 0. This is not an error as it is
397+
* perfectly valid case to set the limit to 0. In this case
398+
* we just silently drop the packet by returning 0.
399+
*/
400+
if (status == -ENOMSG) {
401+
return 0;
402+
}
403+
351404
return status;
352405
} else if (status > 0) {
353406
/* Packet is destined back to us so send it directly
@@ -362,6 +415,17 @@ int net_send_data(struct net_pkt *pkt)
362415
return -EIO;
363416
}
364417

418+
if (IS_ENABLED(CONFIG_NET_STATISTICS)) {
419+
switch (net_pkt_family(pkt)) {
420+
case AF_INET:
421+
net_stats_update_ipv4_sent(net_pkt_iface(pkt));
422+
break;
423+
case AF_INET6:
424+
net_stats_update_ipv6_sent(net_pkt_iface(pkt));
425+
break;
426+
}
427+
}
428+
365429
return 0;
366430
}
367431

0 commit comments

Comments
 (0)