当前位置: 首页 > news >正文

网上效果代码网站可以下载吗网站空间是服务器吗

网上效果代码网站可以下载吗,网站空间是服务器吗,做html的简单网站,南京做网站seo的本文介绍一个因为conntrack内核参数设置和iptables规则设置的原因导致TCP连接不能正常关闭(socket一直处于FIN_WAIT_1状态)的案例#xff0c;并介绍conntrack相关代码在conntrack表项超时后对新报文的处理逻辑。 案例现象 问题的现象#xff1a; ECS上有一个进程#xff0…本文介绍一个因为conntrack内核参数设置和iptables规则设置的原因导致TCP连接不能正常关闭(socket一直处于FIN_WAIT_1状态)的案例并介绍conntrack相关代码在conntrack表项超时后对新报文的处理逻辑。 案例现象 问题的现象 ECS上有一个进程建立了到另一个服务器的socket连接。 kill掉进程发现tcpdump抓不到FIN包发出导致服务器端的连接没有正常关闭。 为什么有这种现象呢 梳理 正常情况下kill进程后用户态调用close()系统调用来发起TCP FIN给对端所以这肯定是个异常现象。关键的信息是 用户态kill进程。ECS网卡层面没有抓到FIN包。 从这个现象描述中可以推断问题出在位于用户空间和网卡驱动中间的内核态中。但是是系统调用问题还是FIN已经构造后出的问题还不确定。这时候比较简单有效的判断的方法是看socket的状态。socket处于TIME_WAIT_1状态这个信息很有用可以判断系统调用是正常的因为按照TCP状态机FIN发出来后socket会进入TIME_WAIT_1状态在收到对端ACK后进入TIME_WAIT_2状态。关于socket的另一个信息是这个socket长时间处于TIME_WAIT_1状态这也反向证明了在网卡上没有抓到FIN包的陈述是合理。FIN包没出虚机网卡对端收不到FIN所以自然没有机会回ACK。 真凶 问题梳理到了这里基本上可以进一步聚焦了在没有大bug的情况下需要重点看下iptables(netfilter), tc等机制对报文的影响。果然在ECS中有许多iptables规则。利用iptables -nvL可以打出每条rule匹配到的计数或者利用写log的办法示例如下 # 记录下new state的报文的日志 iptables -A INPUT -p tcp -m state --state NEW -j LOG --log-prefix [iptables] INPUT NEW: 在这个案例中通过计数和近一步的log发现了是OUTPUT chain的最后一跳DROP规则被匹配上了如下 # iptables -A OUTPUT -m state --state INVALID -j DROP 问题的真凶在此时被找到了iptables规则丢弃了kill进程后发出的FIN包导致对端收不到连接无法正常关闭。 到了这里离最终的root cause还有两个疑问 问题是否在全局必现触发的条件是什么为什么FIN包被认为是INVALID状态 何时触发 先来看第一个问题问题是否在全局必现触发的条件是什么 对于ECS上与服务器建立TCP连接的进程问题实际上不是每次必现的。建议用netcat来做测试验证下是否是全局影响。通过测试有如下发现 利用netcat做类似的操作也能复现同样的问题说明这个确实是全局影响与特定进程或者连接无关。连接时间比较长时能复现时间比较短时kill进程时能正常发FIN。 看下conntrack相关的内核参数设置发现ECS环境的conntrack参数中有一个显著的调整 net.netfilter.nf_conntrack_tcp_timeout_established 120 这个值默认值是5天阿里云官网文档推荐的调优值是1200秒而现在这个ECS环境中的设置是120秒是一个非常短的值。 看到这里可以认定是经过nf_conntrack_tcp_timeout_established 120秒后conntrack中的连接跟踪记录已经被删除此时对这个连接发起主动的FIN在netfilter中回被判定成INVALID状态。而客户在iptables filter表的OUTPUT chain中对INVALID连接状态的报文采取的是drop行为最终导致FIN报文在netfilter filter表OUTPUT chain中被丢弃。 FIN包被认为是INVALID状态 对于一个TCP连接在conntrack中没有连接跟踪表项一端FIN掉连接的时候的时候被认为是INVALID状态是很符合逻辑的事情。但是没有发现任何文档清楚地描述这个场景当用户空间TCP socket仍然存在但是conntrack表项已经不存在时对一个“新”的报文conntrack模块认为它是什么状态。 所有文档描述conntrack的NEW, ESTABLISHED, RELATED, INVALID状态时大同小异比较详细的描述如文档 The NEW state tells us that the packet is the first packet that we see. This means that the first packet that the conntrack module sees, within a specific connection, will be matched. For example, if we see a SYN packet and it is the first packet in a connection that we see, it will match. However, the packet may as well not be a SYN packet and still be considered NEW. This may lead to certain problems in some instances, but it may also be extremely helpful when we need to pick up lost connections from other firewalls, or when a connection has already timed out, but in reality is not closed. 如上对于NEW状态的描述为conntrack module看见的一个报文就是NEW状态例如TCP的SYN报文有时候非SYN也被认为是NEW状态。 在本案例的场景里conntrack表项已经过期了此时不管从用户态发什么报文到conntrack模块时都算是conntrack模块看见的第一个报文那么conntrack都认为是NEW状态吗比如SYN, SYNACK, FIN, RST这些明显有不同的语义实践经验FIN, RST这些直接放成INVALID是没毛病的到这里还是来复现下并看看代码的逻辑吧。 测试 iptables规则设置 用如下脚本来设置下iptables规则 #!/bin/sh iptables -P INPUT ACCEPT iptables -F iptables -X iptables -Z # 在日志里记录INPUT chain里过来的每个报文的状态 iptables -A INPUT -p tcp -m state --state NEW -j LOG --log-prefix [iptables] INPUT NEW: iptables -A INPUT -p TCP -m state --state ESTABLISHED -j LOG --log-prefix [iptables] INPUT ESTABLISHED: iptables -A INPUT -p TCP -m state --state RELATED -j LOG --log-prefix [iptables] INPUT RELATED: iptables -A INPUT -p TCP -m state --state INVALID -j LOG --log-prefix [iptables] INPUT INVALID: iptables -A INPUT -i lo -j ACCEPT iptables -A INPUT -p tcp --dport 22 -j ACCEPT iptables -A INPUT -p tcp --dport 21 -j ACCEPT iptables -A INPUT -p tcp --dport 80 -j ACCEPT iptables -A INPUT -p tcp --dport 443 -j ACCEPT iptables -A INPUT -p tcp --dport 8088 -m state --state NEW -j ACCEPT iptables -A INPUT -p icmp --icmp-type 8 -j ACCEPT iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT # 在日志里记录OUTPUT chain里过来的每个报文的状态 iptables -A OUTPUT -p tcp -m state --state NEW -j LOG --log-prefix [iptables] OUTPUT NEW: iptables -A OUTPUT -p TCP -m state --state ESTABLISHED -j LOG --log-prefix [iptables] OUTPUT ESTABLISHED: iptables -A OUTPUT -p TCP -m state --state RELATED -j LOG --log-prefix [iptables] OUTPUT RELATED: iptables -A OUTPUT -p TCP -m state --state INVALID -j LOG --log-prefix [iptables] OUTPUT INVALID: # iptables -A OUTPUT -m state --state INVALID -j DROP iptables -P INPUT DROP iptables -P OUTPUT ACCEPT iptables -P FORWARD DROP service iptables save systemctl restart iptables.service 利用iptables -nvL看规则如下 注测试时并没有显示地drop掉OUTPUT chain的INVALID状态的报文也能复现类似的问题因为在INPUT方向对端回的FIN同样也是INVALID状态的报文会被INPUT chain默认的DROP规则丢弃掉。 将conntrack tcp timeout设置得短点sysctl -w net.netfilter.nf_conntrack_tcp_timeout_established20 利用nc测试第一次建立连接完idle 20秒conntrack中ESTABLISHED的表项消失 (可以利用iptstate或者conntrack tool查看) 直接kill进程发FIN, 对于conntrack的状态是INVALID。 接续发数据对于conntrack的状态是NEW。 代码逻辑 nf_conntrack模块的报文可以从nf_conntrack_in函数看起对于conntrack表项中不存在的新表项的逻辑 nf_conntrack_in net/netfilter/nf_conntrack_core.c|-- resolve_normal_ct net/netfilter/nf_conntrack_core.c // 利用__nf_conntrack_find_get查找对应的连接跟踪表项没找到则init新的conntrack表项|-- init_conntrack net/netfilter/nf_conntrack_core.c // 初始化conntrack表项|-- tcp_new net/netfilter/nf_conntrack_proto_tcp.c // 到TCP协议的处理逻辑called when a new connection for this protocol found。在这里根据tcp_conntracks数组决定状态。 reslove_normal_ct 在reslove_normal_ct中, 逻辑是先找利用__nf_conntrack_find_get查找对应的连接跟踪表项。在本文的场景中conntrack表项已经超时所以不存在。代码逻辑进入init_conntrack来初始化一个表项。 /* look for tuple match */hash hash_conntrack_raw(tuple, zone);h __nf_conntrack_find_get(net, zone, tuple, hash);if (!h) {h init_conntrack(net, tmpl, tuple, l3proto, l4proto,skb, dataoff, hash);if (!h)return NULL;if (IS_ERR(h))return (void *)h;} init_conntrack 在init_conntrack的如下逻辑里会利用nf_conntrack_l4proto的new来读取和校验一个对于conntrack模块是新连接的报文内容。如果返回值是false则进入如下if statement来结束这个初始化conntrack表项的过程。在案例的场景确实会在这里就结束conntrack表项的初始化。 对于这个“新”的TCP报文的验证也就是我们关心的对于一个conntrack表项不存在(超时)的TCP连接会在new(tcp_new)的逻辑中判断。 if (!l4proto-new(ct, skb, dataoff, timeouts)) {nf_conntrack_free(ct);pr_debug(init conntrack: cant track with proto module\n);return NULL;} tcp_new 在tcp_new的如下逻辑中关键的逻辑是对new_state的赋值当new_state TCP_CONNTRACK_MAX时会返回false退出。对于FIN包new_state的赋值会是TCP_CONNTRACK_MAX (sIV)具体逻辑看如下分析。 /* Called when a new connection for this protocol found. */ static bool tcp_new(struct nf_conn *ct, const struct sk_buff *skb,unsigned int dataoff, unsigned int *timeouts) {enum tcp_conntrack new_state;const struct tcphdr *th;struct tcphdr _tcph;struct net *net nf_ct_net(ct);struct nf_tcp_net *tn tcp_pernet(net);const struct ip_ct_tcp_state *sender ct-proto.tcp.seen[0];const struct ip_ct_tcp_state *receiver ct-proto.tcp.seen[1];th skb_header_pointer(skb, dataoff, sizeof(_tcph), _tcph);BUG_ON(th NULL);/* Dont need lock here: this conntrack not in circulation yet */// 这里get_conntrack_index拿到的是TCP_FIN_SET是枚举类型tcp_bit_set的值new_state tcp_conntracks[0][get_conntrack_index(th)][TCP_CONNTRACK_NONE];/* Invalid: delete conntrack */if (new_state TCP_CONNTRACK_MAX) {pr_debug(nf_ct_tcp: invalid new deleting.\n);return false;} ...... } tcp_conntracks是一个三维数组作为TCP状态转换表(TCP state transition table)存在。 tcp_conntrack数组最外层的下标是0表示ORIGINAL是发出包的一端。在案例的场景中中间层的外标由get_conntrack_index决定。get_conntrack_index(th)根据报文中的FIN flag拿到枚举类型tcp_bit_set (定义如下)的值TCP_FIN_SET。枚举类型tcp_bit_set和下面将要介绍的tcp_conntracks数组的中间下标一一对应。 /* What TCP flags are set from RST/SYN/FIN/ACK. */ enum tcp_bit_set { TCP_SYN_SET, TCP_SYNACK_SET, TCP_FIN_SET, TCP_ACK_SET, TCP_RST_SET, TCP_NON 里层的下标为TCP为TCP_CONNTRACK_NONE是枚举类型tcp_conntrack中的0。 tcp_conntracks数组 数组的内容如下在源码里有非常多的注释说明状态的转换这里先略去具体可参考数组定义。这里只关注在conntrack表项超时后收到第一个报文时对报文状态的定义。 static const u8 tcp_conntracks[2][6][TCP_CONNTRACK_MAX] {{ /* ORIGINAL */ /*syn*/ { sSS, sSS, sIG, sIG, sIG, sIG, sIG, sSS, sSS, sS2 }, /*synack*/ { sIV, sIV, sSR, sIV, sIV, sIV, sIV, sIV, sIV, sSR }, /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, /*ack*/ { sES, sIV, sES, sES, sCW, sCW, sTW, sTW, sCL, sIV }, /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }},{ /* REPLY */ /*syn*/ { sIV, sS2, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sS2 }, /*synack*/ { sIV, sSR, sIG, sIG, sIG, sIG, sIG, sIG, sIG, sSR }, /*fin*/ { sIV, sIV, sFW, sFW, sLA, sLA, sLA, sTW, sCL, sIV }, /*ack*/ { sIV, sIG, sSR, sES, sCW, sCW, sTW, sTW, sCL, sIG }, /*rst*/ { sIV, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL, sCL }, /*none*/ { sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV, sIV }} }; 根据上面的分析对conntrack模块的新报文来说取值如下 tcp_conntracks[0][get_conntrack_index(th)][TCP_CONNTRACK_NONE] tcp_conntracks[0][get_conntrack_index(th)][0] 当报文带有FIN时tcp_conntracks0[0] tcp_conntracks0[0] INVALID状态 // 本案例当报文带有RESET时tcp_conntracks0[0] tcp_conntracks0[0] INVALID状态当报文带有SYNACK时tcp_conntracks0[0] tcp_conntracks0[0] INVALID状态当报文带有SYN和ACK时, 对于conntrack模块是NEW状态 总结 当操作系统使用iptables时(或者在其他场景中使用netfilter提供的hook点)大部分关于nf_conntrack_tcp_timeout_established的优化都是建议把默认的5天调小以避免conntrack表满的情况这个是推荐的最佳实践。但是从另一个角度到底设置到多小比较好除非你能明确地知道你的iptables规则对每一个报文的过滤行为否则不建议设置到几百秒及以下级别。 当把nf_conntrack_tcp_timeout_established设置得很短时对于超时的conntrack表项关闭连接时的FIN或者RST(linger enable)很容易被iptables规则丢弃在本文案例中iptables的filter表规则中的每个chain都显示地丢弃了INVALID状态报文即使不显示丢弃通常设置规则的时候INPUT chain的默认规则也不会允许INVALID状态的包进入采取丢弃行为。最终的影响就是让用户态的socket停在诸如FIN_WAIT_1和LAST_ACK等不太常见的状态造成TCP连接不能正常关闭。 原文链接 本文为云栖社区原创内容未经允许不得转载。
http://www.zqtcl.cn/news/428741/

相关文章:

  • 石家庄做网站价格seo优化效果
  • 为什么浏览器打开是2345网址导航seo免费资源大全
  • 网站工程是干啥的动态个人网页制作html教程
  • 阿里云多网站建设wordpress 统计分析
  • 长沙网站定制公司科技特长生
  • 查公司的口碑和评价的网站中学生怎么做网站
  • 做网站买空间多少钱深圳seo优化公司
  • 中国建设银行北京市互联网网站wordpress商城购物表单
  • 万网网站备案管理查询工程建设项目的网站
  • 网站建设国内外研究现状模板ppt设计大赛
  • 专业网站优化方案网站设计过程怎么写
  • 福州定制网站建设网站ip过万
  • wordpress网站评论插件厦门软件网站建设
  • 网站黄金比例wordpress转typecho
  • 重庆有哪些网络公司百度系优化
  • 无锡网站制作方案企业三合一建站公司怎么找
  • 钉钉crm客户管理系统免费seo网站推荐一下软件
  • wordpress公司网站模版怎么显示wordpress里元素的源代码
  • 泉州网站制作运营商专业wordpress评论软件
  • 网站开发是什么意思啊有没有帮人做简历的网站
  • 企业网站模板包含什么维度 网站建设
  • 个人备案做运营网站宁波建网站模板
  • 做网站需要懂什么软件合肥网站制作套餐
  • 中国建设银行官方网站纪念钞预约网上买手表哪个网站可以买到正品
  • 哪个网站做兼职可以赚钱浙江嘉兴最新事件
  • 苍南网站建设深圳百度关键字优化
  • 网站建设流程及规范是做网站设计好还是杂志美编好
  • 网站模板 登陆南昌做网站开发的公司有哪些
  • 移动网站建设是什么商丘哪里教做网站的
  • 网站建设排名的公司江东seo做关键词优化