在linux网络编程中,使用listen函数监听套接字,在linux中man其用法,第2个参数解释如下:
The backlog argument defines the maximum length to which the queue of pending connections for sockfd may grow. If a connection request arrives when the queue is full, the client may receive an error with an indication of ECONNREFUSED or, if the underlying protocol supports retransmission, the request may be ignored so that a later reattempt at connection succeeds.
backlog参数定义了sockfd套接字上“未完成连接”队列可增长到的最大值;TCP经过3次握手建立连接,所谓“未完成连接”是指服务端回复SYN+ACK,等待客户端ACK完成连接的SYN_RCVD状态;这个参数的定义比较晦涩,它没有解释“未完成连接”是指处于SYN_RCVD状态的连接,还是尚未被进程接受的处于ESTABLISHED状态的连接,亦或两者皆可;而实际上,backlog的含义从未有过正式的定义。
内核为任何一个给定的监听套接字维护两个队列:“未完成连接”和“已完成连接”,当进程调用accept时,“已完成连接队列”中的队头项将返回给进程,或者如果这个队列为空,那么进程将被投入睡眠,直到TCP在该队列中放入一项才唤醒它。
backlog指定了这两个队列和的最大值,一旦内核中的这两个队列被占用完,其它用户的连接请求就会返回失败(ECONNREFUSED);SYN Flood攻击就是利用这个原理,它通过不进行TCP三次握手中最后一步ACK应答,使服务端的连接处于未完成状态,耗尽系统资源。简单的缓解措施主要有1.缩短连接的Timeout时间;2.减少重传SYN+ACK次数;3.增大backlog,使其能容纳更多连接;但这都是治标不治本方法。
到目前为止,能够有效防范SYN Flood攻击的手段并不多,而SYN Cookie就是其中最著名的一种。SYN Cookie原理由D.J.Bernstain和 Eric Schenk发明,其在linux等诸多操作系统上都有相关实现。
SYN Cookie的原理是在TCP服务器收到SYN包并返回SYN+ACK包时,不分配一个专门的数据区,而是根据这个SYN包计算出一个cookie值。在收到TCP ACK包时,TCP服务器再根据那个cookie值检查这个TCP ACK包的合法性,如果合法,再分配专门的数据区处理此连接。
在linux系统中,打开或关闭SYN Cookie功能,可以通过设置/proc/sys/net/ipv4/tcp_syncookies的值(或在/etc/sysctl.conf中 net.ipv4.tcp_syncookies的值),值为0关闭SYN Cookie功能,值为1打开SYN Cookie功能。
[email protected] :/home/zzy/unix# cat /proc/sys/net/ipv4/tcp_syncookies
1
注意:syncookie严重的违背TCP协议:不允许使用TCP扩展,可能对某些服务产生严重的性能影响(如SMTP转发)。(该实现与BSD上面使用的tcp proxy一样,是违反了RFC中关于TCP连接的三次握手实现的,但是对于防御SYN Flood的确很有用)
如果单纯解决系统负载过高的问题,linux下可以通过调整以下几个参数:
tcp_max_syn_backlog, tcp_synack_retries, tcp_abort_on_overflow,这三个文件都是在/proc/sys/net/ipv4目录下。
tcp_max_syn_backlog:内存中可以缓存多少个SYN请求。该变量需要打开tcp_syncookies才有效。如果服务器负载很高,可以尝试提高该变量的值。
[email protected] :/home/zzy/unix# cat /proc/sys/net/ipv4/tcp_max_syn_backlog
128
tcp_synack_retries:用于TCP三次握手机制中第二次握手,当收到客户端发来的SYN连接请求后,服务端将回复SYN+ACK包,这时服务端处于SYN_RCVD状态,并等待客户端发来的回复ACK包。如果服务端没有收到客户端的ACK包,会重新发送SYN+ACK包,直到收到客户端的ACK包。该变量设置发送 SYN+ACK包的次数,超过这个次数,服务端将放弃连接。默认值是5。
[email protected] :/home/zzy/unix# cat /proc/sys/net/ipv4/tcp_synack_retries
5
tcp_abort_on_overflow:是个布尔值,默认值为0(FALSE关闭)。如果开启,当服务端太忙不能接受新连接时,服务端会发送RST包给客户端,令客户端重新连接。只有在你确信进程真的不能完成连接请求时才打开该选项,该选项会影响客户的使用。(对待已经满载的sendmail、apache这类服务的时候,这个选项可以很快让客户端终止连接,给予服务程序处理已有连接的缓冲机会,所以很多防火墙上推荐打开它)
[email protected] :/home/zzy/unix# cat /proc/sys/net/ipv4/tcp_abort_on_overflow
0