aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c51
1 files changed, 41 insertions, 10 deletions
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index 97a82ba75376..9cc6b5cb06af 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -908,23 +908,54 @@ static int tcp_packet(struct nf_conn *ct,
908 /* b) This SYN/ACK acknowledges a SYN that we earlier 908 /* b) This SYN/ACK acknowledges a SYN that we earlier
909 * ignored as invalid. This means that the client and 909 * ignored as invalid. This means that the client and
910 * the server are both in sync, while the firewall is 910 * the server are both in sync, while the firewall is
911 * not. We kill this session and block the SYN/ACK so 911 * not. We get in sync from the previously annotated
912 * that the client cannot but retransmit its SYN and 912 * values.
913 * thus initiate a clean new session.
914 */ 913 */
915 spin_unlock_bh(&ct->lock); 914 old_state = TCP_CONNTRACK_SYN_SENT;
916 if (LOG_INVALID(net, IPPROTO_TCP)) 915 new_state = TCP_CONNTRACK_SYN_RECV;
917 nf_log_packet(pf, 0, skb, NULL, NULL, NULL, 916 ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_end =
918 "nf_ct_tcp: killing out of sync session "); 917 ct->proto.tcp.last_end;
919 nf_ct_kill(ct); 918 ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxend =
920 return NF_DROP; 919 ct->proto.tcp.last_end;
920 ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_maxwin =
921 ct->proto.tcp.last_win == 0 ?
922 1 : ct->proto.tcp.last_win;
923 ct->proto.tcp.seen[ct->proto.tcp.last_dir].td_scale =
924 ct->proto.tcp.last_wscale;
925 ct->proto.tcp.seen[ct->proto.tcp.last_dir].flags =
926 ct->proto.tcp.last_flags;
927 memset(&ct->proto.tcp.seen[dir], 0,
928 sizeof(struct ip_ct_tcp_state));
929 break;
921 } 930 }
922 ct->proto.tcp.last_index = index; 931 ct->proto.tcp.last_index = index;
923 ct->proto.tcp.last_dir = dir; 932 ct->proto.tcp.last_dir = dir;
924 ct->proto.tcp.last_seq = ntohl(th->seq); 933 ct->proto.tcp.last_seq = ntohl(th->seq);
925 ct->proto.tcp.last_end = 934 ct->proto.tcp.last_end =
926 segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th); 935 segment_seq_plus_len(ntohl(th->seq), skb->len, dataoff, th);
927 936 ct->proto.tcp.last_win = ntohs(th->window);
937
938 /* a) This is a SYN in ORIGINAL. The client and the server
939 * may be in sync but we are not. In that case, we annotate
940 * the TCP options and let the packet go through. If it is a
941 * valid SYN packet, the server will reply with a SYN/ACK, and
942 * then we'll get in sync. Otherwise, the server ignores it. */
943 if (index == TCP_SYN_SET && dir == IP_CT_DIR_ORIGINAL) {
944 struct ip_ct_tcp_state seen = {};
945
946 ct->proto.tcp.last_flags =
947 ct->proto.tcp.last_wscale = 0;
948 tcp_options(skb, dataoff, th, &seen);
949 if (seen.flags & IP_CT_TCP_FLAG_WINDOW_SCALE) {
950 ct->proto.tcp.last_flags |=
951 IP_CT_TCP_FLAG_WINDOW_SCALE;
952 ct->proto.tcp.last_wscale = seen.td_scale;
953 }
954 if (seen.flags & IP_CT_TCP_FLAG_SACK_PERM) {
955 ct->proto.tcp.last_flags |=
956 IP_CT_TCP_FLAG_SACK_PERM;
957 }
958 }
928 spin_unlock_bh(&ct->lock); 959 spin_unlock_bh(&ct->lock);
929 if (LOG_INVALID(net, IPPROTO_TCP)) 960 if (LOG_INVALID(net, IPPROTO_TCP))
930 nf_log_packet(pf, 0, skb, NULL, NULL, NULL, 961 nf_log_packet(pf, 0, skb, NULL, NULL, NULL,