diff options
author | Jozsef Kadlecsik <kadlec@blackhole.kfki.hu> | 2005-12-01 17:28:58 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2005-12-01 17:28:58 -0500 |
commit | 73f306024c15bd12e59677d6eaf43ecced614f04 (patch) | |
tree | 88d89bf7d54d51df8bd229ed9384e42f4064245a | |
parent | 5666c0947ede0432ba5148570aa66ffb9febff5b (diff) |
[NETFILTER]: Ignore ACKs ACKs on half open connections in TCP conntrack
Mounting NFS file systems after a (warm) reboot could take a long time if
firewalling and connection tracking was enabled.
The reason is that the NFS clients tends to use the same ports (800 and
counting down). Now on reboot, the server would still have a TCB for an
existing TCP connection client:800 -> server:2049. The client sends a
SYN from port 800 to server:2049, which elicits an ACK from the server.
The firewall on the client drops the ACK because (from its point of
view) the connection is still in half-open state, and it expects to see
a SYNACK.
The client will eventually time out after several minutes.
The following patch corrects this, by accepting ACKs on half open
connections as well.
Signed-off-by: Jozsef Kadlecsik <kadlec@blackhole.kfki.hu>
Signed-off-by: Patrick McHardy <kaber@trash.net>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/ipv4/netfilter/ip_conntrack_proto_tcp.c | 29 | ||||
-rw-r--r-- | net/netfilter/nf_conntrack_proto_tcp.c | 29 |
2 files changed, 40 insertions, 18 deletions
diff --git a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c index 625981676776..aeb7353d4777 100644 --- a/net/ipv4/netfilter/ip_conntrack_proto_tcp.c +++ b/net/ipv4/netfilter/ip_conntrack_proto_tcp.c | |||
@@ -272,9 +272,9 @@ static const enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | |||
272 | * sCL -> sCL | 272 | * sCL -> sCL |
273 | */ | 273 | */ |
274 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | 274 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ |
275 | /*ack*/ { sIV, sIV, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, | 275 | /*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, |
276 | /* | 276 | /* |
277 | * sSS -> sIV Might be a half-open connection. | 277 | * sSS -> sIG Might be a half-open connection. |
278 | * sSR -> sSR Might answer late resent SYN. | 278 | * sSR -> sSR Might answer late resent SYN. |
279 | * sES -> sES :-) | 279 | * sES -> sES :-) |
280 | * sFW -> sCW Normal close request answered by ACK. | 280 | * sFW -> sCW Normal close request answered by ACK. |
@@ -917,8 +917,12 @@ static int tcp_packet(struct ip_conntrack *conntrack, | |||
917 | 917 | ||
918 | switch (new_state) { | 918 | switch (new_state) { |
919 | case TCP_CONNTRACK_IGNORE: | 919 | case TCP_CONNTRACK_IGNORE: |
920 | /* Either SYN in ORIGINAL | 920 | /* Ignored packets: |
921 | * or SYN/ACK in REPLY. */ | 921 | * |
922 | * a) SYN in ORIGINAL | ||
923 | * b) SYN/ACK in REPLY | ||
924 | * c) ACK in reply direction after initial SYN in original. | ||
925 | */ | ||
922 | if (index == TCP_SYNACK_SET | 926 | if (index == TCP_SYNACK_SET |
923 | && conntrack->proto.tcp.last_index == TCP_SYN_SET | 927 | && conntrack->proto.tcp.last_index == TCP_SYN_SET |
924 | && conntrack->proto.tcp.last_dir != dir | 928 | && conntrack->proto.tcp.last_dir != dir |
@@ -985,13 +989,20 @@ static int tcp_packet(struct ip_conntrack *conntrack, | |||
985 | } | 989 | } |
986 | case TCP_CONNTRACK_CLOSE: | 990 | case TCP_CONNTRACK_CLOSE: |
987 | if (index == TCP_RST_SET | 991 | if (index == TCP_RST_SET |
988 | && test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) | 992 | && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) |
989 | && conntrack->proto.tcp.last_index == TCP_SYN_SET | 993 | && conntrack->proto.tcp.last_index == TCP_SYN_SET) |
994 | || (!test_bit(IPS_ASSURED_BIT, &conntrack->status) | ||
995 | && conntrack->proto.tcp.last_index == TCP_ACK_SET)) | ||
990 | && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { | 996 | && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { |
991 | /* RST sent to invalid SYN we had let trough | 997 | /* RST sent to invalid SYN or ACK we had let trough |
992 | * SYN was in window then, tear down connection. | 998 | * at a) and c) above: |
999 | * | ||
1000 | * a) SYN was in window then | ||
1001 | * c) we hold a half-open connection. | ||
1002 | * | ||
1003 | * Delete our connection entry. | ||
993 | * We skip window checking, because packet might ACK | 1004 | * We skip window checking, because packet might ACK |
994 | * segments we ignored in the SYN. */ | 1005 | * segments we ignored. */ |
995 | goto in_window; | 1006 | goto in_window; |
996 | } | 1007 | } |
997 | /* Just fall trough */ | 1008 | /* Just fall trough */ |
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c index 5a6fcf349bdf..6035633d8225 100644 --- a/net/netfilter/nf_conntrack_proto_tcp.c +++ b/net/netfilter/nf_conntrack_proto_tcp.c | |||
@@ -280,9 +280,9 @@ static enum tcp_conntrack tcp_conntracks[2][6][TCP_CONNTRACK_MAX] = { | |||
280 | * sCL -> sCL | 280 | * sCL -> sCL |
281 | */ | 281 | */ |
282 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ | 282 | /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ |
283 | /*ack*/ { sIV, sIV, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, | 283 | /*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, |
284 | /* | 284 | /* |
285 | * sSS -> sIV Might be a half-open connection. | 285 | * sSS -> sIG Might be a half-open connection. |
286 | * sSR -> sSR Might answer late resent SYN. | 286 | * sSR -> sSR Might answer late resent SYN. |
287 | * sES -> sES :-) | 287 | * sES -> sES :-) |
288 | * sFW -> sCW Normal close request answered by ACK. | 288 | * sFW -> sCW Normal close request answered by ACK. |
@@ -912,8 +912,12 @@ static int tcp_packet(struct nf_conn *conntrack, | |||
912 | 912 | ||
913 | switch (new_state) { | 913 | switch (new_state) { |
914 | case TCP_CONNTRACK_IGNORE: | 914 | case TCP_CONNTRACK_IGNORE: |
915 | /* Either SYN in ORIGINAL | 915 | /* Ignored packets: |
916 | * or SYN/ACK in REPLY. */ | 916 | * |
917 | * a) SYN in ORIGINAL | ||
918 | * b) SYN/ACK in REPLY | ||
919 | * c) ACK in reply direction after initial SYN in original. | ||
920 | */ | ||
917 | if (index == TCP_SYNACK_SET | 921 | if (index == TCP_SYNACK_SET |
918 | && conntrack->proto.tcp.last_index == TCP_SYN_SET | 922 | && conntrack->proto.tcp.last_index == TCP_SYN_SET |
919 | && conntrack->proto.tcp.last_dir != dir | 923 | && conntrack->proto.tcp.last_dir != dir |
@@ -979,13 +983,20 @@ static int tcp_packet(struct nf_conn *conntrack, | |||
979 | } | 983 | } |
980 | case TCP_CONNTRACK_CLOSE: | 984 | case TCP_CONNTRACK_CLOSE: |
981 | if (index == TCP_RST_SET | 985 | if (index == TCP_RST_SET |
982 | && test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) | 986 | && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) |
983 | && conntrack->proto.tcp.last_index == TCP_SYN_SET | 987 | && conntrack->proto.tcp.last_index == TCP_SYN_SET) |
988 | || (!test_bit(IPS_ASSURED_BIT, &conntrack->status) | ||
989 | && conntrack->proto.tcp.last_index == TCP_ACK_SET)) | ||
984 | && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { | 990 | && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { |
985 | /* RST sent to invalid SYN we had let trough | 991 | /* RST sent to invalid SYN or ACK we had let trough |
986 | * SYN was in window then, tear down connection. | 992 | * at a) and c) above: |
993 | * | ||
994 | * a) SYN was in window then | ||
995 | * c) we hold a half-open connection. | ||
996 | * | ||
997 | * Delete our connection entry. | ||
987 | * We skip window checking, because packet might ACK | 998 | * We skip window checking, because packet might ACK |
988 | * segments we ignored in the SYN. */ | 999 | * segments we ignored. */ |
989 | goto in_window; | 1000 | goto in_window; |
990 | } | 1001 | } |
991 | /* Just fall trough */ | 1002 | /* Just fall trough */ |