Commit b2155e7f70b3f058efe94c0c459db023b05057bd

Authored by Jozsef Kadlecsik
Committed by David S. Miller
1 parent df922075f2

[NETFILTER]: nf_conntrack: TCP conntrack reopening fix

TCP connection tracking in netfilter did not handle TCP reopening
properly: active close was taken into account for one side only and
not for any side, which is fixed now. The patch includes more comments
to explain the logic how the different cases are handled.
The bug was discovered by Jeff Chua.

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>

Showing 1 changed file with 26 additions and 6 deletions Side-by-side Diff

net/netfilter/nf_conntrack_proto_tcp.c
... ... @@ -125,7 +125,7 @@
125 125 * CLOSE_WAIT: ACK seen (after FIN)
126 126 * LAST_ACK: FIN seen (after FIN)
127 127 * TIME_WAIT: last ACK seen
128   - * CLOSE: closed connection
  128 + * CLOSE: closed connection (RST)
129 129 *
130 130 * LISTEN state is not used.
131 131 *
... ... @@ -824,7 +824,21 @@
824 824 case TCP_CONNTRACK_SYN_SENT:
825 825 if (old_state < TCP_CONNTRACK_TIME_WAIT)
826 826 break;
827   - if ((ct->proto.tcp.seen[!dir].flags & IP_CT_TCP_FLAG_CLOSE_INIT)
  827 + /* RFC 1122: "When a connection is closed actively,
  828 + * it MUST linger in TIME-WAIT state for a time 2xMSL
  829 + * (Maximum Segment Lifetime). However, it MAY accept
  830 + * a new SYN from the remote TCP to reopen the connection
  831 + * directly from TIME-WAIT state, if..."
  832 + * We ignore the conditions because we are in the
  833 + * TIME-WAIT state anyway.
  834 + *
  835 + * Handle aborted connections: we and the server
  836 + * think there is an existing connection but the client
  837 + * aborts it and starts a new one.
  838 + */
  839 + if (((ct->proto.tcp.seen[dir].flags
  840 + | ct->proto.tcp.seen[!dir].flags)
  841 + & IP_CT_TCP_FLAG_CLOSE_INIT)
828 842 || (ct->proto.tcp.last_dir == dir
829 843 && ct->proto.tcp.last_index == TCP_RST_SET)) {
830 844 /* Attempt to reopen a closed/aborted connection.
831 845  
832 846  
... ... @@ -838,15 +852,22 @@
838 852 case TCP_CONNTRACK_IGNORE:
839 853 /* Ignored packets:
840 854 *
  855 + * Our connection entry may be out of sync, so ignore
  856 + * packets which may signal the real connection between
  857 + * the client and the server.
  858 + *
841 859 * a) SYN in ORIGINAL
842 860 * b) SYN/ACK in REPLY
843 861 * c) ACK in reply direction after initial SYN in original.
  862 + *
  863 + * If the ignored packet is invalid, the receiver will send
  864 + * a RST we'll catch below.
844 865 */
845 866 if (index == TCP_SYNACK_SET
846 867 && ct->proto.tcp.last_index == TCP_SYN_SET
847 868 && ct->proto.tcp.last_dir != dir
848 869 && ntohl(th->ack_seq) == ct->proto.tcp.last_end) {
849   - /* This SYN/ACK acknowledges a SYN that we earlier
  870 + /* b) This SYN/ACK acknowledges a SYN that we earlier
850 871 * ignored as invalid. This means that the client and
851 872 * the server are both in sync, while the firewall is
852 873 * not. We kill this session and block the SYN/ACK so
... ... @@ -870,7 +891,7 @@
870 891 write_unlock_bh(&tcp_lock);
871 892 if (LOG_INVALID(IPPROTO_TCP))
872 893 nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
873   - "nf_ct_tcp: invalid packed ignored ");
  894 + "nf_ct_tcp: invalid packet ignored ");
874 895 return NF_ACCEPT;
875 896 case TCP_CONNTRACK_MAX:
876 897 /* Invalid packet */
... ... @@ -924,8 +945,7 @@
924 945  
925 946 ct->proto.tcp.state = new_state;
926 947 if (old_state != new_state
927   - && (new_state == TCP_CONNTRACK_FIN_WAIT
928   - || new_state == TCP_CONNTRACK_CLOSE))
  948 + && new_state == TCP_CONNTRACK_CLOSE)
929 949 ct->proto.tcp.seen[dir].flags |= IP_CT_TCP_FLAG_CLOSE_INIT;
930 950 timeout = ct->proto.tcp.retrans >= nf_ct_tcp_max_retrans
931 951 && tcp_timeouts[new_state] > nf_ct_tcp_timeout_max_retrans