mirror of
https://github.com/edk2-porting/linux-next.git
synced 2024-12-17 01:34:00 +08:00
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>
This commit is contained in:
parent
27e95a8c67
commit
946cedccbd
@ -231,6 +231,8 @@ enum
|
|||||||
LINUX_MIB_TCPDEFERACCEPTDROP,
|
LINUX_MIB_TCPDEFERACCEPTDROP,
|
||||||
LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
|
LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
|
||||||
LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */
|
LINUX_MIB_TCPTIMEWAITOVERFLOW, /* TCPTimeWaitOverflow */
|
||||||
|
LINUX_MIB_TCPREQQFULLDOCOOKIES, /* TCPReqQFullDoCookies */
|
||||||
|
LINUX_MIB_TCPREQQFULLDROP, /* TCPReqQFullDrop */
|
||||||
__LINUX_MIB_MAX
|
__LINUX_MIB_MAX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -96,7 +96,8 @@ extern int sysctl_max_syn_backlog;
|
|||||||
*/
|
*/
|
||||||
struct listen_sock {
|
struct listen_sock {
|
||||||
u8 max_qlen_log;
|
u8 max_qlen_log;
|
||||||
/* 3 bytes hole, try to use */
|
u8 synflood_warned;
|
||||||
|
/* 2 bytes hole, try to use */
|
||||||
int qlen;
|
int qlen;
|
||||||
int qlen_young;
|
int qlen_young;
|
||||||
int clock_hand;
|
int clock_hand;
|
||||||
|
@ -460,6 +460,9 @@ extern int tcp_write_wakeup(struct sock *);
|
|||||||
extern void tcp_send_fin(struct sock *sk);
|
extern void tcp_send_fin(struct sock *sk);
|
||||||
extern void tcp_send_active_reset(struct sock *sk, gfp_t priority);
|
extern void tcp_send_active_reset(struct sock *sk, gfp_t priority);
|
||||||
extern int tcp_send_synack(struct sock *);
|
extern int tcp_send_synack(struct sock *);
|
||||||
|
extern int tcp_syn_flood_action(struct sock *sk,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
const char *proto);
|
||||||
extern void tcp_push_one(struct sock *, unsigned int mss_now);
|
extern void tcp_push_one(struct sock *, unsigned int mss_now);
|
||||||
extern void tcp_send_ack(struct sock *sk);
|
extern void tcp_send_ack(struct sock *sk);
|
||||||
extern void tcp_send_delayed_ack(struct sock *sk);
|
extern void tcp_send_delayed_ack(struct sock *sk);
|
||||||
|
@ -254,6 +254,8 @@ static const struct snmp_mib snmp4_net_list[] = {
|
|||||||
SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
|
SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
|
||||||
SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
|
SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
|
||||||
SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW),
|
SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW),
|
||||||
|
SNMP_MIB_ITEM("TCPReqQFullDoCookies", LINUX_MIB_TCPREQQFULLDOCOOKIES),
|
||||||
|
SNMP_MIB_ITEM("TCPReqQFullDrop", LINUX_MIB_TCPREQQFULLDROP),
|
||||||
SNMP_MIB_SENTINEL
|
SNMP_MIB_SENTINEL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -808,20 +808,38 @@ static void tcp_v4_reqsk_destructor(struct request_sock *req)
|
|||||||
kfree(inet_rsk(req)->opt);
|
kfree(inet_rsk(req)->opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void syn_flood_warning(const struct sk_buff *skb)
|
/*
|
||||||
|
* Return 1 if a syncookie should be sent
|
||||||
|
*/
|
||||||
|
int tcp_syn_flood_action(struct sock *sk,
|
||||||
|
const struct sk_buff *skb,
|
||||||
|
const char *proto)
|
||||||
{
|
{
|
||||||
const char *msg;
|
const char *msg = "Dropping request";
|
||||||
|
int want_cookie = 0;
|
||||||
|
struct listen_sock *lopt;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#ifdef CONFIG_SYN_COOKIES
|
#ifdef CONFIG_SYN_COOKIES
|
||||||
if (sysctl_tcp_syncookies)
|
if (sysctl_tcp_syncookies) {
|
||||||
msg = "Sending cookies";
|
msg = "Sending cookies";
|
||||||
else
|
want_cookie = 1;
|
||||||
|
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDOCOOKIES);
|
||||||
|
} else
|
||||||
#endif
|
#endif
|
||||||
msg = "Dropping request";
|
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
|
||||||
|
|
||||||
pr_info("TCP: Possible SYN flooding on port %d. %s.\n",
|
lopt = inet_csk(sk)->icsk_accept_queue.listen_opt;
|
||||||
ntohs(tcp_hdr(skb)->dest), msg);
|
if (!lopt->synflood_warned) {
|
||||||
|
lopt->synflood_warned = 1;
|
||||||
|
pr_info("%s: Possible SYN flooding on port %d. %s. "
|
||||||
|
" Check SNMP counters.\n",
|
||||||
|
proto, ntohs(tcp_hdr(skb)->dest), msg);
|
||||||
|
}
|
||||||
|
return want_cookie;
|
||||||
}
|
}
|
||||||
|
EXPORT_SYMBOL(tcp_syn_flood_action);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Save and compile IPv4 options into the request_sock if needed.
|
* 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)
|
|||||||
__be32 saddr = ip_hdr(skb)->saddr;
|
__be32 saddr = ip_hdr(skb)->saddr;
|
||||||
__be32 daddr = ip_hdr(skb)->daddr;
|
__be32 daddr = ip_hdr(skb)->daddr;
|
||||||
__u32 isn = TCP_SKB_CB(skb)->when;
|
__u32 isn = TCP_SKB_CB(skb)->when;
|
||||||
#ifdef CONFIG_SYN_COOKIES
|
|
||||||
int want_cookie = 0;
|
int want_cookie = 0;
|
||||||
#else
|
|
||||||
#define want_cookie 0 /* Argh, why doesn't gcc optimize this :( */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Never answer to SYNs send to broadcast or multicast */
|
/* Never answer to SYNs send to broadcast or multicast */
|
||||||
if (skb_rtable(skb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
|
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)
|
|||||||
* evidently real one.
|
* evidently real one.
|
||||||
*/
|
*/
|
||||||
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
|
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
|
||||||
if (net_ratelimit())
|
want_cookie = tcp_syn_flood_action(sk, skb, "TCP");
|
||||||
syn_flood_warning(skb);
|
if (!want_cookie)
|
||||||
#ifdef CONFIG_SYN_COOKIES
|
goto drop;
|
||||||
if (sysctl_tcp_syncookies) {
|
|
||||||
want_cookie = 1;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
goto drop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Accept backlog is full. If we have already queued enough
|
/* 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)
|
|||||||
while (l-- > 0)
|
while (l-- > 0)
|
||||||
*c++ ^= *hash_location++;
|
*c++ ^= *hash_location++;
|
||||||
|
|
||||||
#ifdef CONFIG_SYN_COOKIES
|
|
||||||
want_cookie = 0; /* not our kind of cookie */
|
want_cookie = 0; /* not our kind of cookie */
|
||||||
#endif
|
|
||||||
tmp_ext.cookie_out_never = 0; /* false */
|
tmp_ext.cookie_out_never = 0; /* false */
|
||||||
tmp_ext.cookie_plus = tmp_opt.cookie_plus;
|
tmp_ext.cookie_plus = tmp_opt.cookie_plus;
|
||||||
} else if (!tp->rx_opt.cookie_in_always) {
|
} else if (!tp->rx_opt.cookie_in_always) {
|
||||||
|
@ -531,20 +531,6 @@ static int tcp_v6_rtx_synack(struct sock *sk, struct request_sock *req,
|
|||||||
return tcp_v6_send_synack(sk, req, rvp);
|
return tcp_v6_send_synack(sk, req, rvp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void syn_flood_warning(struct sk_buff *skb)
|
|
||||||
{
|
|
||||||
#ifdef CONFIG_SYN_COOKIES
|
|
||||||
if (sysctl_tcp_syncookies)
|
|
||||||
printk(KERN_INFO
|
|
||||||
"TCPv6: Possible SYN flooding on port %d. "
|
|
||||||
"Sending cookies.\n", ntohs(tcp_hdr(skb)->dest));
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
printk(KERN_INFO
|
|
||||||
"TCPv6: Possible SYN flooding on port %d. "
|
|
||||||
"Dropping request.\n", ntohs(tcp_hdr(skb)->dest));
|
|
||||||
}
|
|
||||||
|
|
||||||
static void tcp_v6_reqsk_destructor(struct request_sock *req)
|
static void tcp_v6_reqsk_destructor(struct request_sock *req)
|
||||||
{
|
{
|
||||||
kfree_skb(inet6_rsk(req)->pktopts);
|
kfree_skb(inet6_rsk(req)->pktopts);
|
||||||
@ -1179,11 +1165,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
|
|||||||
struct tcp_sock *tp = tcp_sk(sk);
|
struct tcp_sock *tp = tcp_sk(sk);
|
||||||
__u32 isn = TCP_SKB_CB(skb)->when;
|
__u32 isn = TCP_SKB_CB(skb)->when;
|
||||||
struct dst_entry *dst = NULL;
|
struct dst_entry *dst = NULL;
|
||||||
#ifdef CONFIG_SYN_COOKIES
|
|
||||||
int want_cookie = 0;
|
int want_cookie = 0;
|
||||||
#else
|
|
||||||
#define want_cookie 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (skb->protocol == htons(ETH_P_IP))
|
if (skb->protocol == htons(ETH_P_IP))
|
||||||
return tcp_v4_conn_request(sk, skb);
|
return tcp_v4_conn_request(sk, skb);
|
||||||
@ -1192,14 +1174,9 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
|
|||||||
goto drop;
|
goto drop;
|
||||||
|
|
||||||
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
|
if (inet_csk_reqsk_queue_is_full(sk) && !isn) {
|
||||||
if (net_ratelimit())
|
want_cookie = tcp_syn_flood_action(sk, skb, "TCPv6");
|
||||||
syn_flood_warning(skb);
|
if (!want_cookie)
|
||||||
#ifdef CONFIG_SYN_COOKIES
|
goto drop;
|
||||||
if (sysctl_tcp_syncookies)
|
|
||||||
want_cookie = 1;
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
goto drop;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sk_acceptq_is_full(sk) && inet_csk_reqsk_queue_young(sk) > 1)
|
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)
|
|||||||
while (l-- > 0)
|
while (l-- > 0)
|
||||||
*c++ ^= *hash_location++;
|
*c++ ^= *hash_location++;
|
||||||
|
|
||||||
#ifdef CONFIG_SYN_COOKIES
|
|
||||||
want_cookie = 0; /* not our kind of cookie */
|
want_cookie = 0; /* not our kind of cookie */
|
||||||
#endif
|
|
||||||
tmp_ext.cookie_out_never = 0; /* false */
|
tmp_ext.cookie_out_never = 0; /* false */
|
||||||
tmp_ext.cookie_plus = tmp_opt.cookie_plus;
|
tmp_ext.cookie_plus = tmp_opt.cookie_plus;
|
||||||
} else if (!tp->rx_opt.cookie_in_always) {
|
} else if (!tp->rx_opt.cookie_in_always) {
|
||||||
|
Loading…
Reference in New Issue
Block a user