linux诡异的半连接(SYN_RECV)队列长度
linux诡异的半连接(SYN_RECV)队列长度(一)
>>转载请注明来源:飘零的代码 piao2010 ’s blog,谢谢!^_^
>>本文链接地址:linux诡异的半连接(SYN_RECV)队列长度(一)
最近在学习TCP方面的基础知识,对于古老的SYN Flood也有了更多认识。SYN Flood利用的是TCP协议缺陷,发送大量伪造的TCP连接请求,从而使得被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式。
SYN Flood的原理简单,实现也不复杂,而且网上有许多现成的程序。
我在两台虚拟机上(虚拟机C攻击虚拟机S)做测试,S上跑了apache监听80端口,用C对S的80端口发送SYN Flood,在无任何防护的情况下攻击效果显著。用netstat可以看见80端口存在大量的半连接状态(SYN_RECV),用tcpdump抓包可以看见大量伪造IP发来的SYN连接,S也不断回复SYN+ACK给对方,可惜对方并不存在(如果存在则S会收到RST这样就失去效果了),所以会超时重传。
这个时候如果有正常客户A请求S的80端口,它的SYN包就被S丢弃了,因为半连接队列已经满了,达到攻击目的。
对于SYN Flood的防御一般会提到修改 net.ipv4.tcp_synack_retries, net.ipv4.tcp_syncookies, net.ipv4.tcp_max_syn_backlog
目的就是减小SYN+ACK重传次数,增加半连接队列长度,启用syn cookie。
当S开启syn cookie的时候情况会缓解,一旦半连接队列满了系统就会启用syn cookie功能,同时在/var/log/messages记录kernel: possible SYN flooding on port 80. Sending cookies.
但也不是可以完全防御的,如果说攻击瞬间并发量足够大,毕竟S的CPU内存有限,一般大公司都有专业的防火墙设备来应对。
其中对于net.ipv4.tcp_max_syn_backlog的描述一般都称为半连接队列的长度,但在我实际测试的过程中却发现SYN_RECV状态的数量与net.ipv4.tcp_max_syn_backlog设置的值相差甚远。
S系统配置如下:
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_syncookies = 0
net.ipv4.tcp_max_syn_backlog = 4096
但SYN_RECV状态的数量却只有256
于是就开始相关资料,首先想到的是TCP/IP详解卷1中提到的backlog,man 2 listen:
int listen(int sockfd, int backlog);
The backlog parameter defines the maximum length the queue of pending connections may grow to. If a connection request arrives with
the queue full the client may receive an error with an indication of ECONNREFUSED or, if the underlying protocol supports retransmis-
sion, the request may be ignored so that retries succeed.
NOTES
The behaviour of the backlog parameter on TCP sockets changed with Linux 2.2. Now it specifies the queue length for completely estab-
lished sockets waiting to be accepted, instead of the number of incomplete connection requests. The maximum length of the queue for
incomplete sockets can be set using the tcp_max_syn_backlog sysctl. When syncookies are enabled there is no logical maximum length
and this sysctl setting is ignored. See tcp(7) for more information.
可见backlog在Linux 2.2之后表示的是已完成三次握手但还未被应用程序accept的队列长度。
man 7 tcp:
tcp_max_syn_backlog (integer; default: see below)
The maximum number of queued connection requests which have still not received an acknowledgement from the connecting client.
If this number is exceeded, the kernel will begin dropping requests. The default value of 256 is increased to 1024 when the
memory present in the system is adequate or greater (>= 128Mb), and reduced to 128 for those systems with very low memory (<=
32Mb). It is recommended that if this needs to be increased above 1024, TCP_SYNQ_HSIZE in include/net/tcp.h be modified to
keep TCP_SYNQ_HSIZE*16<=tcp_max_syn_backlog, and the kernel be recompiled.
可见tcp_max_syn_backlog确实是半连接队列的长度,那为何会不准呢?
这时候正好让同事也在两台机器上测试了一下,得到的数据居然与tcp_max_syn_backlog完全一致。
开始怀疑是系统哪个地方配置有问题,又发现一个可疑的配置 net.core.somaxconn 它是listen的第二个参数int backlog的上限值,如果程序里的backlog大于
net.core.somaxconn的话就会取net.core.somaxconn的值。S系统的net.core.somaxconn = 128
//file:net/socket.c |
查了apache文档关于ListenBackLog 指令的说明,默认值是511. 可见最终全连接队列(backlog)应该是net.core.somaxconn = 128
证实这点比较容易,用慢连接攻击测试观察到虚拟机S的80端口ESTABLISHED状态最大数量384
正好等于256(apache prefork模式MaxClients即apache可以响应的最大并发连接数) + 128(backlog即已完成三次握手等待apache accept的最大连接数)。说明全连接队列长度等于min(backlog,somaxconn);
好久没写这么多文字了,下回linux诡异的半连接(SYN_RECV)队列长度(二)继续
linux诡异的半连接(SYN_RECV)队列长度(二)
>>转载请注明来源:飘零的代码 piao2010 ’s blog,谢谢!^_^
>>本文链接地址:linux诡异的半连接(SYN_RECV)队列长度(二)
继续上回:我们已经确认了全连接队列的长度计算,接下来继续寻找半连接队列长度。
试着慢慢减小tcp_max_syn_backlog的值,但还是看不到半连接状态数量的变化。
实在没什么思路,只能Google之,搜出来的基本都是关于SYN Flood的文章,难道没同学关注过半连接队列的长度吗?
困扰数日终于在某个夜晚被我找一篇题为《关于半连接队列的释疑》的文章,激动呐。根据作者提供的思路我开始翻代码,注意我用的内核版本2.6.32,不同版本代码也有差异。
首先定位到tcp_v4_conn_request函数,在文件netipv4tcp_ipv4.c中。
int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb) |
跟进关键函数inet_csk_reqsk_queue_is_full,在文件includenetinet_connection_sock.h中。
static inline int inet_csk_reqsk_queue_is_full(const struct sock *sk) |
跟进关键函数reqsk_queue_is_full,在文件includenetrequest_sock.h中。
static inline int reqsk_queue_is_full(const struct request_sock_queue *queue) |
查找qlen和max_qlen_log的定义,在文件includenetrequest_sock.h中。
/** struct listen_sock - listen state |
可见关键是如何计算max_qlen_log,前一篇博客提到了listen的系统调用:
//file:net/socket.c |
sock->ops->listen其实是inet_listen,在文件netipv4af_inet.c中。
int inet_listen(struct socket *sock, int backlog) |
跟进inet_csk_listen_start,在文件netipv4inet_connection_sock.c中。
int inet_csk_listen_start(struct sock *sk, const int nr_table_entries) |
跟进reqsk_queue_alloc,在文件netcorerequest_sock.c中。
int reqsk_queue_alloc(struct request_sock_queue *queue, |
代码到此为止,然后我们计算一下为何在虚拟机S上的SYN_RECV状态数量会是256
nr_table_entries = listen的第二个参数int backlog ,上限是系统的somaxconn
若 somaxconn = 128 sysctl_max_syn_backlog = 4096 backlog = 511 则 nr_table_entries = 128
nr_table_entries = min_t(u32, nr_table_entries, sysctl_max_syn_backlog);
取两者较小的一个 nr_table_entries = 128
nr_table_entries = max_t(u32, nr_table_entries, 8);
取两者较大的一个 nr_table_entries = 128
nr_table_entries = roundup_pow_of_two(nr_table_entries + 1); //roundup_pow_of_two - round the given value up to nearest power of two
roundup_pow_of_two(128 + 1) = 256
for (lopt->max_qlen_log = 3; (1 << lopt->max_qlen_log) < nr_table_entries; lopt->max_qlen_log++);
max_qlen_log = 8
判断半连接队列是否满 queue->listen_opt->qlen >> queue->listen_opt->max_qlen_log;
queue->listen_opt->qlen = 256 时reqsk_queue_is_full返回1 , 进入drop
所以queue->listen_opt->qlen 取值 0~255, 因此SYN_RECV状态数量会是 256
另外同事的测试结果为何与我的不同?
因为内核版本小于2.6.20的话max_qlen_log是直接由sysctl_max_syn_backlog决定的,所以半连接队列的长度就是等于sysctl_max_syn_backlog
文章有点长,不过总算是把问题给解决了。这里要特别感谢雨哥(博客),很多代码是他带着我分析的。
linux诡异的半连接(SYN_RECV)队列长度的更多相关文章
- linux诡异的硬盘不足
phpmyadmin页面登录不进去,ftp也连不上.而服务端的service都开着的.直觉是看一下硬盘使用情况. df -TH 发现可用空间几乎为0 但是查看各个目录使用情况: du -sh /* | ...
- Linux 网卡驱动学习(六)(应用层、tcp 层、ip 层、设备层和驱动层作用解析)
本文将介绍网络连接建立的过程.收发包流程,以及当中应用层.tcp层.ip层.设备层和驱动层各层发挥的作用. 1.应用层 对于使用socket进行网络连接的server端程序.我们会先调用socket函 ...
- Linux 驱动开发
linux驱动开发总结(一) 基础性总结 1, linux驱动一般分为3大类: * 字符设备 * 块设备 * 网络设备 2, 开发环境构建: * 交叉工具链构建 * NFS和tftp服务器安装 3, ...
- kernel笔记:TCP参数
http://blog.chinaunix.net/uid-27119491-id-3346430.html 本文将介绍网络连接建立的过程.收发包流程,以及其中应用层.tcp层.ip层.设备层和驱动层 ...
- TCP/IP 三次握手
网络连接状态 网络连接状态(11种)非常重要这里既包含三次握手中的也包括四次断开中的,所以要熟悉. LISTEN 被动打开,首先服务器需要打开一个socket进行监听,监听来自远方TCP端口的连接请求 ...
- kernel笔记——网络收发包流程
本文将介绍网络连接建立的过程.收发包流程,以及其中应用层.tcp层.ip层.设备层和驱动层各层发挥的作用. 应用层 对于使用socket进行网络连接的服务器端程序,我们会先调用socket函数创建一个 ...
- 浅谈Nginx性能调优
点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! Linux系统参数优化 下文中提到的一些配置,需要较新的 ...
- NGINX高性能Web服务器详解(读书笔记)
原文地址:NGINX高性能Web服务器详解(读书笔记) 作者:夏寥寥 第4章 Nginx服务器的高级配置 4.1 针对IPv4的内核7个参数的配置优化 说明:我们可以将这些内核参数的值追加到Linu ...
- python uwsgi 部署以及优化
这篇文章其实两个月之前就应该面世了,但是最近琐事.烦心事太多就一直懒得动笔,拖到现在才写 一.uwsgi.wsgi.fastcgi区别和联系 参见之前的文章 http://www.cnblogs.co ...
随机推荐
- ExecuteReader
最近在做winform的编程,想到一真没有使用过ExecuteReader.可能以前以后它的用户不大,或者 不大好用,故没有用过.今天在这里将学习记录写下来,供读者参考: 1.MSDN上说:Sends ...
- Win7 下,离线安装 Android Studio 1.0.1 的方法
此教程没有亲自动手试过,先保存在这里 http://download.csdn.net/detail/tuobaxiao2008/8268281
- 0xc000000f: Error attempting to read the boot configuration data
Get the fix to “0xc000000f: error attempting to read the boot configuration data” boot error for Win ...
- python cookielib
# HttpClient.py is written by [xqin]: https://github.com/xqin/SmartQQ-for-Raspberry-Piimport cookiel ...
- 工具批处理Demo
前言:用C语言写一些小型工具时,使用传递参数的方式会比较方便.如GIF文件转换为头文件工具,如果我们需要将某一个文件夹里所有的gif文件都转换为头文件,这时我们用批处理给这个工具传递参数,会方便很多. ...
- System.Reflection.Assembly.GetEntryAssembly()获取的为当前已加载的程序集
今天在使用System.Reflection.Assembly.GetEntryAssembly()获取程序集时,发现获取的程序集不全.原来是因为C#的程序集为延迟加载,此方法只获取当前已加载的,未加 ...
- 关于64位Win7/Win 8 下怎么学习汇编语言
我看有许多同学用Win 7/Win 8 学习汇编,现在好多人的内存升级了都用64位系统了,但是64位W7没有自带的DEBUG和MASM. 1.首先下载DOSBOX,(下面附带地址)它的作用就是让你在6 ...
- LightOJ_1038 Race to 1 Again
题目链接 题意: 给一个数n, 每次操作是随机的选择一个[1,N]区间内能够被n整除的数进行除法, 然后得到一个新的n. 问n变成1时的期望操作次数. 思路: 设E[n] 为 当数为x时, 变成 1 ...
- 【产品体验】ONE一个
第二篇博客,加油加油~~本人产品新人,学习中,希望大家多多指教! 先来两张ONE的界面图镇楼—— ONE简介: “复杂世界里,一个就够了.”这是一款轻量级的文艺阅读应用,每日更新一张图 ...
- Codeforces 712E Memory and Casinos
Description There are n casinos lined in a row. If Memory plays at casino \(i\), he has probability ...