Re: DCCP conntrack/NAT

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Patrick McHardy wrote:
Gerrit Renker wrote:

- timewait transition -- question: is it possible to re-incarnate a new connection
     here instead of ignoring the (new) Request?

Yes, I'll change this. The tricker case is a reincarnation in the
reverse direction. The conntrack entry must be killed and recreated
since the state table is directional and the client/server roles
change. Also needs a bit more thought.


The last patch handled reincarnations in the original direction,
this one adds support for reopening a connection in the reverse
direction. I used role reversal instead of recreating the conntrack
entry since that should make it easier to add DCCP_LISTEN support
later on.

(Patch might not apply because of minor cleanups I made locally,
I'll push out a new tree later).
diff --git a/include/linux/netfilter/nf_conntrack_dccp.h b/include/linux/netfilter/nf_conntrack_dccp.h
index 33e57c8..f3b9ce8 100644
--- a/include/linux/netfilter/nf_conntrack_dccp.h
+++ b/include/linux/netfilter/nf_conntrack_dccp.h
@@ -15,12 +15,21 @@ enum ct_dccp_states {
 	CT_DCCP_INVALID,
 	__CT_DCCP_MAX
 };
-#define CT_DCCP_MAX	(__CT_DCCP_MAX - 1)
+#define CT_DCCP_MAX		(__CT_DCCP_MAX - 1)
+
+enum ct_dccp_roles {
+	CT_DCCP_ROLE_CLIENT,
+	CT_DCCP_ROLE_SERVER,
+	__CT_DCCP_ROLE_MAX
+};
+#define CT_DCCP_ROLE_MAX	(__CT_DCCP_ROLE_MAX - 1)
 
 #ifdef __KERNEL__
+#include <net/netfilter/nf_conntrack_tuple.h>
 
 struct nf_ct_dccp {
 	u_int8_t	state;
+	u_int8_t	role[IP_CT_DIR_MAX];
 	u_int64_t	handshake_seq;
 };
 
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index bad3c6a..f768936 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -138,8 +138,8 @@ static const char * const dccp_state_names[] = {
  * or a DCCP_RESPONSE.
  */
 static const u_int8_t
-dccp_state_table[IP_CT_DIR_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = {
-	[IP_CT_DIR_ORIGINAL] = {
+dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = {
+	[CT_DCCP_ROLE_CLIENT] = {
 		[DCCP_PKT_REQUEST] = {
 		/*
 		 * sNO -> sRQ		Regular Request
@@ -157,7 +157,7 @@ dccp_state_table[IP_CT_DIR_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = {
 		},
 		[DCCP_PKT_RESPONSE] = {
 		/*
-		 * A Response in the original direction is always invalid.
+		 * A Response from the client is always invalid.
 		 *
 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
 			sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV,
@@ -254,13 +254,23 @@ dccp_state_table[IP_CT_DIR_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] = {
 			sIG, sIG, sIG, sIG, sIG, sIG, sIG, sIG,
 		},
 	},
-	[IP_CT_DIR_REPLY] = {
+	[CT_DCCP_ROLE_SERVER] = {
 		[DCCP_PKT_REQUEST] = {
 		/*
-		 * A Request in the reply direction is always invalid.
+		 * A Request from the server is only valid for reopening a
+		 * connection in TIMEWAIT state.
+		 *
+		 * sNO -> sIV
+		 * sRQ -> sIV
+		 * sRS -> sIV
+		 * sPO -> sIV
+		 * sOP -> sIV
+		 * sCR -> sIV
+		 * sCG -> sIV
+		 * sTW -> sRQ		Reincarnation, must reverse roles
 		 *
 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
-			sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV
+			sIV, sIV, sIV, sIV, sIV, sIV, sIV, sRQ
 		},
 		[DCCP_PKT_RESPONSE] = {
 		/*
@@ -410,7 +420,7 @@ static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
 	dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
 	BUG_ON(dh == NULL);
 
-	state = dccp_state_table[IP_CT_DIR_ORIGINAL][dh->dccph_type][CT_DCCP_NONE];
+	state = dccp_state_table[CT_DCCP_ROLE_CLIENT][dh->dccph_type][CT_DCCP_NONE];
 	switch (state) {
 	default:
 		if (nf_ct_dccp_loose == 0) {
@@ -425,6 +435,8 @@ static int dccp_new(struct nf_conn *ct, const struct sk_buff *skb,
 	}
 
 	ct->proto.dccp.state = CT_DCCP_NONE;
+	ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
+	ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
 	return 1;
 
 out_invalid:
@@ -446,8 +458,10 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
 		       unsigned int dataoff, enum ip_conntrack_info ctinfo,
 		       int pf, unsigned int hooknum)
 {
+	enum ip_conntrack_dir dir = CTINFO2DIR(ctinfo);
 	struct dccp_hdr _dh, *dh;
 	u_int8_t type, old_state, new_state;
+	enum ct_dccp_roles role;
 
 	dh = skb_header_pointer(skb, dataoff, sizeof(_dh), &dh);
 	BUG_ON(dh == NULL);
@@ -463,10 +477,20 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
 
 	write_lock_bh(&dccp_lock);
 
+	role = ct->proto.dccp.role[dir];
 	old_state = ct->proto.dccp.state;
-	new_state = dccp_state_table[CTINFO2DIR(ctinfo)][type][old_state];
+	new_state = dccp_state_table[role][type][old_state];
 
 	switch (new_state) {
+	case CT_DCCP_REQUEST:
+		if (old_state == CT_DCCP_TIMEWAIT &&
+		    role == CT_DCCP_ROLE_SERVER) {
+			/* Reincarnation in the reverse direction: reopen and
+			 * reverse client/server roles. */
+			ct->proto.dccp.role[dir] = CT_DCCP_ROLE_CLIENT;
+			ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_SERVER;
+		}
+		break;
 	case CT_DCCP_RESPOND:
 		if (old_state == CT_DCCP_REQUEST)
 			ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);

[Index of Archives]     [Linux Kernel]     [IETF DCCP]     [Linux Networking]     [Git]     [Security]     [Linux Assembly]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]

  Powered by Linux