Re: DCCP conntrack/NAT

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

 



Patrick McHardy wrote:
Gerrit Renker wrote:
    State Transitions in the original direction
    ===========================================

 * DCCP-Request:
- in state Respond (sRS -> sRS), the Request is illegal (Respond is server state)

- also, the CLOSEREQ state transition (sCR -> sIG) is illegal: Requests are sent by clients only, and CLOSEREQ can only be entered by servers

We track both sides, so we must also define which client packets
are valid in which server state. This particular one is part of
the unfinished resync feature. The firewall might be out of sync
with both endpoints. If connection pickup is enabled it should
let packets that might establish a new connection pass and resync
when the other side responds with a valid Response. I need to
think about this a bit more, but I've marked it with FIXME for
now :)

I've added this patch on top to handle the out-of-sync case by
letting Requests pass in (almost) any state and resyncing when
seeing a valid Response.

Last TODO before the DCCP_LISTEN support is to fix connection
pickup for established connections. Since it doesn't see the
initial Request/Response it doesn't know which side has which
role and also can't properly pick an inital state.
diff --git a/include/linux/netfilter/nf_conntrack_dccp.h b/include/linux/netfilter/nf_conntrack_dccp.h
index 41ffdf8..40dcc82 100644
--- a/include/linux/netfilter/nf_conntrack_dccp.h
+++ b/include/linux/netfilter/nf_conntrack_dccp.h
@@ -30,6 +30,8 @@ enum ct_dccp_roles {
 struct nf_ct_dccp {
 	u_int8_t	role[IP_CT_DIR_MAX];
 	u_int8_t	state;
+	u_int8_t	last_pkt;
+	u_int8_t	last_dir;
 	u_int64_t	handshake_seq;
 };
 
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index a89113d..96bd70c 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -147,10 +147,10 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
 		 * sRQ -> sRQ		Retransmitted Request or reincarnation
 		 * sRS -> sRS		Retransmitted Request (apparently Response
 		 * 			got lost after we saw it) or reincarnation
-		 * sPO -> sIG		Request during PARTOPEN state, server will ignore it
-		 * sOP -> sIG		Request during OPEN state: server will ignore it
-		 * sCR -> sIG		FIXME MUST respond with Close to CloseReq (8.3.)
-		 * sCG -> sIG
+		 * sPO -> sIG		Ignore, conntrack might be out of sync
+		 * sOP -> sIG		Ignore, conntrack might be out of sync
+		 * sCR -> sIG		Ignore, conntrack might be out of sync
+		 * sCG -> sIG		Ignore, conntrack might be out of sync
 		 * sTW -> sRQ		Reincarnation
 		 *
 		 *	sNO, sRQ, sRS, sPO. sOP, sCR, sCG, sTW, */
@@ -158,10 +158,18 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
 		},
 		[DCCP_PKT_RESPONSE] = {
 		/*
-		 * A Response from the client is always invalid.
+		 * sNO -> sIV		Invalid
+		 * sRQ -> sIG		Ignore, might be response to ignored Request
+		 * sRS -> sIG		Ignore, might be response to ignored Request
+		 * sPO -> sIG		Ignore, might be response to ignored Request
+		 * sOP -> sIG		Ignore, might be response to ignored Request
+		 * sCR -> sIG		Ignore, might be response to ignored Request
+		 * sCG -> sIG		Ignore, might be response to ignored Request
+		 * sTW -> sIV		Invalid, reincarnation in reverse direction
+		 *			goes through sRQ
 		 *
 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
-			sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV,
+			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sIV,
 		},
 		[DCCP_PKT_ACK] = {
 		/*
@@ -258,20 +266,17 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
 	[CT_DCCP_ROLE_SERVER] = {
 		[DCCP_PKT_REQUEST] = {
 		/*
-		 * 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
+		 * sNO -> sIV		Invalid
+		 * sRQ -> sIG		Ignore, conntrack might be out of sync
+		 * sRS -> sIG		Ignore, conntrack might be out of sync
+		 * sPO -> sIG		Ignore, conntrack might be out of sync
+		 * sOP -> sIG		Ignore, conntrack might be out of sync
+		 * sCR -> sIG		Ignore, conntrack might be out of sync
+		 * sCG -> sIG		Ignore, conntrack might be out of sync
 		 * sTW -> sRQ		Reincarnation, must reverse roles
 		 *
 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
-			sIV, sIV, sIV, sIV, sIV, sIV, sIV, sRQ
+			sIV, sIG, sIG, sIG, sIG, sIG, sIG, sRQ
 		},
 		[DCCP_PKT_RESPONSE] = {
 		/*
@@ -279,13 +284,13 @@ dccp_state_table[CT_DCCP_ROLE_MAX + 1][DCCP_PKT_SYNCACK + 1][CT_DCCP_MAX + 1] =
 		 * sRQ -> sRS		Response to clients Request
 		 * sRS -> sRS		Retransmitted Response (8.1.3. SHOULD NOT)
 		 * sPO -> sIG		Response to an ignored Request or late retransmit
-		 * sOP -> sIG		Invalid
-		 * sCR -> sIG		Invalid
-		 * sCG -> sIG		Invalid
-		 * sTW -> sIG		Invalid
+		 * sOP -> sIG		Ignore, might be response to ignored Request
+		 * sCR -> sIG		Ignore, might be response to ignored Request
+		 * sCG -> sIG		Ignore, might be response to ignored Request
+		 * sTW -> sIV		Invalid, Request from client in sTW moves to sRQ
 		 *
 		 *	sNO, sRQ, sRS, sPO, sOP, sCR, sCG, sTW */
-			sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIG
+			sIV, sRS, sRS, sIG, sIG, sIG, sIG, sIV
 		},
 		[DCCP_PKT_ACK] = {
 		/*
@@ -503,6 +508,20 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
 			set_bit(IPS_ASSURED_BIT, &ct->status);
 		break;
 	case CT_DCCP_IGNORE:
+		/*
+		 * Connection tracking might be out of sync, so we ignore
+		 * packets that might establish a new connection and resync
+		 * if the server responds with a valid Response.
+		 */
+		if (ct->proto.dccp.last_dir == !dir &&
+		    ct->proto.dccp.last_pkt == DCCP_PKT_REQUEST &&
+		    type == DCCP_PKT_RESPONSE) {
+			ct->proto.dccp.role[!dir] = CT_DCCP_ROLE_CLIENT;
+			ct->proto.dccp.role[dir] = CT_DCCP_ROLE_SERVER;
+			ct->proto.dccp.handshake_seq = dccp_hdr_seq(dh);
+			new_state = CT_DCCP_RESPOND;
+			break;
+		}
 		write_unlock_bh(&dccp_lock);
 		if (LOG_INVALID(IPPROTO_DCCP))
 			nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
@@ -516,6 +535,8 @@ static int dccp_packet(struct nf_conn *ct, const struct sk_buff *skb,
 		return -NF_ACCEPT;
 	}
 
+	ct->proto.dccp.last_dir = dir;
+	ct->proto.dccp.last_pkt = type;
 	ct->proto.dccp.state = new_state;
 	write_unlock_bh(&dccp_lock);
 	nf_ct_refresh_acct(ct, ctinfo, skb, dccp_timeout[new_state]);

[Index of Archives]     [Netfitler Users]     [LARTC]     [Bugtraq]     [Yosemite Forum]

  Powered by Linux