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

netfilter: nf_conntrack: properly account terminating packets

Currently the last packet of a connection isn't accounted when its causing
abnormal termination.

Introduces nf_ct_kill_acct() which increments the accounting counters on
conntrack kill. The new function was necessary, because there are calls
to nf_ct_kill() which don't need accounting:

nf_conntrack_proto_tcp.c line ~847:
Kills ct and returns NF_REPEAT. We don't want to count twice.

nf_conntrack_proto_tcp.c line ~880:
Kills ct and returns NF_DROP. I think we don't want to count dropped
packets.

nf_conntrack_netlink.c line ~824:
As far as I can see ctnetlink_del_conntrack() is used to destroy a
conntrack on behalf of the user. There is an sk_buff, but I don't think
this is an actual packet. Incrementing counters here is therefore not
desired.

Signed-off-by: Fabian Hugelshofer <hugelshofer2006@gmx.ch>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Fabian Hugelshofer and committed by
David S. Miller
718d4ad9 51091764

+36 -7
+18 -1
include/net/netfilter/nf_conntrack.h
··· 223 223 __nf_ct_refresh_acct(ct, 0, skb, extra_jiffies, 0); 224 224 } 225 225 226 - extern void nf_ct_kill(struct nf_conn *ct); 226 + extern void __nf_ct_kill_acct(struct nf_conn *ct, 227 + enum ip_conntrack_info ctinfo, 228 + const struct sk_buff *skb, 229 + int do_acct); 230 + 231 + /* kill conntrack and do accounting */ 232 + static inline void nf_ct_kill_acct(struct nf_conn *ct, 233 + enum ip_conntrack_info ctinfo, 234 + const struct sk_buff *skb) 235 + { 236 + __nf_ct_kill_acct(ct, ctinfo, skb, 1); 237 + } 238 + 239 + /* kill conntrack without accounting */ 240 + static inline void nf_ct_kill(struct nf_conn *ct) 241 + { 242 + __nf_ct_kill_acct(ct, 0, NULL, 0); 243 + } 227 244 228 245 /* These are for NAT. Icky. */ 229 246 /* Update TCP window tracking data when NAT mangles the packet */
+1 -1
net/ipv4/netfilter/nf_conntrack_proto_icmp.c
··· 88 88 (theoretically possible with SMP) */ 89 89 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 90 90 if (atomic_dec_and_test(&ct->proto.icmp.count)) 91 - nf_ct_kill(ct); 91 + nf_ct_kill_acct(ct, ctinfo, skb); 92 92 } else { 93 93 atomic_inc(&ct->proto.icmp.count); 94 94 nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+1 -1
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
··· 90 90 (theoretically possible with SMP) */ 91 91 if (CTINFO2DIR(ctinfo) == IP_CT_DIR_REPLY) { 92 92 if (atomic_dec_and_test(&ct->proto.icmp.count)) 93 - nf_ct_kill(ct); 93 + nf_ct_kill_acct(ct, ctinfo, skb); 94 94 } else { 95 95 atomic_inc(&ct->proto.icmp.count); 96 96 nf_conntrack_event_cache(IPCT_PROTOINFO_VOLATILE, skb);
+14 -2
net/netfilter/nf_conntrack_core.c
··· 848 848 } 849 849 EXPORT_SYMBOL_GPL(__nf_ct_refresh_acct); 850 850 851 - void nf_ct_kill(struct nf_conn *ct) 851 + void __nf_ct_kill_acct(struct nf_conn *ct, 852 + enum ip_conntrack_info ctinfo, 853 + const struct sk_buff *skb, 854 + int do_acct) 852 855 { 856 + #ifdef CONFIG_NF_CT_ACCT 857 + if (do_acct) { 858 + spin_lock_bh(&nf_conntrack_lock); 859 + ct->counters[CTINFO2DIR(ctinfo)].packets++; 860 + ct->counters[CTINFO2DIR(ctinfo)].bytes += 861 + skb->len - skb_network_offset(skb); 862 + spin_unlock_bh(&nf_conntrack_lock); 863 + } 864 + #endif 853 865 if (del_timer(&ct->timeout)) 854 866 ct->timeout.function((unsigned long)ct); 855 867 } 856 - EXPORT_SYMBOL_GPL(nf_ct_kill); 868 + EXPORT_SYMBOL_GPL(__nf_ct_kill_acct); 857 869 858 870 #if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE) 859 871
+1 -1
net/netfilter/nf_conntrack_proto_dccp.c
··· 475 475 if (type == DCCP_PKT_RESET && 476 476 !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) { 477 477 /* Tear down connection immediately if only reply is a RESET */ 478 - nf_ct_kill(ct); 478 + nf_ct_kill_acct(ct, ctinfo, skb); 479 479 return NF_ACCEPT; 480 480 } 481 481
+1 -1
net/netfilter/nf_conntrack_proto_tcp.c
··· 959 959 problem case, so we can delete the conntrack 960 960 immediately. --RR */ 961 961 if (th->rst) { 962 - nf_ct_kill(ct); 962 + nf_ct_kill_acct(ct, ctinfo, skb); 963 963 return NF_ACCEPT; 964 964 } 965 965 } else if (!test_bit(IPS_ASSURED_BIT, &ct->status)