SYN Flood攻击
它利用TCP协议的三次握手过程进行的攻击。在服务器端收到SYN request包时,发送SYN+ACK给客户端前,服务器要先分配一个数据区描述这个半开连接(Half-open Connection)。攻击者在短时间内发送大
量的TCP SYN包给服务器。服务会为每个TCP SYN包分配一个特定的数据区。这将将导致服务器程序的请求队列满, 最终导致服务器程序接受新连接的接入。
SYN Cookies
服务器端防范SYN Flooding的方法是SYN cookies。它的原理是,当服务器收到TCP SYN包并返回SYN+ACK包时,不分配一个专门的数据区,而是根据这个SYN包计算出一个cookie值。在收到TCP ACK包时,TCP>服务器在根据那个cookie值检查这个TCP ACK包的合法性。如果合法,再分配专门的数据区进行处理未来的TCP连接。默认情况下SYN_Cookies功能是开启的。/proc/sys/net/ipv4/tcp_syncookies
在Linux内核,每个TCP服务器都会有一个队列来保存半打开连接, 它的指依赖于listen函数的backlog参数和tcp_max_syn_backlog。当队列足够的时候内核不会受用syn cookies来进行处理每个TCP SYN。当并发连接数过高或者有SYN Flood攻击的时候会导致满队列,这时候内核会打印出"possible SYN flooding on port x. Sending cookies.“。表示对于当前的连接使用用SYN Cookies(tcp_syncookies 开启>)方式进行处理(进行SYN Flooding防范)。
内核不能阻止对端发起SYN Flood攻击,但可以进行防范。这句打印就表明可能有SYN flooding,开启SYN cookies进行防范。 有些时候只是高并发导致这条打印的出现可以通过增加backlog和tcp_max_syn_backlog值来扩大队列长度。
a. 收到第一个syn的处理
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
{
/*tcp_syncookies为2 进行syn cookie
tcp_syncookies为1 且request队列满了 进行syn cookie处理
tcp_syncookies为0 且request队列满了 将该syn报文drop掉
*/
if ((sysctl_tcp_syncookies == 2 ||
inet_csk_reqsk_queue_is_full(sk)) && !isn) {
want_cookie = tcp_syn_flood_action(sk, skb, "TCP");
if (!want_cookie)
goto drop;
}
}
bool tcp_syn_flood_action(struct sock *sk,
const struct sk_buff *skb,
const char *proto)
{
const char *msg = "Dropping request";
bool want_cookie = false;
struct listen_sock *lopt;
if (sysctl_tcp_syncookies) {
msg = "Sending cookies";
want_cookie = true;
} else
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPREQQFULLDROP);
lopt = inet_csk(sk)->icsk_accept_queue.listen_opt;
if (!lopt->synflood_warned && sysctl_tcp_syncookies != 2) {
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;
}
b. 接收到最后一个ack
tatic struct sock *tcp_v4_hnd_req(struct sock *sk, struct sk_buff *skb)
{
.......
#ifdef CONFIG_SYN_COOKIES
/*如果syn被cookies,获得sk*/
if (!th->syn)
sk = cookie_v4_check(sk, skb, &(IPCB(skb)->opt));
#endif
return sk;
}