Skip to contentSkip to conversation

connection tracking event per packet

PATCH New Pablo Neira 1 participant 1 message Nov 16, 2004

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 connection tracking event per packet

Hi,

I've finished the first version of the conntrack event per packet patch, I've been testing it and I didn't find any problem at the moment.

It includes 11 events, still 3 bits free for further use. Four of them should provide enough info handle expectations replication.

IPCT_RELATED: expectaction has arrived
IPCT_HELPER: new helper set to a master conntrack
IPCT_HELPINFO: update helper private info
IPCT_HELPINFO_VOLATILE: update helper private info, it could be picked up, so mostly ignored.

All the events for confirmed conntracks are delivered in __ip_conntrack_confirm.

Three functions to send events:

ip_conntrack_event: send an asynchronous event, for example, conntrack destruction.
ip_conntrack_event_cache: set event in the per packet cache. ip_conntrack_deliver_cached_events: deliver events! :-)

Two functions exported:

ip_conntrack_register_notifier
ip_conntrack_unregister_notifier

See that I'm sending nat events in __ip_conntrack_confirm because alter_reply doesn't have a skb as parameter and I didn't want to trash ip_nat_setup_info/ip_conntrack_alter_reply with a new parameter (a pointer to a skb). Same thing for the helper event and all ip_ct_find_helper.

I've removed the pick up stuff for TCP which I've inserted in my previous patch since I think that at this moment it's enough leaving ip_ct_tcp_loose set to 3. If someone wants a stateful firewalls which doesn't pick up TCP connection by default, just during the take over, I can recover the pick up feature. Later.

Comments welcome.

--
Pablo

===== include/linux/netfilter.h 1.13 vs edited =====

include/linux/netfilter.h +1 -1
@@ -21,7 +21,7 @@
 #define NF_MAX_VERDICT NF_REPEAT
 
 /* 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
 

===== include/linux/netfilter_ipv4.h 1.7 vs edited =====

include/linux/netfilter_ipv4.h +0 -28
@@ -8,34 +8,6 @@
 #include <linux/config.h>
 #include <linux/netfilter.h>
 
-/* IP Cache bits. */
-/* Src IP address. */
-#define NFC_IP_SRC		0x0001
-/* Dest IP address. */
-#define NFC_IP_DST		0x0002
-/* Input device. */
-#define NFC_IP_IF_IN		0x0004
-/* Output device. */
-#define NFC_IP_IF_OUT		0x0008
-/* TOS. */
-#define NFC_IP_TOS		0x0010
-/* Protocol. */
-#define NFC_IP_PROTO		0x0020
-/* IP options. */
-#define NFC_IP_OPTIONS		0x0040
-/* Frag & flags. */
-#define NFC_IP_FRAG		0x0080
-
-/* Per-protocol information: only matters if proto match. */
-/* TCP flags. */
-#define NFC_IP_TCPFLAGS		0x0100
-/* Source port. */
-#define NFC_IP_SRC_PT		0x0200
-/* Dest port. */
-#define NFC_IP_DST_PT		0x0400
-/* Something else about the proto */
-#define NFC_IP_PROTO_UNKNOWN	0x2000
-
 /* IP Hooks */
 /* After promisc drops, checksum checks. */
 #define NF_IP_PRE_ROUTING	0

===== include/linux/netfilter_ipv4/ip_conntrack.h 1.24 vs edited =====

include/linux/netfilter_ipv4/ip_conntrack.h +109 -1

134 lines not on this page · raw message

===== include/linux/netfilter_ipv4/ip_conntrack_core.h 1.11 vs edited =====

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 *skb)
 {
+	int ret = NF_ACCEPT;
+	
 	if (skb->nfct
 	    && !is_confirmed((struct ip_conntrack *)skb->nfct))
-		return __ip_conntrack_confirm(skb);
-	return NF_ACCEPT;
+		ret = __ip_conntrack_confirm(skb);
+	ip_conntrack_deliver_cached_events(skb);
+
+	return ret;
 }
 
 extern struct list_head *ip_conntrack_hash;

===== include/linux/netfilter_ipv4/ip_conntrack_protocol.h 1.10 vs edited =====

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/Kconfig 1.32 vs edited =====

net/ipv4/netfilter/Kconfig +10 -0
@@ -732,5 +732,15 @@
 
 	  To compile it as a module, choose M here.  If unsure, say N.
 
+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
 

===== net/ipv4/netfilter/ip_conntrack_proto_icmp.c 1.14 vs edited =====

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.10 vs edited =====

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);

===== net/ipv4/netfilter/ip_conntrack_proto_sctp.c 1.8 vs edited =====

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);
 	}
 

===== net/ipv4/netfilter/ip_conntrack_core.c 1.73 vs edited =====

net/ipv4/netfilter/ip_conntrack_core.c +24 -2
@@ -37,6 +37,7 @@
 #include <linux/err.h>
 #include <linux/percpu.h>
 #include <linux/moduleparam.h>
+#include <linux/notifier.h>
 
 /* This rwlock protects the main hash table, protocol/helper/expected
    registrations, conntrack timers*/
@@ -75,6 +76,10 @@
 struct ip_conntrack ip_conntrack_untracked;
 unsigned int ip_ct_log_invalid;
 
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+struct notifier_block *ip_conntrack_chain;
+#endif /* CONFIG_IP_NF_CONNTRACK_EVENTS */
+
 DEFINE_PER_CPU(struct ip_conntrack_stat, ip_conntrack_stat);
 
 inline void 
@@ -287,6 +292,8 @@
 	IP_NF_ASSERT(atomic_read(&nfct->use) == 0);
 	IP_NF_ASSERT(!timer_pending(&ct->timeout));
 
+	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 */
@@ -327,6 +334,7 @@
 {
 	struct ip_conntrack *ct = (void *)ul_conntrack;
 
+	ip_conntrack_event(IPCT_DESTROY, ct);
 	WRITE_LOCK(&ip_conntrack_lock);
 	/* Inside lock so preempt is disabled on module removal path.
 	 * Otherwise we can get spurious warnings. */
@@ -436,6 +444,14 @@
 		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, skb);
+#ifdef CONFIG_IP_NF_NAT_NEEDED
+		if (ct->nat.info.initialized)
+			ip_conntrack_event_cache(IPCT_NATINFO, skb);
+#endif
+		ip_conntrack_event_cache(master_ct(ct) ?
+					 IPCT_RELATED : IPCT_NEW, skb);
 		return NF_ACCEPT;
 	}
 
@@ -708,6 +724,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'. */
@@ -769,8 +787,10 @@
 			return NF_ACCEPT;
 		}
 	}
-	if (set_reply)
+	if (set_reply && !test_bit(IPS_SEEN_REPLY_BIT, &ct->status)) {
 		set_bit(IPS_SEEN_REPLY_BIT, &ct->status);
+		ip_conntrack_event_cache(IPCT_STATUS, *pskb);
+	}
 
 	return ret;
 }
@@ -1052,6 +1072,7 @@
 	if (i->ctrack->helper == me) {
 		/* Get rid of any expected. */
 		remove_expectations(i->ctrack, 0);
+		ip_conntrack_event(IPCT_HELPER, i->ctrack);
 		/* And *then* set helper to NULL */
 		i->ctrack->helper = NULL;
 	}
@@ -1092,7 +1113,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);
@@ -1107,6 +1128,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);

===== net/ipv4/netfilter/ip_conntrack_ftp.c 1.24 vs edited =====

net/ipv4/netfilter/ip_conntrack_ftp.c +1 -0
@@ -300,6 +300,7 @@
 			ct_ftp_info->seq_aft_nl[dir] = 
 						ntohl(th->seq) + datalen;
 			ct_ftp_info->seq_aft_nl_set[dir] = 1;
+			ip_conntrack_event_cache(IPCT_HELPINFO_VOLATILE, skb);
 		}
 	}
 

===== net/ipv4/netfilter/ip_conntrack_standalone.c 1.53 vs edited =====

net/ipv4/netfilter/ip_conntrack_standalone.c +5 -0
@@ -880,6 +880,11 @@
 {
 }
 
+#ifdef CONFIG_IP_NF_CONNTRACK_EVENTS
+EXPORT_SYMBOL(ip_conntrack_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(invert_tuplepr);

===== net/ipv4/netfilter/ip_conntrack_proto_tcp.c 1.24 vs edited =====

net/ipv4/netfilter/ip_conntrack_proto_tcp.c +5 -1
@@ -824,7 +824,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;
@@ -942,6 +942,10 @@
 		  && *tcp_timeouts[new_state] > ip_ct_tcp_timeout_max_retrans
 		  ? 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

===== net/ipv4/netfilter/ip_conntrack_proto_udp.c 1.14 vs edited =====

net/ipv4/netfilter/ip_conntrack_proto_udp.c +5 -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,10 @@
 		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_bit(IPS_ASSURED_BIT, &conntrack->status)) {
+			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);