aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric Dumazet <eric.dumazet@gmail.com>2011-08-29 23:21:44 -0400
committerDavid S. Miller <davem@davemloft.net>2011-09-15 14:49:43 -0400
commit946cedccbd7387488d2cee5da92cdfeb28d2e670 (patch)
treefbb0d9c8dc11d6efee64e2a077a4951831932058
parent27e95a8c670e0c587990ec5b9a87a7ea17873d28 (diff)
tcp: Change possible SYN flooding messages
"Possible SYN flooding on port xxxx " messages can fill logs on servers. Change logic to log the message only once per listener, and add two new SNMP counters to track : TCPReqQFullDoCookies : number of times a SYNCOOKIE was replied to client TCPReqQFullDrop : number of times a SYN request was dropped because syncookies were not enabled. Based on a prior patch from Tom Herbert, and suggestions from David. Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> CC: Tom Herbert <therbert@google.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--include/linux/snmp.h2
-rw-r--r--include/net/request_sock.h3
-rw-r--r--include/net/tcp.h3
-rw-r--r--net/ipv4/proc.c2
-rw-r--r--net/ipv4/tcp_ipv4.c49
-rw-r--r--net/ipv6/tcp_ipv6.c31
6 files changed, 40 insertions, 50 deletions
diff --git a/include/linux/snmp.h b/include/linux/snmp.h
index 12b2b18e50c1..e16557a357e5 100644
--- a/include/linux/snmp.h
+++ b/include/linux/snmp.h
@@ -231,6 +231,8 @@ enum
231 LINUX_MIB_TCPDEFERACCEPTDROP, 231 LINUX_MIB_TCPDEFERACCEPTDROP,
232 LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */ 232 LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
233 LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */ 233 LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */
234 LINUX_MIB_TCPREQQFULLDOCOOKIES, /* TCPReqQFullDoCookies */
235 LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */
234 __LINUX_MIB_MAX 236 __LINUX_MIB_MAX
235}; 237};
236 238
diff --git a/include/net/request_sock.h b/include/net/request_sock.h
index 99e6e19b57c2..4c0766e201e3 100644
--- a/include/net/request_sock.h
+++ b/include/net/request_sock.h
@@ -96,7 +96,8 @@ extern int sysctl_max_syn_backlog;
96 */ 96 */
97struct listen_sock { 97struct listen_sock {
98 u8 max_qlen_log; 98 u8 max_qlen_log;
99 /* 3 bytes hole, try to use */ 99 u8 synflood_warned;
100 /* 2 bytes hole, try to use */
100 int qlen; 101 int qlen;
101 int qlen_young; 102 int qlen_young;
102 int clock_hand; 103 int clock_hand;
diff --git a/include/net/tcp.h b/include/net/tcp.h
index 149a415d1e0a..e9b48b094683 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -460,6 +460,9 @@ extern int tcp_write_wakeup(struct sock *);
460extern void tcp_send_fin(struct sock *sk); 460extern void tcp_send_fin(struct sock *sk);
461extern void tcp_send_active_reset(struct sock *sk, gfp_t priority); 461extern void tcp_send_active_reset(struct sock *sk, gfp_t priority);
462extern int tcp_send_synack(struct sock *); 462extern int tcp_send_synack(struct sock *);
463extern int tcp_syn_flood_action(struct sock *sk,
464 const struct sk_buff *skb,
465 const char *proto);
463extern void tcp_push_one(struct sock *, unsigned int mss_now); 466extern void tcp_push_one(struct sock *, unsigned int mss_now);
464extern void tcp_send_ack(struct sock *sk); 467extern void tcp_send_ack(struct sock *sk);
465extern void tcp_send_delayed_ack(struct sock *sk); 468extern void tcp_send_delayed_ack(struct sock *sk);
diff --git a/net/ipv4/proc.c b/net/ipv4/proc.c
index b14ec7d03b6e..4bfad5da94f4 100644
--- a/net/ipv4/proc.c
+++ b/net/ipv4/proc.c
@@ -254,6 +254,8 @@ static const struct snmp_mib snmp4_net_list[] = {
254 SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP), 254 SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
255 SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER), 255 SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
256 SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW), 256 SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW),
257 SNMP_MIB_ITEM("TCPReqQFullDoCookies", LINUX_MIB_TCPREQQFULLDOCOOKIES),
258 SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP),
257 SNMP_MIB_SENTINEL 259 SNMP_MIB_SENTINEL
258}; 260};
259 261
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 1c12b8ec849d..c34f01513945 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -808,20 +808,38 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req)
808 kfree(inet_rsk(req)->opt); 808 kfree(inet_rsk(req)->opt);
809} 809}
810 810
811static void syn_flood_warning(const struct sk_buff *skb) 811/*
812 * Return 1 if a syncookie should be sent
813 */
814int tcp_syn_flood_action(struct sock *sk,
815 const struct sk_buff *skb,
816 const char *proto)
812{ 817{
813 const char *msg; 818 const char *msg = "Dropping request";
819 int want_cookie = 0;
820 struct listen_sock *lopt;
821
822
814 823
815#ifdef CONFIG_SYN_COOKIES 824#ifdef CONFIG_SYN_COOKIES
816 if (sysctl_tcp_syncookies) 825 if (sysctl_tcp_syncookies) {
817 msg = "Sending cookies"; 826 msg = "Sending cookies";
818 else 827 want_cookie = 1;
828 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES);
829 } else
819#endif 830#endif
820 msg = "Dropping request"; 831 NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
821 832
822 pr_info("TCP: Possible SYN flooding on port %d. %s.\n", 833 lopt = inet_csk(sk)->icsk_accept_queue.listen_opt;
823 ntohs(tcp_hdr(skb)->dest), msg); 834 if (!lopt->synflood_warned) {
835 lopt->synflood_warned = 1;
836 pr_info("%s: Possible SYN flooding on port %d. %s. "
837 " Check SNMP counters.\n",
838 proto, ntohs(tcp_hdr(skb)->dest), msg);
839 }
840 return want_cookie;
824} 841}
842EXPORT_SYMBOL(tcp_syn_flood_action);
825 843
826/* 844/*
827 * Save and compile IPv4 options into the request_sock if needed. 845 * Save and compile IPv4 options into the request_sock if needed.
@@ -1235,11 +1253,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
1235 __be32 saddr = ip_hdr(skb)->saddr; 1253 __be32 saddr = ip_hdr(skb)->saddr;
1236 __be32 daddr = ip_hdr(skb)->daddr; 1254 __be32 daddr = ip_hdr(skb)->daddr;
1237 __u32 isn = TCP_SKB_CB(skb)->when; 1255 __u32 isn = TCP_SKB_CB(skb)->when;
1238#ifdef CONFIG_SYN_COOKIES
1239 int want_cookie = 0; 1256 int want_cookie = 0;
1240#else
1241#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
1242#endif
1243 1257
1244 /* Never answer to SYNs send to broadcast or multicast */ 1258 /* Never answer to SYNs send to broadcast or multicast */
1245 if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST)) 1259 if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
@@ -1250,14 +1264,9 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
1250 * evidently real one. 1264 * evidently real one.
1251 */ 1265 */
1252 if (inet_csk_reqsk_queue_is_full(sk) && !isn) { 1266 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
1253 if (net_ratelimit()) 1267 want_cookie = tcp_syn_flood_action(sk, skb, "TCP");
1254 syn_flood_warning(skb); 1268 if (!want_cookie)
1255#ifdef CONFIG_SYN_COOKIES 1269 goto drop;
1256 if (sysctl_tcp_syncookies) {
1257 want_cookie = 1;
1258 } else
1259#endif
1260 goto drop;
1261 } 1270 }
1262 1271
1263 /* Accept backlog is full. If we have already queued enough 1272 /* Accept backlog is full. If we have already queued enough
@@ -1303,9 +1312,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
1303 while (l-- > 0) 1312 while (l-- > 0)
1304 *c++ ^= *hash_location++; 1313 *c++ ^= *hash_location++;
1305 1314
1306#ifdef CONFIG_SYN_COOKIES
1307 want_cookie = 0; /* not our kind of cookie */ 1315 want_cookie = 0; /* not our kind of cookie */
1308#endif
1309 tmp_ext.cookie_out_never = 0; /* false */ 1316 tmp_ext.cookie_out_never = 0; /* false */
1310 tmp_ext.cookie_plus = tmp_opt.cookie_plus; 1317 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
1311 } else if (!tp->rx_opt.cookie_in_always) { 1318 } else if (!tp->rx_opt.cookie_in_always) {
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index d1fb63f4aeb7..3c9fa618b69d 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -531,20 +531,6 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
531 return tcp_v6_send_synack(sk, req, rvp); 531 return tcp_v6_send_synack(sk, req, rvp);
532} 532}
533 533
534static inline void syn_flood_warning(struct sk_buff *skb)
535{
536#ifdef CONFIG_SYN_COOKIES
537 if (sysctl_tcp_syncookies)
538 printk(KERN_INFO
539 "TCPv6: Possible SYN flooding on port %d. "
540 "Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
541 else
542#endif
543 printk(KERN_INFO
544 "TCPv6: Possible SYN flooding on port %d. "
545 "Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
546}
547
548static void tcp_v6_reqsk_destructor(struct request_sock *req) 534static void tcp_v6_reqsk_destructor(struct request_sock *req)
549{ 535{
550 kfree_skb(inet6_rsk(req)->pktopts); 536 kfree_skb(inet6_rsk(req)->pktopts);
@@ -1179,11 +1165,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1179 struct tcp_sock *tp = tcp_sk(sk); 1165 struct tcp_sock *tp = tcp_sk(sk);
1180 __u32 isn = TCP_SKB_CB(skb)->when; 1166 __u32 isn = TCP_SKB_CB(skb)->when;
1181 struct dst_entry *dst = NULL; 1167 struct dst_entry *dst = NULL;
1182#ifdef CONFIG_SYN_COOKIES
1183 int want_cookie = 0; 1168 int want_cookie = 0;
1184#else
1185#define want_cookie 0
1186#endif
1187 1169
1188 if (skb->protocol == htons(ETH_P_IP)) 1170 if (skb->protocol == htons(ETH_P_IP))
1189 return tcp_v4_conn_request(sk, skb); 1171 return tcp_v4_conn_request(sk, skb);
@@ -1192,14 +1174,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1192 goto drop; 1174 goto drop;
1193 1175
1194 if (inet_csk_reqsk_queue_is_full(sk) && !isn) { 1176 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
1195 if (net_ratelimit()) 1177 want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
1196 syn_flood_warning(skb); 1178 if (!want_cookie)
1197#ifdef CONFIG_SYN_COOKIES 1179 goto drop;
1198 if (sysctl_tcp_syncookies)
1199 want_cookie = 1;
1200 else
1201#endif
1202 goto drop;
1203 } 1180 }
1204 1181
1205 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1) 1182 if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
@@ -1249,9 +1226,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
1249 while (l-- > 0) 1226 while (l-- > 0)
1250 *c++ ^= *hash_location++; 1227 *c++ ^= *hash_location++;
1251 1228
1252#ifdef CONFIG_SYN_COOKIES
1253 want_cookie = 0; /* not our kind of cookie */ 1229 want_cookie = 0; /* not our kind of cookie */
1254#endif
1255 tmp_ext.cookie_out_never = 0; /* false */ 1230 tmp_ext.cookie_out_never = 0; /* false */
1256 tmp_ext.cookie_plus = tmp_opt.cookie_plus; 1231 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
1257 } else if (!tp->rx_opt.cookie_in_always) { 1232 } else if (!tp->rx_opt.cookie_in_always) {