Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: conntrack: remove error callback and handle icmp from core

icmp(v6) are the only two layer four protocols that need the error()
callback (to handle icmp errors that are related to an established
connections, e.g. packet too big, port unreachable and the like).

Remove the error callback and handle these two special cases from the core.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Florian Westphal and committed by
Pablo Neira Ayuso
6fe78fa4 0150ffba

+52 -22
+9 -4
include/net/netfilter/nf_conntrack_l4proto.h
··· 51 51 /* Called when a conntrack entry is destroyed */ 52 52 void (*destroy)(struct nf_conn *ct); 53 53 54 - int (*error)(struct nf_conn *tmpl, struct sk_buff *skb, 55 - unsigned int dataoff, 56 - const struct nf_hook_state *state); 57 - 58 54 /* called by gc worker if table is full */ 59 55 bool (*can_early_drop)(const struct nf_conn *ct); 60 56 ··· 93 97 struct module *me; 94 98 }; 95 99 100 + int nf_conntrack_icmpv4_error(struct nf_conn *tmpl, 101 + struct sk_buff *skb, 102 + unsigned int dataoff, 103 + const struct nf_hook_state *state); 104 + 105 + int nf_conntrack_icmpv6_error(struct nf_conn *tmpl, 106 + struct sk_buff *skb, 107 + unsigned int dataoff, 108 + const struct nf_hook_state *state); 96 109 /* Existing built-in generic protocol */ 97 110 extern const struct nf_conntrack_l4proto nf_conntrack_l4proto_generic; 98 111
+36 -7
net/netfilter/nf_conntrack_core.c
··· 1486 1486 return 0; 1487 1487 } 1488 1488 1489 + /* 1490 + * icmp packets need special treatment to handle error messages that are 1491 + * related to a connection. 1492 + * 1493 + * Callers need to check if skb has a conntrack assigned when this 1494 + * helper returns; in such case skb belongs to an already known connection. 1495 + */ 1496 + static unsigned int __cold 1497 + nf_conntrack_handle_icmp(struct nf_conn *tmpl, 1498 + struct sk_buff *skb, 1499 + unsigned int dataoff, 1500 + u8 protonum, 1501 + const struct nf_hook_state *state) 1502 + { 1503 + int ret; 1504 + 1505 + if (state->pf == NFPROTO_IPV4 && protonum == IPPROTO_ICMP) 1506 + ret = nf_conntrack_icmpv4_error(tmpl, skb, dataoff, state); 1507 + #if IS_ENABLED(CONFIG_IPV6) 1508 + else if (state->pf == NFPROTO_IPV6 && protonum == IPPROTO_ICMPV6) 1509 + ret = nf_conntrack_icmpv6_error(tmpl, skb, dataoff, state); 1510 + #endif 1511 + else 1512 + return NF_ACCEPT; 1513 + 1514 + if (ret <= 0) { 1515 + NF_CT_STAT_INC_ATOMIC(state->net, error); 1516 + NF_CT_STAT_INC_ATOMIC(state->net, invalid); 1517 + } 1518 + 1519 + return ret; 1520 + } 1521 + 1489 1522 unsigned int 1490 1523 nf_conntrack_in(struct sk_buff *skb, const struct nf_hook_state *state) 1491 1524 { ··· 1551 1518 1552 1519 l4proto = __nf_ct_l4proto_find(state->pf, protonum); 1553 1520 1554 - /* It may be an special packet, error, unclean... 1555 - * inverse of the return code tells to the netfilter 1556 - * core what to do with the packet. */ 1557 - if (l4proto->error != NULL) { 1558 - ret = l4proto->error(tmpl, skb, dataoff, state); 1521 + if (protonum == IPPROTO_ICMP || protonum == IPPROTO_ICMPV6) { 1522 + ret = nf_conntrack_handle_icmp(tmpl, skb, dataoff, 1523 + protonum, state); 1559 1524 if (ret <= 0) { 1560 - NF_CT_STAT_INC_ATOMIC(state->net, error); 1561 - NF_CT_STAT_INC_ATOMIC(state->net, invalid); 1562 1525 ret = -ret; 1563 1526 goto out; 1564 1527 }
+3 -5
net/netfilter/nf_conntrack_proto_icmp.c
··· 165 165 } 166 166 167 167 /* Small and modified version of icmp_rcv */ 168 - static int 169 - icmp_error(struct nf_conn *tmpl, 170 - struct sk_buff *skb, unsigned int dataoff, 171 - const struct nf_hook_state *state) 168 + int nf_conntrack_icmpv4_error(struct nf_conn *tmpl, 169 + struct sk_buff *skb, unsigned int dataoff, 170 + const struct nf_hook_state *state) 172 171 { 173 172 const struct icmphdr *icmph; 174 173 struct icmphdr _ih; ··· 354 355 .pkt_to_tuple = icmp_pkt_to_tuple, 355 356 .invert_tuple = icmp_invert_tuple, 356 357 .packet = icmp_packet, 357 - .error = icmp_error, 358 358 .destroy = NULL, 359 359 .me = NULL, 360 360 #if IS_ENABLED(CONFIG_NF_CT_NETLINK)
+4 -6
net/netfilter/nf_conntrack_proto_icmpv6.c
··· 184 184 IPPROTO_ICMPV6, "%s", msg); 185 185 } 186 186 187 - static int 188 - icmpv6_error(struct nf_conn *tmpl, 189 - struct sk_buff *skb, 190 - unsigned int dataoff, 191 - const struct nf_hook_state *state) 187 + int nf_conntrack_icmpv6_error(struct nf_conn *tmpl, 188 + struct sk_buff *skb, 189 + unsigned int dataoff, 190 + const struct nf_hook_state *state) 192 191 { 193 192 const struct icmp6hdr *icmp6h; 194 193 struct icmp6hdr _ih; ··· 365 366 .pkt_to_tuple = icmpv6_pkt_to_tuple, 366 367 .invert_tuple = icmpv6_invert_tuple, 367 368 .packet = icmpv6_packet, 368 - .error = icmpv6_error, 369 369 #if IS_ENABLED(CONFIG_NF_CT_NETLINK) 370 370 .tuple_to_nlattr = icmpv6_tuple_to_nlattr, 371 371 .nlattr_tuple_size = icmpv6_nlattr_tuple_size,