History

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.

Eric Dumazet committed 15 years ago

Commit 946cedc1 parent 27e95a86 files · +40 −50Browse files

Unified · Split

6 files
  1. include/linux/snmp.h +2 −0
  2. include/net/request_sock.h +2 −1
  3. include/net/tcp.h +3 −0
  4. net/ipv4/proc.c +2 −0
  5. net/ipv4/tcp_ipv4.c +28 −21
  6. net/ipv6/tcp_ipv6.c +3 −28
include/linux/snmp.h+2−0
@@ -231,6 +231,8 @@ enum · 230 unmodified lines
231231 LINUX_MIB_TCPDEFERACCEPTDROP,
232232 LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
233233 LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */
234+ LINUX_MIB_TCPREQQFULLDOCOOKIES, /* TCPReqQFullDoCookies */
235+ LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */
234236 __LINUX_MIB_MAX
235237 };
236238
include/net/request_sock.h+2−1
@@ -96,7 +96,8 @@ extern int sysctl_max_syn_backlog; · 95 unmodified lines
9696 */
9797 struct listen_sock {
9898 u8 max_qlen_log;
99− /* 3 bytes hole, try to use */
99+ u8 synflood_warned;
100+ /* 2 bytes hole, try to use */
100101 int qlen;
101102 int qlen_young;
102103 int clock_hand;
include/net/tcp.h+3−0
@@ -460,6 +460,9 @@ extern int tcp_write_wakeup(struct sock *); · 459 unmodified lines
460460 extern void tcp_send_fin(struct sock *sk);
461461 extern void tcp_send_active_reset(struct sock *sk, gfp_t priority);
462462 extern int tcp_send_synack(struct sock *);
463+extern int tcp_syn_flood_action(struct sock *sk,
464+ const struct sk_buff *skb,
465+ const char *proto);
463466 extern void tcp_push_one(struct sock *, unsigned int mss_now);
464467 extern void tcp_send_ack(struct sock *sk);
465468 extern void tcp_send_delayed_ack(struct sock *sk);
net/ipv4/proc.c+2−0
@@ -254,6 +254,8 @@ static const struct snmp_mib snmp4_net_list[] = { · 253 unmodified lines
254254 SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
255255 SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
256256 SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW),
257+ SNMP_MIB_ITEM("TCPReqQFullDoCookies", LINUX_MIB_TCPREQQFULLDOCOOKIES),
258+ SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP),
257259 SNMP_MIB_SENTINEL
258260 };
259261
net/ipv4/tcp_ipv4.c+28−21
@@ -808,20 +808,38 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req) · 807 unmodified lines
808808 kfree(inet_rsk(req)->opt);
809809 }
810810
811−static void syn_flood_warning(const struct sk_buff *skb)
811+/*
812+ * Return 1 if a syncookie should be sent
813+ */
814+int tcp_syn_flood_action(struct sock *sk,
815+ const struct sk_buff *skb,
816+ const char *proto)
812817 {
813− const char *msg;
818+ const char *msg = "Dropping request";
819+ int want_cookie = 0;
820+ struct listen_sock *lopt;
821+
822+
814823
815824 #ifdef CONFIG_SYN_COOKIES
816− if (sysctl_tcp_syncookies)
825+ if (sysctl_tcp_syncookies) {
817826 msg = "Sending cookies";
818− else
827+ want_cookie = 1;
828+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES);
829+ } else
819830 #endif
820− msg = "Dropping request";
831+ NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
821832
822− pr_info("TCP: Possible SYN flooding on port %d. %s.\n",
823− ntohs(tcp_hdr(skb)->dest), msg);
833+ lopt = inet_csk(sk)->icsk_accept_queue.listen_opt;
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;
824841 }
842+EXPORT_SYMBOL(tcp_syn_flood_action);
825843
826844 /*
827845 * 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) · 407 unmodified lines
12351253 __be32 saddr = ip_hdr(skb)->saddr;
12361254 __be32 daddr = ip_hdr(skb)->daddr;
12371255 __u32 isn = TCP_SKB_CB(skb)->when;
1238−#ifdef CONFIG_SYN_COOKIES
12391256 int want_cookie = 0;
1240−#else
1241−#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
1242−#endif
12431257
12441258 /* Never answer to SYNs send to broadcast or multicast */
12451259 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) · 4 unmodified lines
12501264 * evidently real one.
12511265 */
12521266 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
1253− if (net_ratelimit())
1254− syn_flood_warning(skb);
1255−#ifdef CONFIG_SYN_COOKIES
1256− if (sysctl_tcp_syncookies) {
1257− want_cookie = 1;
1258− } else
1259−#endif
1260− goto drop;
1267+ want_cookie = tcp_syn_flood_action(sk, skb, "TCP");
1268+ if (!want_cookie)
1269+ goto drop;
12611270 }
12621271
12631272 /* 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) · 39 unmodified lines
13031312 while (l-- > 0)
13041313 *c++ ^= *hash_location++;
13051314
1306−#ifdef CONFIG_SYN_COOKIES
13071315 want_cookie = 0; /* not our kind of cookie */
1308−#endif
13091316 tmp_ext.cookie_out_never = 0; /* false */
13101317 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
13111318 } else if (!tp->rx_opt.cookie_in_always) {
net/ipv6/tcp_ipv6.c+3−28
@@ -531,20 +531,6 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req, · 530 unmodified lines
531531 return tcp_v6_send_synack(sk, req, rvp);
532532 }
533533
534−static 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−
548534 static void tcp_v6_reqsk_destructor(struct request_sock *req)
549535 {
550536 kfree_skb(inet6_rsk(req)->pktopts);
@@ -1179,11 +1165,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) · 628 unmodified lines
11791165 struct tcp_sock *tp = tcp_sk(sk);
11801166 __u32 isn = TCP_SKB_CB(skb)->when;
11811167 struct dst_entry *dst = NULL;
1182−#ifdef CONFIG_SYN_COOKIES
11831168 int want_cookie = 0;
1184−#else
1185−#define want_cookie 0
1186−#endif
11871169
11881170 if (skb->protocol == htons(ETH_P_IP))
11891171 return tcp_v4_conn_request(sk, skb);
@@ -1192,14 +1174,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb) · 2 unmodified lines
11921174 goto drop;
11931175
11941176 if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
1195− if (net_ratelimit())
1196− syn_flood_warning(skb);
1197−#ifdef CONFIG_SYN_COOKIES
1198− if (sysctl_tcp_syncookies)
1199− want_cookie = 1;
1200− else
1201−#endif
1202− goto drop;
1177+ want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
1178+ if (!want_cookie)
1179+ goto drop;
12031180 }
12041181
12051182 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) · 43 unmodified lines
12491226 while (l-- > 0)
12501227 *c++ ^= *hash_location++;
12511228
1252−#ifdef CONFIG_SYN_COOKIES
12531229 want_cookie = 0; /* not our kind of cookie */
1254−#endif
12551230 tmp_ext.cookie_out_never = 0; /* false */
12561231 tmp_ext.cookie_plus = tmp_opt.cookie_plus;
12571232 } else if (!tp->rx_opt.cookie_in_always) {