自连接

1. 如何实验出现这个现象

创建python 脚本 self_connect.py

#!/usr/bin/python
import errno
import socket
import sys
import time

if len(sys.argv) < 2:
    print "must input port."
    print "port should in net.ipv4.ip_local_port_range"
    exit()

port = int(sys.argv[1])
for i in range(65536):
    try:
        sock = socket.create_connection(("127.0.0.1", port))
        print "connected", sock.getsockname(), sock.getpeername()
        time.sleep(60*60)  # to netstat port
    except socket.error,  e:
        if e.errno != errno.ECONNREFUSED:
            print e.errno, errno.ECONNREFUSED
            break

执行该脚本,可以看到结果为:
脚本执行结果
netstat查看端口状态
从截图可以看到,同一ip下的同一端口,相互连接。
这不是内核bug

2. 原因

2.1 连接的时候,没有指定本地端口(local port),Linux系统会在 net.ipv4.ip_local_port_range 指定的端口范围内分配一个未被占用的端口。比如选择了端口N,如果N端口拒绝连接,就会发送包含RST标志的TCP报文段,本地
2.2 TCP协议支持同时打开
(RFC 793 TRANSMISSION CONTROL PROTOCOL 3.4. Establishing a connection)

上面python脚本过程说明: python self_connection.py 33000
ip 都是127.0.0.1
(1) 内核选择端口N与port: 33000 连接, 33000端口未打开,内核给 N端口返回 RST 标示的TCP报文段。
(2) 选择端口N+1,N+2,…, 直到 33000

    33000 ----------->(SYN)   33000
    33000 (ACK)<----------    33000
    33000 端口 ENSTABLISHED
    自连接

3. 附录

3.1 TCP 同时打开

(1) TCP 协议允许同时打开: RTC793 TRANSMISSION CONTROL PROTOCO figure 8

TCP A                                            TCP B

  1.  CLOSED                                           CLOSED

  2.  SYN-SENT     --> <SEQ=100><CTL=SYN>              ...

  3.  SYN-RECEIVED <-- <SEQ=300><CTL=SYN>              <-- SYN-SENT

  4.               ... <SEQ=100><CTL=SYN>              --> SYN-RECEIVED

  5.  SYN-RECEIVED --> <SEQ=100><ACK=301><CTL=SYN,ACK> ...

  6.  ESTABLISHED  <-- <SEQ=300><ACK=101><CTL=SYN,ACK> <-- SYN-RECEIVED

  7.               ... <SEQ=101><ACK=301><CTL=ACK>     --> ESTABLISHED

                Simultaneous Connection Synchronization

                               Figure 8.

3.2 自连接
(1) 根据tpcdump 查看TCP报文段(握手和挥手)

21:45:17.452481 IP 127.0.0.1.33000 > 127.0.0.1.33000: Flags [S], seq 2122155273, win 43690, options [mss 65495,sackOK,TS val 214381031 ecr 0,nop,wscale 7], length 0
21:45:17.452485 IP 127.0.0.1.33000 > 127.0.0.1.33000: Flags [S.], seq 2122155273, ack 2122155274, win 43690, options [mss 65495,sackOK,TS val 214381031 ecr 214381031,nop,wscale 7], length 0
21:45:17.452488 IP 127.0.0.1.33000 > 127.0.0.1.33000: Flags [.], ack 2122155274, win 342, options [nop,nop,TS val 214381031 ecr 214381031], length 0
21:45:23.601611 IP 127.0.0.1.33000 > 127.0.0.1.33000: Flags [F.], seq 2122155274, ack 2122155274, win 342, options [nop,nop,TS val 214382568 ecr 214381031], length 0
21:45:23.601624 IP 127.0.0.1.33000 > 127.0.0.1.33000: Flags [.], ack 2122155275, win 342, options [nop,nop,TS val 214382568 ecr 214382568], length 0
    SYN报文段和FIN报文段比较特殊,会消耗一个序列号

(2) TCP 协议允许自连接
RTC793 TRANSMISSION CONTROL PROTOCO figure 7

      TCP A                                                TCP B

  1.  CLOSED                                               LISTEN

  2.  SYN-SENT    --> <SEQ=100><CTL=SYN>               --> SYN-RECEIVED

  3.  ESTABLISHED <-- <SEQ=300><ACK=101><CTL=SYN,ACK>  <-- SYN-RECEIVED

  4.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK>       --> ESTABLISHED

  5.  ESTABLISHED --> <SEQ=101><ACK=301><CTL=ACK><DATA> --> ESTABLISHED

          Basic 3-Way Handshake for Connection Synchronization

                                Figure 7.

4. 如何解决

连接以后,根据连接的socket获取本地和目标的地址(ip+port),然后比较地址是否相等即可。
根据 getpeername和getsockname 分别获取目标和本地地址。

5. 引用

http://gad.qq.com/article/detail/26391
https://blog.csdn.net/wohenfanjian/article/details/51867950
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=24716553&id=5602432
https://tools.ietf.org/html/rfc793#section-3.4

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐