diff options
author | Eric Dumazet <edumazet@google.com> | 2012-07-16 21:41:30 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2012-07-17 10:40:46 -0400 |
commit | 0c24604b68fc7810d429d6c3657b6f148270e528 (patch) | |
tree | f5dd9deb10cfbcf8742483ecda7d07899ccb57f9 /net | |
parent | 5f3600ebe252aa5fe782e9f9115c66c639f62ac0 (diff) |
tcp: implement RFC 5961 4.2
Implement the RFC 5691 mitigation against Blind
Reset attack using SYN bit.
Section 4.2 of RFC 5961 advises to send a Challenge ACK and drop
incoming packet, instead of resetting the session.
Add a new SNMP counter to count number of challenge acks sent
in response to SYN packets.
(netstat -s | grep TCPSYNChallenge)
Remove obsolete TCPAbortOnSyn, since we no longer abort a TCP session
because of a SYN flag.
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Kiran Kumar Kella <kkiran@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r-- | net/ipv4/proc.c | 2 | ||||
-rw-r--r-- | net/ipv4/tcp_input.c | 32 |
2 files changed, 16 insertions, 18 deletions
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c index 3e8e78f12a38..2a5240b2ea61 100644 --- a/net/ipv4/proc.c +++ b/net/ipv4/proc.c | |||
@@ -232,7 +232,6 @@ static const struct snmp_mib snmp4_net_list[] = { | |||
232 | SNMP_MIB_ITEM("TCPDSACKOfoSent", LINUX_MIB_TCPDSACKOFOSENT), | 232 | SNMP_MIB_ITEM("TCPDSACKOfoSent", LINUX_MIB_TCPDSACKOFOSENT), |
233 | SNMP_MIB_ITEM("TCPDSACKRecv", LINUX_MIB_TCPDSACKRECV), | 233 | SNMP_MIB_ITEM("TCPDSACKRecv", LINUX_MIB_TCPDSACKRECV), |
234 | SNMP_MIB_ITEM("TCPDSACKOfoRecv", LINUX_MIB_TCPDSACKOFORECV), | 234 | SNMP_MIB_ITEM("TCPDSACKOfoRecv", LINUX_MIB_TCPDSACKOFORECV), |
235 | SNMP_MIB_ITEM("TCPAbortOnSyn", LINUX_MIB_TCPABORTONSYN), | ||
236 | SNMP_MIB_ITEM("TCPAbortOnData", LINUX_MIB_TCPABORTONDATA), | 235 | SNMP_MIB_ITEM("TCPAbortOnData", LINUX_MIB_TCPABORTONDATA), |
237 | SNMP_MIB_ITEM("TCPAbortOnClose", LINUX_MIB_TCPABORTONCLOSE), | 236 | SNMP_MIB_ITEM("TCPAbortOnClose", LINUX_MIB_TCPABORTONCLOSE), |
238 | SNMP_MIB_ITEM("TCPAbortOnMemory", LINUX_MIB_TCPABORTONMEMORY), | 237 | SNMP_MIB_ITEM("TCPAbortOnMemory", LINUX_MIB_TCPABORTONMEMORY), |
@@ -262,6 +261,7 @@ static const struct snmp_mib snmp4_net_list[] = { | |||
262 | SNMP_MIB_ITEM("TCPOFODrop", LINUX_MIB_TCPOFODROP), | 261 | SNMP_MIB_ITEM("TCPOFODrop", LINUX_MIB_TCPOFODROP), |
263 | SNMP_MIB_ITEM("TCPOFOMerge", LINUX_MIB_TCPOFOMERGE), | 262 | SNMP_MIB_ITEM("TCPOFOMerge", LINUX_MIB_TCPOFOMERGE), |
264 | SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK), | 263 | SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK), |
264 | SNMP_MIB_ITEM("TCPSYNChallenge", LINUX_MIB_TCPSYNCHALLENGE), | ||
265 | SNMP_MIB_SENTINEL | 265 | SNMP_MIB_SENTINEL |
266 | }; | 266 | }; |
267 | 267 | ||
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index c841a8990377..8aaec5536111 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c | |||
@@ -5270,8 +5270,8 @@ static void tcp_send_challenge_ack(struct sock *sk) | |||
5270 | /* Does PAWS and seqno based validation of an incoming segment, flags will | 5270 | /* Does PAWS and seqno based validation of an incoming segment, flags will |
5271 | * play significant role here. | 5271 | * play significant role here. |
5272 | */ | 5272 | */ |
5273 | static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, | 5273 | static bool tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, |
5274 | const struct tcphdr *th, int syn_inerr) | 5274 | const struct tcphdr *th, int syn_inerr) |
5275 | { | 5275 | { |
5276 | const u8 *hash_location; | 5276 | const u8 *hash_location; |
5277 | struct tcp_sock *tp = tcp_sk(sk); | 5277 | struct tcp_sock *tp = tcp_sk(sk); |
@@ -5323,20 +5323,22 @@ static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb, | |||
5323 | 5323 | ||
5324 | /* step 3: check security and precedence [ignored] */ | 5324 | /* step 3: check security and precedence [ignored] */ |
5325 | 5325 | ||
5326 | /* step 4: Check for a SYN in window. */ | 5326 | /* step 4: Check for a SYN |
5327 | if (th->syn && !before(TCP_SKB_CB(skb)->seq, tp->rcv_nxt)) { | 5327 | * RFC 5691 4.2 : Send a challenge ack |
5328 | */ | ||
5329 | if (th->syn) { | ||
5328 | if (syn_inerr) | 5330 | if (syn_inerr) |
5329 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); | 5331 | TCP_INC_STATS_BH(sock_net(sk), TCP_MIB_INERRS); |
5330 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPABORTONSYN); | 5332 | NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPSYNCHALLENGE); |
5331 | tcp_reset(sk); | 5333 | tcp_send_challenge_ack(sk); |
5332 | return -1; | 5334 | goto discard; |
5333 | } | 5335 | } |
5334 | 5336 | ||
5335 | return 1; | 5337 | return true; |
5336 | 5338 | ||
5337 | discard: | 5339 | discard: |
5338 | __kfree_skb(skb); | 5340 | __kfree_skb(skb); |
5339 | return 0; | 5341 | return false; |
5340 | } | 5342 | } |
5341 | 5343 | ||
5342 | /* | 5344 | /* |
@@ -5366,7 +5368,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, | |||
5366 | const struct tcphdr *th, unsigned int len) | 5368 | const struct tcphdr *th, unsigned int len) |
5367 | { | 5369 | { |
5368 | struct tcp_sock *tp = tcp_sk(sk); | 5370 | struct tcp_sock *tp = tcp_sk(sk); |
5369 | int res; | ||
5370 | 5371 | ||
5371 | if (sk->sk_rx_dst) { | 5372 | if (sk->sk_rx_dst) { |
5372 | struct dst_entry *dst = sk->sk_rx_dst; | 5373 | struct dst_entry *dst = sk->sk_rx_dst; |
@@ -5555,9 +5556,8 @@ slow_path: | |||
5555 | * Standard slow path. | 5556 | * Standard slow path. |
5556 | */ | 5557 | */ |
5557 | 5558 | ||
5558 | res = tcp_validate_incoming(sk, skb, th, 1); | 5559 | if (!tcp_validate_incoming(sk, skb, th, 1)) |
5559 | if (res <= 0) | 5560 | return 0; |
5560 | return -res; | ||
5561 | 5561 | ||
5562 | step5: | 5562 | step5: |
5563 | if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) | 5563 | if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0) |
@@ -5877,7 +5877,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
5877 | struct tcp_sock *tp = tcp_sk(sk); | 5877 | struct tcp_sock *tp = tcp_sk(sk); |
5878 | struct inet_connection_sock *icsk = inet_csk(sk); | 5878 | struct inet_connection_sock *icsk = inet_csk(sk); |
5879 | int queued = 0; | 5879 | int queued = 0; |
5880 | int res; | ||
5881 | 5880 | ||
5882 | tp->rx_opt.saw_tstamp = 0; | 5881 | tp->rx_opt.saw_tstamp = 0; |
5883 | 5882 | ||
@@ -5932,9 +5931,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb, | |||
5932 | return 0; | 5931 | return 0; |
5933 | } | 5932 | } |
5934 | 5933 | ||
5935 | res = tcp_validate_incoming(sk, skb, th, 0); | 5934 | if (!tcp_validate_incoming(sk, skb, th, 0)) |
5936 | if (res <= 0) | 5935 | return 0; |
5937 | return -res; | ||
5938 | 5936 | ||
5939 | /* step 5: check the ACK field */ | 5937 | /* step 5: check the ACK field */ |
5940 | if (th->ack) { | 5938 | if (th->ack) { |