diff options
| author | Eric Dumazet <eric.dumazet@gmail.com> | 2011-08-29 23:21:44 -0400 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2011-09-15 14:49:43 -0400 |
| commit | 946cedccbd7387488d2cee5da92cdfeb28d2e670 (patch) | |
| tree | fbb0d9c8dc11d6efee64e2a077a4951831932058 /net | |
| parent | 27e95a8c670e0c587990ec5b9a87a7ea17873d28 (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>
Diffstat (limited to 'net')
| -rw-r--r-- | net/ipv4/proc.c | 2 | ||||
| -rw-r--r-- | net/ipv4/tcp_ipv4.c | 49 | ||||
| -rw-r--r-- | net/ipv6/tcp_ipv6.c | 31 |
3 files changed, 33 insertions, 49 deletions
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 | ||
| 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) | ||
| 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 | } |
| 842 | EXPORT_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 | ||
| 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 | |||
| 548 | static void tcp_v6_reqsk_destructor(struct request_sock *req) | 534 | static 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) { |
