conntrack event API updates
Subsystems (2)
PATCH 1/1 conntrack event API updates
This includes three fixes:
a) nfcache bits are reset once the events has been delivered. Loopback connections events are notified twice.
b) Don't kill NFC_IP_*. Just more it into a #ifndef __KERNEL__ fence, that way we don't break iptables backward compilation.
c) IPCT_DESTROY is delivered from destroy_conntrack. Some users has reported out of logical order event notification. This fixes the problem.
conntrack event API
net/ipv4/netfilter/ip_conntrack_standalone.c +6 -0
@@ -963,6 +963,12 @@ { } +#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS +EXPORT_SYMBOL (ip_conntrack_chain); +EXPORT_SYMBOL (ip_conntrack_expect_chain); +EXPORT_SYMBOL (ip_conntrack_register_notifier); +EXPORT_SYMBOL (ip_conntrack_unregister_notifier); +#endif EXPORT_SYMBOL (ip_conntrack_protocol_register);EXPORT_SYMBOL (ip_conntrack_protocol_unregister);EXPORT_SYMBOL (ip_ct_get_tuple);
include/linux/netfilter_ipv4.h +3 -0
@@ -8,6 +8,8 @@#include <linux/config.h> #include <linux/netfilter.h> +/* Old iptables versions need this: backward compatibility compilation */ +#ifndef __KERNEL__/* IP Cache bits. */ /* Src IP address. */ #define NFC_IP_SRC 0x0001
@@ -35,6 +37,7 @@#define NFC_IP_DST_PT 0x0400/* Something else about the proto */ #define NFC_IP_PROTO_UNKNOWN 0x2000 +#endif /* IP Hooks */ /* After promisc drops, checksum checks. */
net/ipv4/netfilter/ip_conntrack_proto_udp.c +3 -2
@@ -64,7 +64,7 @@/* Returns verdict for packet, and may modify conntracktype */ static int udp_packet (struct ip_conntrack *conntrack, -const struct sk_buff *skb, +struct sk_buff *skb,enum ip_conntrack_info ctinfo) {/* If we've seen traffic both ways, this is some kind of UDP
@@ -73,7 +73,8 @@ip_ct_refresh_acct (conntrack, ctinfo, skb, ip_ct_udp_timeout_stream);/* Also, more likely to be important, and not a probe */ -set_bit (IPS_ASSURED_BIT , &conntrack->status); +if (!test_and_set_bit (IPS_ASSURED_BIT , &conntrack->status)) +ip_conntrack_event_cache (IPCT_STATUS , skb); }else ip_ct_refresh_acct (conntrack, ctinfo, skb, ip_ct_udp_timeout);
net/ipv4/netfilter/ip_conntrack_proto_tcp.c +5 -1
@@ -843,7 +843,7 @@/* Returns verdict for packet, or -1 for invalid. */ static int tcp_packet (struct ip_conntrack *conntrack, -const struct sk_buff *skb, +struct sk_buff *skb,enum ip_conntrack_info ctinfo) {enum tcp_conntrack new_state, old_state;
@@ -974,6 +974,10 @@ ? ip_ct_tcp_timeout_max_retrans : *tcp_timeouts[new_state];WRITE_UNLOCK (&tcp_lock); +ip_conntrack_event_cache (IPCT_PROTOINFO_VOLATILE , skb); +if (new_state != old_state) +ip_conntrack_event_cache (IPCT_PROTOINFO , skb); +if (!test_bit (IPS_SEEN_REPLY_BIT , &conntrack->status)) {/* If only reply is a RST, we can consider ourselves not to have an established connection: this is a fairly common
include/linux/netfilter_ipv4/ip_conntrack.h +12 -1
@@ -65,6 +65,10 @@/* Both together */ IPS_NAT_DONE_MASK = (IPS_DST_NAT_DONE |IPS_SRC_NAT_DONE ), + +/* Connection is destroyed (removed from lists), can not be unset. */ +IPS_DESTROYED_BIT =9 , + IPS_DESTROYED = (1 << IPS_DESTROYED_BIT), };#ifdef __KERNEL__
@@ -247,7 +251,7 @@/* Refresh conntrack for this many jiffies */ extern void ip_ct_refresh_acct (struct ip_conntrack *ct,enum ip_conntrack_info ctinfo, -const struct sk_buff *skb, +struct sk_buff *skb,unsigned long extra_jiffies);/* These are for NAT. Icky. */
@@ -277,6 +281,11 @@return test_bit (IPS_CONFIRMED_BIT , &ct->status); } +static inline int is_destroyed (struct ip_conntrack *ct) +{ +return test_bit (IPS_DESTROYED_BIT , &ct->status); +} +extern unsigned int ip_conntrack_htable_size;struct ip_conntrack_stat
@@ -300,6 +309,8 @@#define CONNTRACK_STAT_INC (count) (__get_cpu_var(ip_conntrack_stat).count++) +#include <linux/netfilter_ipv4/ip_conntrack_events.h> +#ifdef CONFIG_IP_NF_NAT_NEEDED static inline int ip_nat_initialized (struct ip_conntrack *conntrack,enum ip_nat_manip_type manip)
include/linux/netfilter_ipv4/ip_conntrack_events.h new file +138 -0
138 lines not on this page · raw message
net/ipv4/netfilter/ip_conntrack_ftp.c +8 -4
@@ -263,7 +263,8 @@ }/* We don't update if it's older than what we have. */ -static void update_nl_seq (u32 nl_seq,struct ip_ct_ftp_master *info,int dir) +static void update_nl_seq (u32 nl_seq,struct ip_ct_ftp_master *info,int dir, +struct sk_buff *skb) {unsigned int i, oldest =NUM_SEQ_TO_REMEMBER ;
@@ -277,10 +278,13 @@ oldest = i; } -if (info->seq_aft_nl_num[dir] <NUM_SEQ_TO_REMEMBER ) +if (info->seq_aft_nl_num[dir] <NUM_SEQ_TO_REMEMBER ) { info->seq_aft_nl[dir][info->seq_aft_nl_num[dir]++] = nl_seq; -else if (oldest !=NUM_SEQ_TO_REMEMBER ) +ip_conntrack_event_cache (IPCT_HELPINFO_VOLATILE , skb); + }else if (oldest !=NUM_SEQ_TO_REMEMBER ) { info->seq_aft_nl[dir][oldest] = nl_seq; +ip_conntrack_event_cache (IPCT_HELPINFO_VOLATILE , skb); + } } static int help(struct sk_buff **pskb,
@@ -440,7 +444,7 @@/* Now if this ends in \n, update ftp info. Seq may have been * adjusted by NAT code. */ if (ends_in_nl) -update_nl_seq (seq, ct_ftp_info,dir); +update_nl_seq (seq, ct_ftp_info,dir, *pskb); out:UNLOCK_BH (&ip_ftp_lock);return ret;
net/ipv4/netfilter/Kconfig +10 -0
@@ -692,5 +692,15 @@ Allows altering the ARP packet payload: source and destination hardware and network addresses. +config IP_NF_CONNTRACK_EVENTS + bool "Connection tracking events" + depends on IP_NF_CONNTRACK + help + If this option is enabled, the connection tracking code will + provide a notifier chain that can be used by other kernel code + to get notified about changes in the connection tracking state. + + IF unsure, say `N'. + endmenu
include/linux/netfilter.h +1 -1
@@ -22,7 +22,7 @@#define NF_MAX_VERDICT NF_STOP/* Generic cache responses from hook functions. -<= 0x2000 is used for protocol-flags. */ +<= 0x2000 is reserved for conntrack event cache. */ #define NFC_UNKNOWN 0x4000#define NFC_ALTERED 0x8000
net/ipv4/netfilter/ip_conntrack_proto_icmp.c +2 -1
@@ -89,7 +89,7 @@/* Returns verdict for packet, or -1 for invalid. */ static int icmp_packet (struct ip_conntrack *ct, -const struct sk_buff *skb, +struct sk_buff *skb,enum ip_conntrack_info ctinfo) {/* Try to delete connection immediately after all replies:
@@ -102,6 +102,7 @@ ct->timeout.function ((unsigned long )ct); }else {atomic_inc (&ct->proto.icmp.count); +ip_conntrack_event_cache (IPCT_PROTOINFO_VOLATILE , skb);ip_ct_refresh_acct (ct, ctinfo, skb, ip_ct_icmp_timeout); }
net/ipv4/netfilter/ip_conntrack_proto_generic.c +1 -1
@@ -49,7 +49,7 @@/* Returns verdict for packet, or -1 for invalid. */ static int packet (struct ip_conntrack *conntrack, -const struct sk_buff *skb, +struct sk_buff *skb,enum ip_conntrack_info ctinfo) {ip_ct_refresh_acct (conntrack, ctinfo, skb, ip_ct_generic_timeout);
include/linux/netfilter_ipv4/ip_conntrack_protocol.h +1 -1
@@ -34,7 +34,7 @@/* Returns verdict for packet, or -1 for invalid. */ int (*packet)(struct ip_conntrack *conntrack, -const struct sk_buff *skb, +struct sk_buff *skb,enum ip_conntrack_info ctinfo);/* Called when a new connection for this protocol found;
net/ipv4/netfilter/ip_conntrack_proto_sctp.c +3 -1
@@ -310,7 +310,7 @@/* Returns verdict for packet, or -1 for invalid. */ static int sctp_packet (struct ip_conntrack *conntrack, -const struct sk_buff *skb, +struct sk_buff *skb,enum ip_conntrack_info ctinfo) {enum sctp_conntrack newconntrack, oldsctpstate;
@@ -405,6 +405,8 @@ } conntrack->proto.sctp.state = newconntrack; +if (oldsctpstate != newconntrack) +ip_conntrack_event_cache (IPCT_PROTOINFO , skb);WRITE_UNLOCK (&sctp_lock); }
include/linux/netfilter_ipv4/ip_conntrack_core.h +6 -2
@@ -39,10 +39,14 @@/* Confirm a connection: returns NF_DROP if packet must be dropped. */ static inline int ip_conntrack_confirm (struct sk_buff **pskb) { +int ret =NF_ACCEPT ; +if ((*pskb)->nfct && !is_confirmed ((struct ip_conntrack *)(*pskb)->nfct)) -return __ip_conntrack_confirm (pskb); -return NF_ACCEPT ; + ret =__ip_conntrack_confirm (pskb); +ip_conntrack_deliver_cached_events (*pskb); + +return ret; }extern struct list_head *ip_conntrack_hash;
net/ipv4/netfilter/ip_conntrack_core.c +28 -4
@@ -76,6 +76,11 @@static LIST_HEAD (unconfirmed);static int ip_conntrack_vmalloc; +#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS +struct notifier_block *ip_conntrack_chain; +struct notifier_block *ip_conntrack_expect_chain; +#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */ + DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);void
@@ -157,6 +162,7 @@ {struct ip_conntrack_expect *exp = (void *)ul_expect; +ip_conntrack_expect_event (IPEXP_TIMEOUT , exp);WRITE_LOCK (&ip_conntrack_lock);unlink_expect (exp);WRITE_UNLOCK (&ip_conntrack_lock);
@@ -230,6 +236,9 @@IP_NF_ASSERT (atomic_read (&nfct->use) ==0 );IP_NF_ASSERT (!timer_pending (&ct->timeout)); +ip_conntrack_event (IPCT_DESTROY , ct); +set_bit (IPS_DESTROYED_BIT , &ct->status); +/* To make sure we don't get any weird locking issues here: * destroy_conntrack() MUST NOT be called with a write lock * to ip_conntrack_lock!!! -HW */
@@ -381,6 +390,15 @@set_bit (IPS_CONFIRMED_BIT , &ct->status);CONNTRACK_STAT_INC (insert);WRITE_UNLOCK (&ip_conntrack_lock); +if (ct->helper) +ip_conntrack_event_cache (IPCT_HELPER , *pskb); +#ifdef CONFIG_IP_NF_NAT_NEEDED +if (IPS_NAT_DONE_MASK & ct->status) +ip_conntrack_event_cache (IPCT_NATINFO , *pskb); +#endif +ip_conntrack_event_cache (master_ct (ct) ? +IPCT_RELATED :IPCT_NEW , *pskb); +return NF_ACCEPT ; }
@@ -630,6 +648,8 @@/* FIXME: Do this right please. --RR */ (*pskb)->nfcache |=NFC_UNKNOWN ; +ip_conntrack_event_cache_init (*pskb); +/* Doesn't cover locally-generated broadcast, so not worth it. */ #if 0 /* Ignore broadcast: no `connection'. */
@@ -681,8 +701,8 @@return -ret; } -if (set_reply) -set_bit (IPS_SEEN_REPLY_BIT , &ct->status); +if (set_reply && !test_and_set_bit (IPS_SEEN_REPLY_BIT , &ct->status)) +ip_conntrack_event_cache (IPCT_STATUS , *pskb);return ret; }
@@ -802,7 +822,7 @@int ip_conntrack_expect_related (struct ip_conntrack_expect *expect) {struct ip_conntrack_expect *i; -int ret; +int ret, inserted =0 ;DEBUGP ("ip_conntrack_expect_related %p\n" , related_to);DEBUGP ("tuple: " );DUMP_TUPLE (&expect->tuple);
@@ -830,9 +850,12 @@evict_oldest_expect (expect->master);ip_conntrack_expect_insert (expect); + inserted =1 ; ret =0 ; out:WRITE_UNLOCK (&ip_conntrack_lock); +if (inserted) +ip_conntrack_expect_event (IPEXP_NEW , expect);return ret; }
@@ -915,7 +938,7 @@/* Refresh conntrack for this many jiffies and do accounting (if skb != NULL) */ void ip_ct_refresh_acct (struct ip_conntrack *ct,enum ip_conntrack_info ctinfo, -const struct sk_buff *skb, +struct sk_buff *skb,unsigned long extra_jiffies) {IP_NF_ASSERT (ct->timeout.data == (unsigned long )ct);
@@ -930,6 +953,7 @@if (del_timer (&ct->timeout)) { ct->timeout.expires = jiffies + extra_jiffies;add_timer (&ct->timeout); +ip_conntrack_event_cache (IPCT_REFRESH , skb); }ct_add_counters (ct, ctinfo, skb);WRITE_UNLOCK (&ip_conntrack_lock);