[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>

authored by Jozsef Kadlecsik and committed by David S. Miller 73f30602 5666c094

+40 -18
+20 -9
net/ipv4/netfilter/ip_conntrack_proto_tcp.c
··· 272 * sCL -> sCL 273 */ 274 /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ 275 - /*ack*/ { sIV, sIV, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, 276 /* 277 - * sSS -> sIV Might be a half-open connection. 278 * sSR -> sSR Might answer late resent SYN. 279 * sES -> sES :-) 280 * sFW -> sCW Normal close request answered by ACK. ··· 917 918 switch (new_state) { 919 case TCP_CONNTRACK_IGNORE: 920 - /* Either SYN in ORIGINAL 921 - * or SYN/ACK in REPLY. */ 922 if (index == TCP_SYNACK_SET 923 && conntrack->proto.tcp.last_index == TCP_SYN_SET 924 && conntrack->proto.tcp.last_dir != dir ··· 989 } 990 case TCP_CONNTRACK_CLOSE: 991 if (index == TCP_RST_SET 992 - && test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) 993 - && conntrack->proto.tcp.last_index == TCP_SYN_SET 994 && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { 995 - /* RST sent to invalid SYN we had let trough 996 - * SYN was in window then, tear down connection. 997 * We skip window checking, because packet might ACK 998 - * segments we ignored in the SYN. */ 999 goto in_window; 1000 } 1001 /* Just fall trough */
··· 272 * sCL -> sCL 273 */ 274 /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ 275 + /*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, 276 /* 277 + * sSS -> sIG Might be a half-open connection. 278 * sSR -> sSR Might answer late resent SYN. 279 * sES -> sES :-) 280 * sFW -> sCW Normal close request answered by ACK. ··· 917 918 switch (new_state) { 919 case TCP_CONNTRACK_IGNORE: 920 + /* Ignored packets: 921 + * 922 + * a) SYN in ORIGINAL 923 + * b) SYN/ACK in REPLY 924 + * c) ACK in reply direction after initial SYN in original. 925 + */ 926 if (index == TCP_SYNACK_SET 927 && conntrack->proto.tcp.last_index == TCP_SYN_SET 928 && conntrack->proto.tcp.last_dir != dir ··· 985 } 986 case TCP_CONNTRACK_CLOSE: 987 if (index == TCP_RST_SET 988 + && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) 989 + && conntrack->proto.tcp.last_index == TCP_SYN_SET) 990 + || (!test_bit(IPS_ASSURED_BIT, &conntrack->status) 991 + && conntrack->proto.tcp.last_index == TCP_ACK_SET)) 992 && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { 993 + /* RST sent to invalid SYN or ACK we had let trough 994 + * at a) and c) above: 995 + * 996 + * a) SYN was in window then 997 + * c) we hold a half-open connection. 998 + * 999 + * Delete our connection entry. 1000 * We skip window checking, because packet might ACK 1001 + * segments we ignored. */ 1002 goto in_window; 1003 } 1004 /* Just fall trough */
+20 -9
net/netfilter/nf_conntrack_proto_tcp.c
··· 280 * sCL -> sCL 281 */ 282 /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ 283 - /*ack*/ { sIV, sIV, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, 284 /* 285 - * sSS -> sIV Might be a half-open connection. 286 * sSR -> sSR Might answer late resent SYN. 287 * sES -> sES :-) 288 * sFW -> sCW Normal close request answered by ACK. ··· 912 913 switch (new_state) { 914 case TCP_CONNTRACK_IGNORE: 915 - /* Either SYN in ORIGINAL 916 - * or SYN/ACK in REPLY. */ 917 if (index == TCP_SYNACK_SET 918 && conntrack->proto.tcp.last_index == TCP_SYN_SET 919 && conntrack->proto.tcp.last_dir != dir ··· 983 } 984 case TCP_CONNTRACK_CLOSE: 985 if (index == TCP_RST_SET 986 - && test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) 987 - && conntrack->proto.tcp.last_index == TCP_SYN_SET 988 && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { 989 - /* RST sent to invalid SYN we had let trough 990 - * SYN was in window then, tear down connection. 991 * We skip window checking, because packet might ACK 992 - * segments we ignored in the SYN. */ 993 goto in_window; 994 } 995 /* Just fall trough */
··· 280 * sCL -> sCL 281 */ 282 /* sNO, sSS, sSR, sES, sFW, sCW, sLA, sTW, sCL, sLI */ 283 + /*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIV }, 284 /* 285 + * sSS -> sIG Might be a half-open connection. 286 * sSR -> sSR Might answer late resent SYN. 287 * sES -> sES :-) 288 * sFW -> sCW Normal close request answered by ACK. ··· 912 913 switch (new_state) { 914 case TCP_CONNTRACK_IGNORE: 915 + /* Ignored packets: 916 + * 917 + * a) SYN in ORIGINAL 918 + * b) SYN/ACK in REPLY 919 + * c) ACK in reply direction after initial SYN in original. 920 + */ 921 if (index == TCP_SYNACK_SET 922 && conntrack->proto.tcp.last_index == TCP_SYN_SET 923 && conntrack->proto.tcp.last_dir != dir ··· 979 } 980 case TCP_CONNTRACK_CLOSE: 981 if (index == TCP_RST_SET 982 + && ((test_bit(IPS_SEEN_REPLY_BIT, &conntrack->status) 983 + && conntrack->proto.tcp.last_index == TCP_SYN_SET) 984 + || (!test_bit(IPS_ASSURED_BIT, &conntrack->status) 985 + && conntrack->proto.tcp.last_index == TCP_ACK_SET)) 986 && ntohl(th->ack_seq) == conntrack->proto.tcp.last_end) { 987 + /* RST sent to invalid SYN or ACK we had let trough 988 + * at a) and c) above: 989 + * 990 + * a) SYN was in window then 991 + * c) we hold a half-open connection. 992 + * 993 + * Delete our connection entry. 994 * We skip window checking, because packet might ACK 995 + * segments we ignored. */ 996 goto in_window; 997 } 998 /* Just fall trough */