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

netfilter: nf_ct_icmp: keep the ICMP ct entries longer

Current conntrack code kills the ICMP conntrack entry as soon as
the first reply is received. This is incorrect, as we then see only
the first ICMP echo reply out of several possible duplicates as
ESTABLISHED, while the rest will be INVALID. Also this unnecessarily
increases the conntrackd traffic on H-A firewalls.

Make all the ICMP conntrack entries (including the replied ones)
last for the default of nf_conntrack_icmp{,v6}_timeout seconds.

Signed-off-by: Jan "Yenya" Kasprzak <kas@fi.muni.cz>
Signed-off-by: Patrick McHardy <kaber@trash.net>

authored by

Jan Kasprzak and committed by
Patrick McHardy
f87fb666 17f2f52b

+8 -45
-11
include/net/netfilter/ipv4/nf_conntrack_icmp.h
··· 1 - #ifndef _NF_CONNTRACK_ICMP_H 2 - #define _NF_CONNTRACK_ICMP_H 3 - /* ICMP tracking. */ 4 - #include <asm/atomic.h> 5 - 6 - struct ip_ct_icmp 7 - { 8 - /* Optimization: when number in == number out, forget immediately. */ 9 - atomic_t count; 10 - }; 11 - #endif /* _NF_CONNTRACK_ICMP_H */
-7
include/net/netfilter/ipv6/nf_conntrack_icmpv6.h
··· 9 9 10 10 #ifndef _NF_CONNTRACK_ICMPV6_H 11 11 #define _NF_CONNTRACK_ICMPV6_H 12 - #include <asm/atomic.h> 13 12 14 13 #ifndef ICMPV6_NI_QUERY 15 14 #define ICMPV6_NI_QUERY 139 ··· 16 17 #ifndef ICMPV6_NI_REPLY 17 18 #define ICMPV6_NI_REPLY 140 18 19 #endif 19 - 20 - struct nf_ct_icmpv6 21 - { 22 - /* Optimization: when number in == number out, forget immediately. */ 23 - atomic_t count; 24 - }; 25 20 26 21 #endif /* _NF_CONNTRACK_ICMPV6_H */
-3
include/net/netfilter/nf_conntrack.h
··· 23 23 #include <linux/netfilter/nf_conntrack_dccp.h> 24 24 #include <linux/netfilter/nf_conntrack_sctp.h> 25 25 #include <linux/netfilter/nf_conntrack_proto_gre.h> 26 - #include <net/netfilter/ipv4/nf_conntrack_icmp.h> 27 26 #include <net/netfilter/ipv6/nf_conntrack_icmpv6.h> 28 27 29 28 #include <net/netfilter/nf_conntrack_tuple.h> ··· 33 34 struct nf_ct_dccp dccp; 34 35 struct ip_ct_sctp sctp; 35 36 struct ip_ct_tcp tcp; 36 - struct ip_ct_icmp icmp; 37 - struct nf_ct_icmpv6 icmpv6; 38 37 struct nf_ct_gre gre; 39 38 }; 40 39
+4 -12
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
··· 82 82 u_int8_t pf, 83 83 unsigned int hooknum) 84 84 { 85 - /* Try to delete connection immediately after all replies: 86 - won't actually vanish as we still have skb, and del_timer 87 - means this will only run once even if count hits zero twice 88 - (theoretically possible with SMP) */ 89 - if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 90 - if (atomic_dec_and_test(&ct->proto.icmp.count)) 91 - nf_ct_kill_acct(ct, ctinfo, skb); 92 - } else { 93 - atomic_inc(&ct->proto.icmp.count); 94 - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); 95 - } 85 + /* Do not immediately delete the connection after the first 86 + successful reply to avoid excessive conntrackd traffic 87 + and also to handle correctly ICMP echo reply duplicates. */ 88 + nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmp_timeout); 96 89 97 90 return NF_ACCEPT; 98 91 } ··· 109 116 nf_ct_dump_tuple_ip(&ct->tuplehash[0].tuple); 110 117 return false; 111 118 } 112 - atomic_set(&ct->proto.icmp.count, 0); 113 119 return true; 114 120 } 115 121
+4 -12
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
··· 95 95 u_int8_t pf, 96 96 unsigned int hooknum) 97 97 { 98 - /* Try to delete connection immediately after all replies: 99 - won't actually vanish as we still have skb, and del_timer 100 - means this will only run once even if count hits zero twice 101 - (theoretically possible with SMP) */ 102 - if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 103 - if (atomic_dec_and_test(&ct->proto.icmp.count)) 104 - nf_ct_kill_acct(ct, ctinfo, skb); 105 - } else { 106 - atomic_inc(&ct->proto.icmp.count); 107 - nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); 108 - } 98 + /* Do not immediately delete the connection after the first 99 + successful reply to avoid excessive conntrackd traffic 100 + and also to handle correctly ICMP echo reply duplicates. */ 101 + nf_ct_refresh_acct(ct, ctinfo, skb, nf_ct_icmpv6_timeout); 109 102 110 103 return NF_ACCEPT; 111 104 } ··· 124 131 type + 128); 125 132 return false; 126 133 } 127 - atomic_set(&ct->proto.icmp.count, 0); 128 134 return true; 129 135 } 130 136