【转】iptables的nf_conntrack相关参数引起两个问题
作者:易隐者 发布于:2016-4-23 11:49 Saturday 分类:案例讨论
【说在之前】:
近段时间在处理一个故障时,网上查找相关资料时看到的一篇文章,作者处理故障时的态度和思路堪称技术牛典范,特转发过来分享给大家。
【原文作者】:phanx
【原文链接】:http://blog.chinaunix.net/uid-7549563-id-4912055.html
【原为全文】:
========phanx.com========
Author: phanx
Updated: 2015-3-23
转载请保留作者信息
=========================
某关键业务系统上频繁出现业务失败,并发生了一次大规模业务中断。
该系统采用两台IBM Power 740运行AIX 6.1+Oracle 11gR2 RAC作为数据库服务器,两台DELL PowerEdge R720作为应用服务器,前端采用F5作为负载均衡设备。
数据库服务器和应用服务器之间有Cisco ASA5585硬件防火墙进行访问控制。
应用服务器上运行自行开发的C程序,通过Oracle Client提供的接口,以长连接的方式访问RAC数据库。
故障时,先检查了数据库服务器的系统负载,发现相对于正常时期,CPU负载偏高,IO负载明显升高,IOPS达到13000左右。
正常时的负载
异常时的负载
检查数据库相关日志,发现有大量的TNS错误:
- Fatal NI connect error 12170.
- VERSION INFORMATION: VERSION INFORMATION:
TNS for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
TCP/IP NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
Oracle Bequeath NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
VERSION INFORMATION:
TNS for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
TCP/IP NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
Oracle Bequeath NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
VERSION INFORMATION:
TNS for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
TCP/IP NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
Oracle Bequeath NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
VERSION INFORMATION:
TNS for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
TCP/IP NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
Oracle Bequeath NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
Mon Feb 23 13:22:16 2015
Time: 23-Feb-2015 13:22:16
*********************************************************************** Time: 23-Feb-2015 13:22:16
Time: 23-Feb-2015 13:22:16
Time: 23-Feb-2015 13:22:16
Tracing not turned on.
Tracing not turned on.
Fatal NI connect error 12170.
Tracing not turned on.
Tracing not turned on.
Tns error struct:
Tns error struct:
VERSION INFORMATION:
TNS for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
TCP/IP NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
Oracle Bequeath NT Protocol Adapter for IBM/AIX RISC System/6000: Version 11.2.0.3.0 - Production
Tns error struct:
Tns error struct:
ns main err code: 12535
ns main err code: 12535
Time: 23-Feb-2015 13:22:16
ns main err code: 12535
ns main err code: 12535
Tracing not turned on.
Tns error struct:
TNS-12535: TNS:operation timed out
TNS-12535: TNS:operation timed out
TNS-12535: TNS:operation timed out
ns secondary err code: 12560
ns main err code: 12535
TNS-12535: TNS:operation timed out
ns secondary err code: 12560
ns secondary err code: 12560
nt main err code: 505
ns secondary err code: 12560
nt main err code: 505
nt main err code: 505
nt main err code: 505
TNS-12535: TNS:operation timed out
TNS-00505: Operation timed out
TNS-00505: Operation timed out
ns secondary err code: 12560
TNS-00505: Operation timed out
nt secondary err code: 78
nt secondary err code: 78
nt main err code: 505
TNS-00505: Operation timed out
nt secondary err code: 78
nt OS err code: 0
nt OS err code: 0
nt secondary err code: 78
nt OS err code: 0
Client address: (ADDRESS=(PROTOCOL=tcp)(HOST=10.1.32.70)(PORT=37975))
TNS-00505: Operation timed out
nt OS err code: 0
Client address: (ADDRESS=(PROTOCOL=tcp)(HOST=10.1.32.70)(PORT=25972))
Client address: (ADDRESS=(PROTOCOL=tcp)(HOST=10.1.32.70)(PORT=9108))
nt secondary err code: 78
Client address: (ADDRESS=(PROTOCOL=tcp)(HOST=10.1.32.70)(PORT=52073))
nt OS err code: 0
Client address: (ADDRESS=(PROTOCOL=tcp)(HOST=10.1.32.70)(PORT=49148))
- Mon Feb 23 13:22:16 2015
再检查应用服务器端,发现应用服务进程大量处于Busy状态,无法处理应用数据。再检查应用服务器到数据库的连接情况,发现数据库上报告timeout的连接,在应用服务器上仍然处于ESTABLISHED状态。
- [sysadmin@appsrv1 ~]$ netstat -an|grep 10.1.197.15
- tcp 0 0 10.1.32.70:37975 10.1.197.15:1521 ESTABLISHED
- tcp 0 0 10.1.32.70:25972 10.1.197.15:1521 ESTABLISHED
- tcp 0 0 10.1.32.70:9108 10.1.197.15:1521 ESTABLISHED
- tcp 0 0 10.1.32.70:52073 10.1.197.15:1521 ESTABLISHED
- tcp 0 0 10.1.32.70:49148 10.1.197.15:1521 ESTABLISHED
- .
- .
- .
- .
这时候,怀疑是不是ASA阻断了数据库和应用之间的连接。检查ASA配置后发现超时时间设置的是8个小时,这个业务在低谷期也不会出现8小时空闲,并且应用程序会在空闲的时候定期探测数据库长连接是否可用。
因此,觉得不太可能是常见的空闲超时导致的连接中断。 继续进行分析,发现数据库里面有较多的direct path read 等待事件。观察应用SQL的执行计划,发现有大量的全表扫描,并且某些SQL的执行时间较长,
超过了60秒。 很显然这是常见的11g Direct Path Read的副作用,要么让应用开发组去优化SQL,要么关掉11g的针对串行的直接路径读。这样就会缓解系统IO繁忙的情况。这样SQL的执行时间也会降低,如果在
合理的范围内,就不会引发这个故障了。
但是,仅仅是这个原因,应该不会引起TNS Time out的情况,性能不好,SQL执行时间过长,只是让这个问题浮现了出来,并不是这个故障的根本原因。
所以还得继续分析是什么导致应用服务器和数据库服务器之间的已建立连接被单向断掉。
应用组把挂死的服务器进程kill掉后,重启了服务进程,业务暂时是恢复了。
这时候,让应用组找到连接中断时执行的相应的SQL和连接端口,再找到网络组的兄弟帮忙,从Riverbed Cascade上提取了RAC一个节点和其中一个APP的对应端口的通信流,用wireshark打开进行分析。
我们从ARW和ASH报告中发现引起中断的情况中,SQL执行时间都较长,基本达到了5分钟左右。 然后针对这些执行较长的SQL的连接数据流分析,应用服务器在提交SQL执行请求后等待数据库服务器回复。
数据库服务器在执行完以后返回数据给应用服务器时,应用服务器就一直无法接收到数据了,然后数据库服务器就一直重传,直到超时,然后报错TNS Time out。
从这个TCP流上可以清楚看到,appsrv1在12:20.040144的时候提交了SQL执行请求,紧接着收到了racdb1的ACK报文,说明racdb1成功接收了这个请求,并且开始执行。
在15:55.30881的时候,racdb1执行完这个SQL后开始向appsrv1返回结果,SQL执行了215秒左右。这时候,appsrv1没有任何回应。直到最后超时,racdb1发出重置连接的RST报文。
这个情况,总是感觉不对,为什么appsrv1莫名其妙的不响应了呢? appsrv1并没有宕机,网络连接也正常的,百思不得其解。 最后想实在没有办法的话,只能到appsrv1上去抓包看看。
由于appsrv1比较繁忙,在无法确定故障发生的情况下持续抓包的记录数据肯定会相当庞大,并且肯定会对应用服务器造成较大的压力,并且存储空间也是个问题。
这时候,应用组的人报告说偶尔会有一两个服务进程出现挂死的情况。 于是决定去碰碰运气,设好capture条件,只抓取与racdb1的通信,与其余关联应用服务器的包全部过滤掉,抓了5分钟,就已经有20个G的数据了。
这么大的数据,我的4G内存i3小破本子开起来都是个问题,于是找了一台强力的测试服务器,传上去看看。 翻着翻着发现了一些TCP重传,看起来像故障的现象了,但是发现appsrv1对于重传却返回了
ICMP Host Administratively Prohibited,并不是完全没有反应。 于是再找网络组按照时间段提取数据,发现故障时是一样的,在racdb1重传的时候,appsrv1每个重传都回应了ICMP Host Administratively Prohibited。
原来,网络组的哥们从Riverbed Cascade里面提取数据流的时候是设定了只提取TCP相关端口的报文,ICMP报文就被漏掉了,没有提取出来。于是,重新提取故障时候的TCP流和相关数据包。
这个时候就可以看到完整的信息了。确实每个重传都有回应的。
TCP流是建立起来的,iptables里面也应该也有正常的流状态信息,为什么会被appsrv1拒绝呢?
继续对appsrv1进行检查,发现 /etc/sysctl.conf里面配置了这么一句
net.netfilter.nf_conntrack_tcp_timeout_established = 300
就是它让iptables对于已建立的连接,300秒若没有活动,那么则清除掉,默认的时间是432000秒(5天)。
问是谁设置的这个参数,答复是应用组在上线前做性能测试时,按照应用供应商的建议修改的。为啥要改,为啥改成这个值也不清楚 。
好吧,应该就是它了,改回默认的值 432000 应该就能解决了。同时让应用组的优化优化SQL,就可以写故障报告了。
故事就到这里就完了? 当然不是。 在调整了这个值后,一开始还风平浪静。过了一段时间,应用组又来报告说,又出现了很少的
业务超时,而且有越来越频繁的趋势,从一天一两次到一条一二十次。真是不省心啊。。
继续了解情况,这次仿佛跟数据库服务器没啥关系了,是这个应用服务器到服务器总线应用之间的连接出现了问题。服务总线应用服务器向该应用服务器发起连接的时候,偶尔会被拒绝。
考虑到应用服务器之前有F5来作为负载均衡,先检查了F5上应用服务状态有没有异常,结果良好,F5上对应用的健康探测没有异常。 好吧,还是直接看数据流,为啥会拒绝应用连接。
服务总线应用服务器和该应用服务器之间通信是短连接,有业务调用的时候,由服务总线方发起连接。应用组找到了被拒绝的连接,通过debug日志找到相关端口信息,继续让网络组
提取相关连接数据包。
这里可以看到,在svcbus2向appsrv1发起请求后,同样有应答,但是一分钟后,svcbus2关闭了连接。再过了3分钟appsrv1处理完请求后返回数据给svcbus2的时候就被svcbus2给拒绝掉了,然后同样也是不停重传,最后超时。
应用组说svcbus2上,应用有一个60秒超时的机制,当对端在60秒内没有返回结果就直接关闭这个请求,断掉连接。
从上面的报文也可以看到,svcbus2发起了FIN报文,但是由于appsrv1没有处理完,所以这个连接关闭是单向的,直到appsrv1处理完成,重传数据超时,连接完全关闭。
这和svcbus2新建连接到appsrv1被拒绝有啥关系呢?我一时也没有想明白。 appsrv1上的iptables对于服务端口应该是一直开放的,不应该拒绝新建的连接啊,除非这个新建的连接有什么特殊的地方。
通过红帽的客户网站,找到了一些相关信息。
https://access.redhat.com/solutions/73353 iptables randomly drops new connection requests
- if /proc/net/ipv4/netfilter/ip_conntrack_tcp_loose is set to 1, iptables creates a new connection-tracking entry after receiving any packet, not just packets with the SYN flag set
- the ip_conntrack_tcp_loose setting is useful in firewalls for keeping already established connections unaffected if the firewall restarts, but this causes issues in the following scenario:
- a client initiates a new connection with the same source port it used in a previous connection
- the server already has an iptables connection-tracking entry for the same IP address and port, with states ESTABLISHED and UNREPLIED
- the default rule gets hit, instead of the desired one
- the packet is dropped, and the server returns icmp-host-prohibited
https://access.redhat.com/solutions/73273 Why iptables sporadically drops initial connections requests?
This behavior is caused by enabling ip_conntrack_tcp_loose sysctl parameter which enables iptables to create a conntrack entry whenever it sees any packet from any direction and not just SYN packet.
This is called connection picking and is usually used by the firewalls to ensure that the ongoing end to end sessions remain active if for some reason the firewall gets restarted. But this feature is not needed in standalone servers.
这里面提到了iptables在规则为allow的情况下也会对某些数据包drop的情况。大意就是在默认情况下(/proc/net/ipv4/netfilter/ip_conntrack_tcp_loose 为1时),iptables会对即时是不完整的TCP连接也会记录其状态,这样避免
iptables重启的时候影响已有的连接,但是会影响一些特殊情况。
我们的应用正好就出现了这种特殊情况。当svcbus2因为等待appsrv1应答超时的时候,关闭了连接。而appsrv1上的nf_conntrack表中,当收到svcbus2发送的FIN包是,对于这个连接的记录会变成CLOSE_WAIT状态,然后在60秒后,
条目被清除。 但是,当appsrv1开始回应数据的时候,nf_conntrack表中又出现了这个连接的条目,并且状态是ESTABLISHED [UNREPLIED]。
- [root@appsrv1 ~]# grep 51522 /proc/net/nf_conntrack
ipv4 2 tcp 6 35 CLOSE_WAIT src=10.1.32.70 dst=10.1.41.192 sport=9102 dport=51522 src=10.1.41.192 dst=10.1.32.70 sport=51522 dport=9102 [ASSURED] mark=0 secmark=0 use=2
.
- .
- wait more seconds
- .
- .
- [root@appsrv1 ~]# grep 51522 /proc/net/nf_conntrack
- ipv4 2 tcp 6 431965 ESTABLISHED src=10.1.32.70 dst=10.1.41.192 sport=9102 dport=51522 [UNREPLIED] src=10.1.41.192 dst=10.1.32.70 sport=51522 dport=9102 mark=0 secmark=0 use=2
这个条目,由于默认的net.netfilter.nf_conntrack_tcp_timeout_established = 432000 的影响,会一直保持5天,直到红色那个值变为0才会被清除。 这就导致了当svcbus2再以相同的源端口51522向appsrv1发起连接的时候,appsrv1的iptables
会拒绝掉这个请求。
那是不是设置net.ipv4.netfilter.ip_conntrack_tcp_loose=0就行了呢,副作用怎么消除呢?
反复想了想,还是不想就这样了,决定看看有没有其它更优的方法。
到测试环境模拟这个故障,服务端口就用TCP 8888,客户机源端口就用TCP 22222
- 1.配置服务器的iptables 允许tcp 8888端口.
- 2.用python来建立一个监听服务,监听在tcp 8888.
- [root@server ~]# python
- Python 2.6.6 (r266:84292, Sep 4 2013, 07:46:00)
- [GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
- Type "help", "copyright", "credits" or "license" for more information.
- >>> import socket
- >>> serversocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- >>> serversocket.bind(("0.0.0.0",8888))
- >>> serversocket.listen(5)
- >>> (clientsocket, address) = serversocket.accept()
- 3. 从客户端以tcp 22222为源端口发起连接,并发送请求数据
- [root@client ~]# python
- Python 2.6.6 (r266:84292, Sep 4 2013, 07:46:00)
- [GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
- Type "help", "copyright", "credits" or "license" for more information.
- >>> import socket
- >>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- >>> s.bind(("0.0.0.0",22222))
- >>> s.connect(("1.1.1.101",8888))
- >>> s.send("request",100)
- 在server端检查iptable contrack 的状态
- [root@server ~]# grep 103 /proc/net/nf_conntrack
- ipv4 2 tcp 6 431949 ESTABLISHED src=1.1.1.103 dst=1.1.1.101 sport=22222 dport=8888 src=1.1.1.101 dst=1.1.1.103 sport=8888 dport=22222 [ASSURED] mark=0 secmark=0 use=2
- Wait some seconds, then close the connection on client.
- >>> s.close()
- >>> exit()
- 继续检查server端的iptable contrack 状态
- [root@server ~]# grep 103 /proc/net/nf_conntrack
- ipv4 2 tcp 6 54 CLOSE_WAIT src=1.1.1.103 dst=1.1.1.101 sport=22222 dport=8888 src=1.1.1.101 dst=1.1.1.103 sport=8888 dport=22222 [ASSURED] mark=0 secmark=0 use=2
- [root@server ~]# sleep 55
- [root@server ~]# grep 103 /proc/net/nf_conntrack
- server端的条目消失了.
- 4. 当server端向client发送响应数据的时候
- >>> clientsocket.recv(1000)
- 'request'
- >>> clientsocket.send("respond",100)
- 再到server端查看iptable contrack 状态就会发现有 ESTABLISHED[UNREPLIED] 条目.
- 但是看TCP 连接的状态却是 CLOSE_WAIT.
- [root@server ~]# grep 103 /proc/net/nf_conntrack
- ipv4 2 tcp 6 431996 ESTABLISHED src=1.1.1.101 dst=1.1.1.103 sport=8888 dport=22222 [UNREPLIED] src=1.1.1.103 dst=1.1.1.101 sport=22222 dport=8888 mark=0 secmark=0 use=2
- [root@server ~]# netstat -ntp|grep 103
- tcp 1 7 1.1.1.101:8888 1.1.1.103:22222 CLOSE_WAIT 28978/python
- 这个时候,从wireshark上抓包也发现了client拒绝server的响应数据并发送ICMP[host administratively prohibited].
- 当server端TCP连接CLOSE_WAIT超时后, 受到net.netfilter.nf_conntrack_tcp_timeout_established参数的控制,nf_contrack表中ESTABLISHED[UNREPLIED] 条目是依然存在的。
- [root@server ~]# netstat -ntp|grep 103
- [root@server ~]# grep 103 /proc/net/nf_conntrack
- ipv4 2 tcp 6 431066 ESTABLISHED src=1.1.1.101 dst=1.1.1.103 sport=8888 dport=22222 [UNREPLIED] src=1.1.1.103 dst=1.1.1.101 sport=22222 dport=8888 mark=0 secmark=0 use=2
- 监听端口状态是正常的
- [root@server ~]# netstat -nplt|grep 8888
- tcp 0 0 0.0.0.0:8888 0.0.0.0:* LISTEN 28978/python
- 5. 这个时候,当client再以tcp 22222为源端口向tcp 8888发起连接,server端的iptables就拒绝了这个SYN报文. client端连接报错。
- [root@client ~]# python
- Python 2.6.6 (r266:84292, Sep 4 2013, 07:46:00)
- [GCC 4.4.7 20120313 (Red Hat 4.4.7-3)] on linux2
- Type "help", "copyright", "credits" or "license" for more information.
- >>> import socket
- >>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- >>> s.bind(("0.0.0.0",22222))
- >>> s.connect(("1.1.1.101",8888))
- Traceback (most recent call last):
- File "
", line 1, in - File "
", line 1, in connect - socket.error: [Errno 113] No route to host
- >>>
经过这个模拟,也验证了故障的成因,那么要解决问题,就简单了。
有两边可以想办法,一是appsrv1这边,如果让该条目早点过期,那么只要端口重用不是特别快的情况下,这个问题就不会发生。
在不改造应用的情况下,这是一个较好的临时解决方案,但是过期时间设多久,要先要满足前一个问题的SQL最长执行时间,然后观察端口重用的时间有没有短于SQL最长执行时间。
appsrv1这边存在条目的原因是返回数据被拒绝后的TCP重传数据包被iptables nf_conntrack记录,svcbus2又没有响应的TCP回应报文。
那么另外一个方法就是如果能让svcbus2正常响应就解决了。 怎么能正常解决呢?
iptables nf_contrack 还有另外一个参数 net.netfilter.nf_conntrack_tcp_timeout_close_wait。 默认是60秒跟TCP的CLOSE_WAIT 超时时间是一致的。通过试验模拟这个故障发现,如果把这个时间设长,超过TCP CLOSE_WAIT 超时时间,
那么在TCP连接关闭后,appsrv1的返回报文还可以到达svcbus2的内核, svcbus2会直接发送TCP RST包将这个连接重置。这样appsrv1上的TCP连接和nf_contrack中的条目都会清除掉。
看模拟的过程。
当 appsrv-test 在svcbus-test发送FIN连接后过了127秒开始发送响应数据,这时候svcbus-test就立刻回应了RST报文,后来svcbus-test半个小时候在重新再用tcp 22222端口向appsrv-test tcp 8888发起连接的时候,问题问题,连接可以正常建立了。
当然这种处理方法应用层会收到错误,要对这个错误进行处理才行。
由于第二种方法还涉及应用代码的调整和测试,因此通过观察发现SQL最长执行时间在15分钟左右,服务总线源端口重用时间大概在4个小时,但是由于重用源端口的时候,目标端口还不一定是appsrv上的对应端口,因此4小时不一定形成冲突。
综合考虑了一下,设置
net.netfilter.nf_conntrack_tcp_timeout_establishe=7200
是一个比较合适的解决方法。调整后,经过近期的观察,没有出现业务失败了。
经验:
系统参数调整要小心,特别是对应用行为不清楚的情况下,要多测试。该业务系统就是没有经过严格的测试,为了赶目标节点匆匆上线继而发生后续故障。
另外,在系统软件部署的时候,管理员使用的文档中没有及时更新,缺乏了对Oracle 11g一些容易引起问题的新特性参数进行调整的要求。当遇到应用
没有充分优化的情况下,由于这个新特性带来的性能加速恶化,也对相关故障产生了间接的影响。 因此及时更新文档,保证系统的参数基线合理显得也很重要。
最后,运维工作纷繁复杂,要静下心来仔细的看,才会发现其中的小细节。
标签: 疑难杂症 ICMP iptables Host Administratively Prohibited nf_conntrack
ICMP通讯管理性过滤禁止差错报文(type 3,code 13)
作者:易隐者 发布于:2012-9-20 20:10 Thursday 分类:网络分析
ICMP通讯管理性禁止差错报文的产生
ICMP通讯管理性禁止差错报文是由于中间设备或服务器对该报文的禁止访问策略而产生的,当一个报文经过某中间设备或达到服务器时,如果中间设备或服务器的管理策略禁止该报文的通过,那么,中间设备或服务器会生成一个目的地址为客户端的ICMP通讯管理性禁止报文,其产生过程如下图所示:
ICMP通讯管理性禁止差错报文产生过程
ICMP通讯管理性禁止差错报文的封装
ICMP通讯管理性禁止差错报文的封装格式如下图所示:
ICMP通讯管理性禁止差错报文的封装(wireshark)
ICMP通讯管理性禁止差错报文在实际网络分析中的作用
由ICMP通讯管理性禁止差错报文产生的机制决定了其可以帮助我们快速地发现数据报文被丢弃的位置和原因,从而大大提高了我们定位、解决问题的效率。
但是,ICMP通讯管理性禁止差错报文也是一把双刃剑,它也可以帮助黑客判断一些安全防护设备的策略和位置,正是基于这种考虑,有时一些设备不发送这种ICMP通讯管理性禁止差错报文。
标签: icmp差错 ICMP Type 3 Code 13 ICMP通讯管理性禁止差错
连接数相关知识
作者:易隐者 发布于:2012-9-19 19:58 Wednesday 分类:网络分析
连接数是网络中非常重要的一个概念,在我们学习工作的过程中会经常遇到。下面将针对连接数相关的一些知识点做一些描述。
“连接数”是什么
不同产品对“连接数”的理解有一些差别,但是主流认为网络中交互双方的五元组信息决定了一个连接。所谓五元组信息是指源地址、源端口、目的地址、目的端口以及协议类型。连接数就是网络连接的数目。基本上TCP/UDP应用根据五元组信息都可以很好的对应于一个连接,但是对于ICMP协议,不同的产品会有一些不同的处理,考虑到ICMP报文在实际工作环境下非常少,相对于TCP、UDP应用的连接数基本上可以忽略,因此不针对此做深入的描述。
并发连接数
并发连接数是指同时在连接表中的连接数目。端系统和中间系统在处理这些连接时都会设置一个连接超时时间,在超时时间溢出之前,系统会为这些连接分配相应的存储资源。而我们熟知的Syn flood DOS攻击正是利用这个特性来达到攻击效果的。一般而言,并发连接数是衡量一个中间系统性能的指标之一。
每秒新建连接数
每秒新建连接数是一般是指中间设备在单位时间内(1秒内)所能建立连接的数量,这个参数的大小直接影响中间系统在单位时间内所能建立的最大连接数量,其也是衡量中间系统性能的一个重要指标。
连接数限制
连接数限制主要是指端系统或中间系统基于安全(防攻击)、管理(流量控制)等方面的需要而对某些IP的网络连接数量限制在某一范围内的策略。如windows系统中的连接数限制,防火墙路由器等中间系统上的“连接数限制”功能等。
端系统中的主机防火墙(如linux下的iptables)、操作系统本身、应用程序(Apche、IIS、数据库等)等都可能针对连接数进行限制,而现在常见的中间设备(防火墙、路由器等)基本上都支持连接数限制的功能,大家可以根据实际环境中的设备自行查阅相关手册的连接数有关功能的设置。
我们随便找个路由器上连接数限制功能设置的截图看看:
我们再来看看IIS连接数限制功能设置的截图:
连接数限制对网络的影响
连接数限制策略实施之后,当被限制连接数的IP超出限制的范围,其后续的网络连接将会被端系统或中间系统过滤丢弃,这将导致这些IP在进行网络交互时速度变慢、丢包等情况发生。因此,连接数限制是管理策略性导致网络交互异常的原因之一。
另外值得注意的是,在实际环境下,虽然端系统或中间系统可能会由于连接数限制功能丢弃部分报文,但是并不是所有设备在丢弃这些报文之后会向源主机发送ICMP差错通告报文,这给我们分析定位带来了一些难度。
标签: TCP 五元组 ICMP 连接数 连接数限制 并发连接数 每秒新建连接数
TCP MSS与PMTUD
作者:易隐者 发布于:2012-9-6 19:16 Thursday 分类:网络分析
一旦DF位置一,将不允许中间设备对该报文进行分片,那么在遇到IP报文长度超过中间设备转发接口的MTU值时,该IP报文将会被中间设备丢弃。在丢弃之后,中间设备会向发送方发送ICMP差错报文。
为了简单直观的展示这个交互的过程,我做了下面这个图示:
我找了一个实际环境下捕获的ICMP需要分片但DF位置一的差错报文,下图为其解码格式:
我们可以看到其差错类型为3,代码为4,并且告知了下一跳的MTU值为1478。在ICMP差错报文里封装导致此差错的原始IP报文的报头(包含IP报头和四层报头)。
一旦出现这种因DF位置一而引起丢包,如果客户端无法正常处理的话,将会导致业务应用出现异常,外在表现为页面无法打开、页面打开不全、某些大文件无法传输等等,这将严重影响业务的正常运行。
那么客户端如何处理这种状况呢?
TCP主要通过两种方式来应对:
1, 协商MSS,在交互之前避免分片的产生
2, 路径MTU发现(PMTUD)
TCP MSS
TCP在三次握手建立连接过程中,会在SYN报文中使用MSS(Maximum Segment Size)选项功能,协商交互双方能够接收的最大段长MSS值。
MSS是传输层TCP协议范畴内的概念,顾名思义,其标识TCP能够承载的最大的应用数据段长度,因此,MSS=MTU-20字节TCP报头-20字节IP报头,那么在以太网环境下,MSS值一般就是1500-20-20=1460字节。
客户端与服务器端分别根据自己发包接口的MTU值计算出相应MSS值,并通过SYN报文告知对方,我们还是通过一个实际环境中捕获的数据报文来看一下MSS协商的过程:
这是整个报文交互过程的截图,我们再来看一下客户端的报文详细解码:
上图为客户端的SYN报文,在其TCP选项字段,我们可以看到其通告的MSS值为1460;我们在看看服务器端的SYN/ACK报文解码:
上图为服务器端给客户端回应的SYN/ACK报文,查看其TCP选项字段,我们可以发现其通告的MSS值为1440。
交互双方会以双方通告的MSS值中取最小值作为发送报文的最大段长。在此TCP连接后续的交互过程中,我们可以清楚的看到服务器端向客户端发送的报文中,TCP的最大段长度都是1440字节,如下图解码所示:
通过在TCP连接之初,协商MSS值巧妙的解决了避免端系统分片的问题,但是在复杂的实际网络环境下,影响到IP报文分片的并不仅仅是发送方和接收方,还有路由器、防火墙等中间系统,假设在下图的网络环境下:
中间路径上的MTU问题,端系统并不知道,因此需要一个告知的机制,这个机制就是路径MTU发现(PMTUD: Path MTU Discovery )!
PMTUD
说起PMTUD,我们必须在此回到上面讲到的ICMP需要分片但DF位置一差错报文,还记得那个ICMP差错报文中有一个字段是告知下一跳的MTU值的吗?PMTUD正是利用ICMP需要分片但DF位置一差错报文的这一特性来实现的。
发送方在接收到该差错报文后,会根据该报文给出的下一跳的MTU值计算适合传输的最大段长度,从而在后续的发送报文过程中,避免在中间路径被分片的情况产生。
这在端系统主要是通过在路由表里临时添加目的主机路由并将ICMP差错报文告知的下一跳MTU值跟该主机路由关联起来来实现。
PMTUD的确是个非常不错的机制,但是在复杂的实际网络环境中,有时候会失效,因为为了安全起见,有些网络管理员会在路由器、防火墙等中间设备上设置过滤ICMP报文的安全策略,这将导致ICMP差错报文被这些中间设备丢弃,无法达到发送方,从而引起PMTUD的失效,网上有个宫一鸣前辈共享的案例——《错误的网络访问控制策略导致PMTUD 实现故障一例》,该案例正是说明这种情况绝好的例子,大家可以自行百度此文档学习参考。
值得一提的是PMTUD仅TCP支持,UDP并不支持PMTUD。
由于PMTUD可能存在ICMP差错报文被过滤的情况,很多中间设备的接口支持adjust tcp mss设置功能,思科路由器一般是在接口模式下使用命令“ip tcp adjust-mss 1400 ”来做设置,其他的品牌产品的相关设置大家可在实际工作环境下自查相关品牌和产品的使用手册。
这个功能主要是通过由中间设备修改经过其转发的TCP SYN报文中的MSS值,让中间设备参与进TCP 三次握手时SYN报文的MSS协商来避免分片。
需要注意的是,该功能不像MTU值,只针对出接口,此功能一旦开启,其将针对该接口的收发双向有效。
我做一个简化环境下的工作过程图示以便于大家理解其工作过程:
标签: TCP icmp差错 分片 SYN TCP选项 UDP MTU ICMP PMTUD MSS
IP分片(IP Fragment)
作者:易隐者 发布于:2012-9-3 22:22 Monday 分类:网络分析
为什么要分片
不同的链路类型能够支持的最大传输单元值(MTU: Maxitum Transmission Unit)主要是由相关RFC文档规定的,常见的以太网链路的MTU值为1500,如果需要转发的IP报文超出其转发接口的MTU值,则在转发该报文之前,需要将其分片,分为多个适合于该链路类型传输的报文,这些分片报文在到达接收方的时候,由接收方完成重组。
各种常见链路类型的MTU值如下图所示:
报文的分片和重组
我们先来看一下分片的过程,为了简单起见,我就用《TCPIP详解卷一》第11章《UDP:用户数据报协议》中关于IP分片的案例,应用进程将1473字节应用字段交给UDP处理,UDP加上8字节的UDP报头之后,交给IP层处理,IP层在转发之前,发现该报文长度超出转发接口的MTU,因此需要分片,分为两个IP分组,如下图所示:
从上图可以看出原始的IP报文经过分片后,只有第一个分片报文是带有四层信息的,后续报文均不带四层信息,为做直观展示,我找了一个实际环境下抓取的分片报文,如下图所示:
这是分片的第一个报文,我们可以看到该报文IP层封装的上层协议为ICMP协议,这是一个ping报文(上层协议信息),我们再来看一下后续分片报文的解码:
这是分片后续报文,我们能看到封装的是ICMP协议,但是封装的上层协议的具体信息就无法看到了。
IP数据报被分片之后,所有分片报文的IP报头中的源IP、目的IP、IP标识、上层协议等信息都是一样的(TTL不一定是一样的,因为不同的分片报文可能会经过不同的路由路径达到目的端),不同的地方在于分片标志位和分片偏移量,而接收方正是根据接收到的分片报文的源IP、目的IP、 IP标识、分片标志位、分片偏移量来对接收到的分片报文进行重组。
接收方根据报文的源IP、目的IP、IP标识将接收到的分片报文归为不同原始IP数据报的分片分组;分片标志中的MF位(More Fragment)标识了是否是最后一个分片报文,如果是最后一个分片报文,则根据分片偏移量计算出各个分片报文在原始IP数据报中的位置,重组为分片前的原始IP报文。如果不是最后一个分片报文,则等待最后一个分片报文达到后完成重组。
分片带来的问题
1, 分片带来的性能消耗
分片和重组会消耗发送方、接收方一定的CPU等资源,如果存在大量的分片报文的话,可能会造成较为严重的资源消耗;
分片对接收方内存资源的消耗较多,因为接收方要为接收到的每个分片报文分配内存空间,以便于最后一个分片报文到达后完成重组。
2,分片丢包导致的重传问题
如果某个分片报文在网络传输过程中丢失,那么接收方将无法完成重组,如果应用进程要求重传的话,发送方必须重传所有分片报文而不是仅重传被丢弃的那个分片报文,这种效率低下的重传行为会给端系统和网络资源带来额外的消耗。
3, 分片攻击
黑客构造的分片报文,但是不向接收方发送最后一个分片报文,导致接收方要为所有的分片报文分配内存空间,可由于最后一个分片报文永远不会达到,接收方的内存得不到及时的释放(接收方会启动一个分片重组的定时器,在一定时间内如果无法完成重组,将向发送方发送ICMP重组超时差错报文,请大家参考本博客《ICMP重组超时》一文),只要这种攻击的分片报文发送的足够多、足够快,很容易占满接收方内存,让接收方无内存资源处理正常的业务,从而达到DOS的攻击效果。
4, 安全隐患
由于分片只有第一个分片报文具有四层信息而其他分片没有,这给路由器、防火墙等中间设备在做访问控制策略匹配的时候带来了麻烦。
如果路由器、防火墙等中间设备不对分片报文进行安全策略的匹配检测而直接放行IP分片报文,则有可能给接收方带来安全隐患和威胁,因为黑客可以利用这个特性,绕过路由器、防火墙的安全策略检查对接收方实施攻击;
如果路由器、防火墙等中间设备对这些分片报文进行重组后在匹配其安全策略,那么又会对这些中间设备的资源带来极大的消耗,特别是在遇到分片攻击的时候,这些中间设备会在第一时间内消耗完其所有内存资源,从而导致全网中断的严重后果。
基于以上原因,很多应用程序都尽量避免分片的产生,其通过将IP报文的分片标志中的DF位(Don’t Fragment)置一来实现,而这可能给应用带来一些难以预料的麻烦。下一篇我将介绍端系统如何处理这种状况,请大家关注。
分片补充
1,分片既有可能发生在端系统(发送主机)上,也可能发生在转发报文的路由器、防火墙等中间系统上。
2,分片只发生在转发出接口上。
跟分片有关的案例
后续我会在本博客里添加一些跟分片有关的案例,有兴趣的同学可关注。
标签: ip分片 重组超时 IP标识 icmp差错 分片 ip fragment IPID UDP 分片攻击 分片偏移量 DF位 MF位 MTU 重组 fragment ICMP
日历
最新日志
链接
分类
最新碎语
- 如果一个人想要做一件真正忠于自己内心的事情,那么往往只能一个人独自去做"——理查德·耶茨
2019-06-25 21:34
- 日后我们知道,真正的人生道路是由内心决定的。不论我们的道路看上去如此曲折、如此荒谬地背离我们的愿望,它终归还是把我们引到我们看不见的目的地。(茨威格《昨日世界》)
2019-03-16 21:27
- 如果你渴望得到某样东西,你得让它自由,如果它回到你身边,它就是属于你的,如果它不会回来,你就从未拥有过它。——大仲马《基督山伯爵》
2018-10-09 22:07
- 人生有两大悲剧:一个是没有得到你心爱的东西;另一个是得到了你心爱的东西。人生有两大快乐:一个是没有得到你心爱的东西,于是可以寻求和创造;另一个是得到了你心爱的东西,于是可以去品味和体验。——弗洛伊德
2018-09-25 18:06
- 一个人越有思想,发现有个性的人就越多。普通人是看不出人与人之间的差别的——布莱兹·帕斯卡尔
2018-08-30 18:44
存档
- 2020年11月(2)
- 2018年1月(1)
- 2017年12月(1)
- 2017年11月(6)
- 2017年6月(1)
- 2017年5月(1)
- 2017年4月(1)
- 2017年3月(1)
- 2016年11月(1)
- 2016年4月(1)
- 2015年7月(2)
- 2015年6月(1)
- 2015年5月(5)
- 2014年12月(1)
- 2014年11月(1)
- 2014年10月(1)
- 2014年8月(1)
- 2014年7月(1)
- 2014年6月(1)
- 2014年5月(1)
- 2014年4月(3)
- 2014年2月(2)
- 2014年1月(2)
- 2013年12月(1)
- 2013年11月(1)
- 2013年10月(2)
- 2013年9月(1)
- 2013年8月(1)
- 2013年7月(3)
- 2013年6月(2)
- 2013年5月(1)
- 2013年4月(3)
- 2013年3月(1)
- 2013年2月(2)
- 2013年1月(2)
- 2012年12月(11)
- 2012年11月(12)
- 2012年10月(12)
- 2012年9月(26)
- 2012年8月(29)
- 2012年7月(18)
- 2012年6月(2)
- 2012年5月(25)
- 2012年4月(16)
- 2012年3月(13)
- 2012年2月(6)