aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <edumazet@google.com>2012-07-17 04:13:05 -0400
committerDavid S. Miller <davem@davemloft.net>2012-07-17 04:36:20 -0400
commit282f23c6ee343126156dd41218b22ece96d747e3 (patch)
tree9a306d99ed77d760078d29699edd3007507d709b
parenta858d64b7709ca7bd2ee71d66ef3b7190cdcbb7d (diff)
tcp: implement RFC 5961 3.2
Implement the RFC 5691 mitigation against Blind Reset attack using RST bit. Idea is to validate incoming RST sequence, to match RCV.NXT value, instead of previouly accepted window : (RCV.NXT <= SEG.SEQ < RCV.NXT+RCV.WND) If sequence is in window but not an exact match, send a "challenge ACK", so that the other part can resend an RST with the appropriate sequence. Add a new sysctl, tcp_challenge_ack_limit, to limit number of challenge ACK sent per second. Add a new SNMP counter to count number of challenge acks sent. (netstat -s | grep TCPChallengeACK) Signed-off-by: Eric Dumazet <edumazet@google.com> Cc: Kiran Kumar Kella <kkiran@broadcom.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--Documentation/networking/ip-sysctl.txt5
-rw-r--r--include/linux/snmp.h1
-rw-r--r--include/net/tcp.h1
-rw-r--r--net/ipv4/proc.c1
-rw-r--r--net/ipv4/sysctl_net_ipv4.c7
-rw-r--r--net/ipv4/tcp_input.c31
6 files changed, 45 insertions, 1 deletions
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index e20c17a7d34e..e1e021594cff 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -565,6 +565,11 @@ tcp_limit_output_bytes - INTEGER
565 reduce the size of individual GSO packet (64KB being the max) 565 reduce the size of individual GSO packet (64KB being the max)
566 Default: 131072 566 Default: 131072
567 567
568tcp_challenge_ack_limit - INTEGER
569 Limits number of Challenge ACK sent per second, as recommended
570 in RFC 5961 (Improving TCP's Robustness to Blind In-Window Attacks)
571 Default: 100
572
568UDP variables: 573UDP variables:
569 574
570udp_mem - vector of 3 INTEGERs: min, pressure, max 575udp_mem - vector of 3 INTEGERs: min, pressure, max
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 6e4c51123828..673e0e928b2b 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -237,6 +237,7 @@ enum
237 LINUX_MIB_TCPOFOQUEUE, /* TCPOFOQueue */ 237 LINUX_MIB_TCPOFOQUEUE, /* TCPOFOQueue */
238 LINUX_MIB_TCPOFODROP, /* TCPOFODrop */ 238 LINUX_MIB_TCPOFODROP, /* TCPOFODrop */
239 LINUX_MIB_TCPOFOMERGE, /* TCPOFOMerge */ 239 LINUX_MIB_TCPOFOMERGE, /* TCPOFOMerge */
240 LINUX_MIB_TCPCHALLENGEACK, /* TCPChallengeACK */
240 __LINUX_MIB_MAX 241 __LINUX_MIB_MAX
241}; 242};
242 243
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 439984b9af49..85c5090bfe25 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -254,6 +254,7 @@ extern int sysctl_tcp_thin_linear_timeouts;
254extern int sysctl_tcp_thin_dupack; 254extern int sysctl_tcp_thin_dupack;
255extern int sysctl_tcp_early_retrans; 255extern int sysctl_tcp_early_retrans;
256extern int sysctl_tcp_limit_output_bytes; 256extern int sysctl_tcp_limit_output_bytes;
257extern int sysctl_tcp_challenge_ack_limit;
257 258
258extern atomic_long_t tcp_memory_allocated; 259extern atomic_long_t tcp_memory_allocated;
259extern struct percpu_counter tcp_sockets_allocated; 260extern struct percpu_counter tcp_sockets_allocated;
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index dae25e7622cf..3e8e78f12a38 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -261,6 +261,7 @@ static const struct snmp_mib snmp4_net_list[] = {
261 SNMP_MIB_ITEM("TCPOFOQueue", LINUX_MIB_TCPOFOQUEUE), 261 SNMP_MIB_ITEM("TCPOFOQueue", LINUX_MIB_TCPOFOQUEUE),
262 SNMP_MIB_ITEM("TCPOFODrop", LINUX_MIB_TCPOFODROP), 262 SNMP_MIB_ITEM("TCPOFODrop", LINUX_MIB_TCPOFODROP),
263 SNMP_MIB_ITEM("TCPOFOMerge", LINUX_MIB_TCPOFOMERGE), 263 SNMP_MIB_ITEM("TCPOFOMerge", LINUX_MIB_TCPOFOMERGE),
264 SNMP_MIB_ITEM("TCPChallengeACK", LINUX_MIB_TCPCHALLENGEACK),
264 SNMP_MIB_SENTINEL 265 SNMP_MIB_SENTINEL
265}; 266};
266 267
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index 70730f7aeafe..3f6a1e762e9c 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -605,6 +605,13 @@ static struct ctl_table ipv4_table[] = {
605 .mode = 0644, 605 .mode = 0644,
606 .proc_handler = proc_dointvec 606 .proc_handler = proc_dointvec
607 }, 607 },
608 {
609 .procname = "tcp_challenge_ack_limit",
610 .data = &sysctl_tcp_challenge_ack_limit,
611 .maxlen = sizeof(int),
612 .mode = 0644,
613 .proc_handler = proc_dointvec
614 },
608#ifdef CONFIG_NET_DMA 615#ifdef CONFIG_NET_DMA
609 { 616 {
610 .procname = "tcp_dma_copybreak", 617 .procname = "tcp_dma_copybreak",
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index cc4e12f1f2f7..c841a8990377 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -88,6 +88,9 @@ int sysctl_tcp_app_win __read_mostly = 31;
88int sysctl_tcp_adv_win_scale __read_mostly = 1; 88int sysctl_tcp_adv_win_scale __read_mostly = 1;
89EXPORT_SYMBOL(sysctl_tcp_adv_win_scale); 89EXPORT_SYMBOL(sysctl_tcp_adv_win_scale);
90 90
91/* rfc5961 challenge ack rate limiting */
92int sysctl_tcp_challenge_ack_limit = 100;
93
91int sysctl_tcp_stdurg __read_mostly; 94int sysctl_tcp_stdurg __read_mostly;
92int sysctl_tcp_rfc1337 __read_mostly; 95int sysctl_tcp_rfc1337 __read_mostly;
93int sysctl_tcp_max_orphans __read_mostly = NR_FILE; 96int sysctl_tcp_max_orphans __read_mostly = NR_FILE;
@@ -5247,6 +5250,23 @@ out:
5247} 5250}
5248#endif /* CONFIG_NET_DMA */ 5251#endif /* CONFIG_NET_DMA */
5249 5252
5253static void tcp_send_challenge_ack(struct sock *sk)
5254{
5255 /* unprotected vars, we dont care of overwrites */
5256 static u32 challenge_timestamp;
5257 static unsigned int challenge_count;
5258 u32 now = jiffies / HZ;
5259
5260 if (now != challenge_timestamp) {
5261 challenge_timestamp = now;
5262 challenge_count = 0;
5263 }
5264 if (++challenge_count <= sysctl_tcp_challenge_ack_limit) {
5265 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPCHALLENGEACK);
5266 tcp_send_ack(sk);
5267 }
5268}
5269
5250/* 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
5251 * play significant role here. 5271 * play significant role here.
5252 */ 5272 */
@@ -5283,7 +5303,16 @@ static int tcp_validate_incoming(struct sock *sk, struct sk_buff *skb,
5283 5303
5284 /* Step 2: check RST bit */ 5304 /* Step 2: check RST bit */
5285 if (th->rst) { 5305 if (th->rst) {
5286 tcp_reset(sk); 5306 /* RFC 5961 3.2 :
5307 * If sequence number exactly matches RCV.NXT, then
5308 * RESET the connection
5309 * else
5310 * Send a challenge ACK
5311 */
5312 if (TCP_SKB_CB(skb)->seq == tp->rcv_nxt)
5313 tcp_reset(sk);
5314 else
5315 tcp_send_challenge_ack(sk);
5287 goto discard; 5316 goto discard;
5288 } 5317 }
5289 5318