当前位置: 首页 > Linux

如何处理SYN

时间:2023-04-06 02:32:09 Linux

SYN是TCP三次握手的一部分。在开发网络应用时通常不被重视,但它与请求中偶尔出现的长时间延迟(latencyspike)密切相关,是服务器维护环节中不可忽视的重要一环。.如果SYN包在发送过程中丢失,通常客户端会在1s、3s、7s、15s、31s后重试,这是造成长时延的原因之一。困扰游戏公司的SYNFlood攻击也是利用了SYN的特性。查看原来Linux是如何处理SYN的,如下图TCP状态图上半部分,应用listen()后,可以收到SYN并发送SYN+ACK,进入SYNRECEIVED状态;等待ACK后,进入ESTABLISHED状态。然后它可以与accept()一起应用。这意味着在一个TCP连接的建立过程中,有两个等待:1是等待ACK,2是等待申请accept()。linux使用2个队列来实现两次等待,队列中保存了structinet\_request\_sock结构体。我们不考虑像TCP\_SAVED\_SYN,TCP\_DEFER\_ACCEPT,TCP\_FAST\_OPEN这样的特殊情况。第一个队列是SYN队列(也称为不完整队列)。收到SYN并返回SYN+ACK后,连接会保存在这个队列中等待ACK,连接进入SYNRECEIVED状态。如果等待ACK超时,会重传net.ipv4.tcp_synack_retries次。由于SYNCookie的存在,这个队列的长度并不是很重要。第二个队列是接受队列(也称为完成队列)。当收到ACK后,连接从SYN队列中移除,保存在Accept队列中,进入ESTABLISHED状态,等待应用程序调用accept()。如果队列已满,将发送RST。SYNQueue的长度由/proc/sys/net/ipv4/tcp_max_syn_backlog控制。Accept队列的长度受listen()第二个参数backlog的限制,不能大于/proc/sys/net/core/somaxconn。Linux5.4之前somaxconn默认值为128,5.4之后改为4096。最佳AcceptQueue长度是多少这个问题经常被问到:应该将backlog设置为多少?答案是视情况而定。大多数情况下这个参数并不重要,在Golang1.11之前甚至不能更改这个参数。如果新连接很频繁,或者设置了TCP\_DEFER\_ACCEPT,可以设置大一些。但是设置太大也是不对的,一个inet_requst_sock占用256字节。一些系统管理员会建议设置一个非常大的积压并使net.core.somaxconn非常大。这实际上掩盖了应用程序的问题。如果应用程序来不及消费,那么拥有一个大队列就没有多大意义。相反,它会导致客户端长时间延迟。最好设置一个短队列,并使用RST尽快告诉客户端出现问题,可能需要重新连接。如果您设置了合适的负载均衡器,那么在您重新连接时可能会很好。我一般设置listen(fd,-1)然后根据情况修改somaxconn的值。使用以下命令查看端口的SYNQueue元素数:ss-nstatesyn-recvsport=:80|wc-l使用以下命令查看端口的AcceptQueue元素个数,其中Recv-Q为AcceptQueue元素个数,Send-Q为backlog参数。ss-plntsport=:80有几个变量可以检查队列满的次数:TcpExtListenOverflows是AcceptQueue满了无法服务的次数,TcpExtTCPReqQFullDoCookies是SYNQueue满的次数和变成了SynSookie。使用以下命令查看这些变量:nstat-azTcpExtListenOverflows根据实际需要调整somaxconn。SYNFlood和SYNCookie1996年以前,连续发送SYN可以使服务器SYNQueue满而停止服务,直到出现SYNCookie。这种攻击就是SYNFlodd,它只需要少量的带宽,发送的数据包也不会太多来填满SYNQueue,简单有效。syn-flood.c我不是叫你去攻击别人,因为ACK的ack值就是SYN+ACK的seq值,你可以把SYN的hash值保存在seq中,等收到ACK的时候再验证。这样就不再需要SYN队列了:+------------+--------+------------------+|6位|2位|24位||t模32|管理系统|hash(ip,port,t)|+----------+------+-----------------+之后启用syncookie(net.ipv4.tcp_timestamps=1,默认启用),当SYNQueue已满时将启用此功能以防止SYNFlood。麻烦的问题是,这会向网络发送大量无用的SYN+ACK。Linux4.4之前,SYN处理的很慢,后来他们去掉了一个kernellock,现在基本上不用太担心SYNFlood了。