• linux系统telnet端口不通能收到SYN但不回SYN+ACK响应问题排查(转载)


    linux系统telnet端口不通能收到SYN但不回SYN+ACK响应问题排查


    一:背景:
    一台机器从公司办公网登录不上且所有tcp端口都telnet不通,但是通过同机房同的其它机器却可以正常访问到出问题的机器。于是就立即在这台出问题的server端抓包分析,发现问题如下:
    server端收到了本地pc发的SYN包,但是没有回syn+ack包,所以确认是server端系统问题。tcpdump抓包如下:


    client端抓包:
    有发送,服务端回的都是R 重置
    [root@localhost ~]# tcpdump -vv host 1.1.1.1
    tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
    14:56:47.156700 IP (tos 0x10, ttl 64, id 58127, offset 0, flags [DF], proto TCP (6), length 60)
    10.10.18.161.59860 > 1.1.1.1.ftp: Flags [S], cksum 0xda7b (correct), seq 2448459144, win 14600, options [mss 1460,sackOK,TS val 4000933511 ecr 0,nop,wscale 7], length 0
    14:56:48.156592 IP (tos 0x10, ttl 64, id 58128, offset 0, flags [DF], proto TCP (6), length 60)
    10.10.18.161.59860 > 1.1.1.1.ftp: Flags [S], cksum 0xd693 (correct), seq 2448459144, win 14600, options [mss 1460,sackOK,TS val 4000934511 ecr 0,nop,wscale 7], length 0
    14:56:53.881707 IP (tos 0x0, ttl 252, id 63006, offset 0, flags [DF], proto TCP (6), length 40)
    1.1.1.1.ftp > 10.10.18.161.59860: Flags [R.], cksum 0xd054 (correct), seq 0, ack 2448459145, win 0, length 0


    14:58:57.481680 IP (tos 0x10, ttl 64, id 25165, offset 0, flags [DF], proto TCP (6), length 60)
    10.10.18.161.56634 > 1.1.1.1.rsync: Flags [S], cksum 0x8df0 (correct), seq 1851916753, win 14600, options [mss 1460,sackOK,TS val 4001063836 ecr 0,nop,wscale 7], length 0
    14:58:58.481605 IP (tos 0x10, ttl 64, id 25166, offset 0, flags [DF], proto TCP (6), length 60)
    10.10.18.161.56634 > 1.1.1.1.rsync: Flags [S], cksum 0x8a08 (correct), seq 1851916753, win 14600, options [mss 1460,sackOK,TS val 4001064836 ecr 0,nop,wscale 7], length 0
    14:59:08.587051 IP (tos 0x0, ttl 252, id 14708, offset 0, flags [DF], proto TCP (6), length 40)
    1.1.1.1.rsync > 10.10.18.161.56634: Flags [R.], cksum 0x80e0 (correct), seq 0, ack 1851916754, win 0, length 0


    server端抓包
    只能收到类似下面的发过来的包,没有响应包
    # tcpdump -n -vv -i eth0 tcp port 21
    00:04:43.585345 IP (tos 0x14, ttl 47, id 50536, offset 0, flags [DF], proto TCP (6), length 52)
    121.15.134.170.32581 > 172.18.54.135.ftp: Flags [F.], cksum 0x341d (correct), seq 1, ack 77, win 58, options [nop,nop,TS val 4071735193 ecr 877988392], length 0
    00:04:43.585457 IP (tos 0x0, ttl 64, id 17336, offset 0, flags [DF], proto TCP (6), length 52)
    172.18.54.135.ftp > 121.15.134.170.32581: Flags [.], cksum 0xe279 (incorrect -> 0xd9f8), seq 77, ack 2, win 57, options [nop,nop,TS val 878011469 ecr 4071735193], length 0
    00:04:43.585489 IP (tos 0x0, ttl 64, id 17337, offset 0, flags [DF], proto TCP (6), length 52)
    172.18.54.135.ftp > 121.15.134.170.32581: Flags [F.], cksum 0xe279 (incorrect -> 0xd9f7), seq 77, ack 2, win 57, options [nop,nop,TS val 878011469 ecr 4071735193], length 0
    00:04:43.591892 IP (tos 0x14, ttl 47, id 12870, offset 0, flags [DF], proto TCP (6), length 52)
    121.15.134.170.32581 > 172.18.54.135.ftp: Flags [.], cksum 0xd9f0 (correct), seq 2, ack 78, win 58, options [nop,nop,TS val 4071735199 ecr 878011469], length 0


    二,排查

    1,发现系统没有任何负载

    2,网卡也没有丢包

    3,iptables策略也都没问题

    4,系统的SYN_RECV连接很少,也没超限

    5,系统的文件描述符等资源也都没问题

    6,messages和dmesg中没有任何提示或者错误信息

    7,通过netstat命令查看系统上协议统计信息,发现很多请求由于时间戳的问题被rejected

    # netstat -s |grep reject
    2092 passive connections rejected because of time stamp
    1506 packets rejects in established connections because of timestamp


    三,通过google来协助

    发现有同样的人遇见这个问题:

    是通过调整sysctl -w net.ipv4.tcp_timestamps=0或者sysctl -w net.ipv4.tcp_tw_recycle=0来解决这个问题,于是我就顺藤摸瓜继续查。


    而在查询这两个参数的过程中,发现问题原因如下:

    发现是 Linux tcp_tw_recycle/tcp_timestamps设置导致的问题。 因为在linux kernel源码中发现tcp_tw_recycle/tcp_timestamps都开启的条件下,60s内同一源ip主机的socket connect请求中的timestamp必须是递增的。经过测试,我这边centos6系统(kernel 2.6.32)和centos7系统(kernel 3.10.0)都有这问题。

    源码函数:kernel 2.6.32 tcp_v4_conn_request(),该函数是tcp层三次握手syn包的处理函数(服务端);
    源码片段:
    if (tmp_opt.saw_tstamp &&
    tcp_death_row.sysctl_tw_recycle &&
    (dst = inet_csk_route_req(sk, req)) != NULL &&
    (peer = rt_get_peer((struct rtable *)dst)) != NULL &&
    peer->v4daddr == saddr) {
    if (get_seconds() < peer->tcp_ts_stamp + TCP_PAWS_MSL &&
    (s32)(peer->tcp_ts - req->ts_recent) >
    TCP_PAWS_WINDOW) {
    NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_PAWSPASSIVEREJECTED);
    goto drop_and_release;
    }
    }

    tmp_opt.saw_tstamp:该socket支持tcp_timestamp
    sysctl_tw_recycle:本机系统开启tcp_tw_recycle选项
    TCP_PAWS_MSL:60s,该条件判断表示该源ip的上次tcp通讯发生在60s内
    TCP_PAWS_WINDOW:1,该条件判断表示该源ip的上次tcp通讯的timestamp 大于 本次tcp


    总结:

    我这边和其它同事通过公司出口(NAT网关只有1个ip地址)访问问题server,由于timestamp时间为系统启动到当前的时间,故我和其它同事的timestamp肯定不相同;根据上述SYN包处理源码,在tcp_tw_recycle和tcp_timestamps同时开启的条件下,timestamp大的主机访问serverN成功,而timestmap小的主机访问失败。并且,我在办公网找了两台机器可100%重现这个问题。


    解决:

    # echo "0" > /proc/sys/net/ipv4/tcp_tw_recycle


    四,扩展

    1,net.ipv4.tcp_timestamps

    tcp_timestamps的本质是记录数据包的发送时间。基本的步骤如下:

    发送方在发送数据时,将一个timestamp(表示发送时间)放在包里面

    接收方在收到数据包后,在对应的ACK包中将收到的timestamp返回给发送方(echo back)

    发送发收到ACK包后,用当前时刻now - ACK包中的timestamp就能得到准确的RTT


    当然实际运用中要考虑到RTT的波动,因此有了后续的(Round-Trip Time Measurement)RTTM机制。

    TCP Timestamps Option (TSopt)具体设计如下

    Kind: 8 // 标记唯一的选项类型,比如window scale是3
    Length: 10 bytes // 标记Timestamps选项的字节数
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    | Kind=8 | Length=10 | TS Value (TSval) | TS ECho Reply (TSecr) |
    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    1 1 4 4
    timestamps一个双向的选项,当一方不开启时,两方都将停用timestamps。比如client端发送的SYN包中带有timestamp选项,但server端并没有开启该选项。则回复的SYN-ACK将不带timestamp选项,同时client后续回复的ACK也不会带有timestamp选项。当然,如果client发送的SYN包中就不带timestamp,双向都将停用timestamp。

    tcp数据包中timestamps的value是系统开机时间到现在时间的(毫秒级)时间戳。

    参数:

    0:停用

    1:启用(系统默认值)

    2,net.ipv4.tcp_tw_recycle

    TCP规范中规定的处于TIME_WAIT的TCP连接必须等待2MSL时间。但在linux中,如果开启了tcp_tw_recycle,TIME_WAIT的TCP连接就不会等待2MSL时间(而是rto或者60s),从而达到快速重用(回收)处于TIME_WAIT状态的tcp连接的目的。这就可能导致连接收到之前连接的数据。为此,linux在打开tcp_tw_recycle的情况下,会记录下TIME_WAIT连接的对端(peer)信息,包括IP地址、时间戳等。这样,当内核收到同一个IP的SYN包时,就会去比较时间戳,检查SYN包的时间戳是否滞后,如果滞后,就将其丢掉(认为是旧连接的数据)。这在绝大部分情况下是没有问题的,但是对于我们实际的client-server的服务,访问我们服务的用户一般都位于NAT之后,如果NAT之后有多个用户访问同一个服务,就有可能因为时间戳滞后的连接被丢掉。


    参数:

    0:停用(系统默认值)

    1:启用


    参考:

    https://serverfault.com/questions/235965/why-would-a-server-not-send-a-syn-ack-packet-in-response-to-a-syn-packet

    http://hustcat.github.io/tcp_tw_recycle-and-tcp_timestamp/

    原文地址:https://blog.51cto.com/leejia/1954628


    # 配置记录
    [root@sz_cc_cbs_download01:~]# cat /etc/sysctl.conf
    # Kernel sysctl configuration file for Red Hat Linux
    #
    # For binary values, 0 is disabled, 1 is enabled. See sysctl(8) and
    # sysctl.conf(5) for more details.

    # Controls IP packet forwarding
    net.ipv4.ip_forward = 0

    # Controls source route verification
    net.ipv4.conf.default.rp_filter = 1

    # Do not accept source routing
    net.ipv4.conf.default.accept_source_route = 0

    # Controls the System Request debugging functionality of the kernel
    kernel.sysrq = 0

    # Controls whether core dumps will append the PID to the core filename.
    # Useful for debugging multi-threaded applications.
    kernel.core_uses_pid = 1

    # Controls the use of TCP syncookies
    net.ipv4.tcp_syncookies = 1

    # Disable netfilter on bridges.
    net.bridge.bridge-nf-call-ip6tables = 0
    net.bridge.bridge-nf-call-iptables = 0
    net.bridge.bridge-nf-call-arptables = 0

    # Controls the maximum size of a message, in bytes
    kernel.msgmnb = 65536

    # Controls the default maxmimum size of a mesage queue
    kernel.msgmax = 65536

    # Controls the maximum shared segment size, in bytes
    kernel.shmmax = 68719476736

    # Controls the maximum number of shared memory segments, in pages
    kernel.shmall = 4294967296

    net.core.netdev_max_backlog = 32768
    net.core.somaxconn = 32768
    net.core.rmem_max = 16777216
    net.core.rmem_default = 8388608
    net.core.wmem_max = 16777216
    net.core.wmem_default = 8388608

    net.ipv4.tcp_sack = 1
    net.ipv4.tcp_window_scaling = 1
    net.ipv4.tcp_rmem = 8192 436600 873200
    net.ipv4.tcp_wmem = 8192 436600 873200
    net.ipv4.tcp_mem = 94500000 915000000 927000000
    net.ipv4.tcp_max_orphans = 3276800
    #net.ipv4.tcp_max_orphans = 32768

    net.ipv4.tcp_synack_retries = 2
    net.ipv4.tcp_syn_retries = 2
    net.ipv4.tcp_retries2 = 5
    net.ipv4.tcp_syncookies = 1
    net.ipv4.tcp_timestamps = 1
    net.ipv4.tcp_tw_recycle = 0
    net.ipv4.tcp_tw_reuse = 1
    net.ipv4.tcp_fin_timeout = 10

    net.ipv4.tcp_keepalive_time = 1200
    net.ipv4.tcp_keepalive_probes = 5
    net.ipv4.tcp_keepalive_intvl = 15

    net.ipv4.ip_local_port_range = 1024 65500
    net.ipv4.tcp_max_syn_backlog = 16384
    #net.ipv4.tcp_max_tw_buckets = 5000
    net.ipv4.tcp_max_tw_buckets = 18000

    net.ipv4.tcp_retries1 = 3
    net.ipv4.tcp_retries2 = 3
    net.ipv4.tcp_orphan_retries = 3
    net.ipv4.tcp_abort_on_overflow = 1

    net.netfilter.nf_conntrack_max = 65530
    net.nf_conntrack_max = 655300
    net.netfilter.nf_conntrack_tcp_timeout_established = 1200

    vm.swappiness= 5

    #########

     tcp_tw_recycle和tcp_timestamps     注意:VPC 中,这二个参数只能打开一个,即这两个参数的值一般只能tcp_timestamps  设置为1

  • 相关阅读:
    java高并发
    阿里网盘挂载到本地主机
    frp突破内网ip限制教程
    docker学习总结(流水线、redis集群、网络待)
    git\svn提交记录规范
    【寻径06】如何突破学习瓶颈学习笔记
    leetcode 每日一题解题859. 亲密字符串
    字符串格式的json字符串转换为json格式的字符串
    如何使用github发布自己的静态项目
    软考第一课总结考前介绍(1)
  • 原文地址:https://www.cnblogs.com/reblue520/p/11195944.html
Copyright © 2020-2023  润新知