我有一个用Python编写的套接字代理,当它从一对通信对等端接收RST时,将通过让套接字被垃圾收集来关闭与两个对等体的连接。这导致其他对等体看到FIN而不是RST。
这意味着代理有效地将RST转换为FIN,我认为这不是理想的。
我发现在Linux中可以通过使用系列AF_UNSPEC
的地址调用connect来reset a TCP connnection。但我还没有找到一种方法来从Python程序中做到这一点。
我如何connect
使用Python中的AF_UNSPEC
地址?
到目前为止我尝试了什么
我尝试查看相关help
方法的connect
输出,并发现了这个:
Help on built-in function connect:
connect(...)
connect(address)
Connect the socket to a remote address. For IP sockets, the address
is a pair (host, port).
不幸的是,这并没有告诉我address
参数必须是什么才能构建AF_UNSPEC
地址。
我尝试将原始套接字fd包装在一个带有AF_UNSPEC
族的新套接字对象中,如下所示:
socket.fromfd(s.fileno(), socket.AF_UNSPEC, 0)
生成的对象生成相同的帮助文本,并且在新构造的套接字对象上调用connect
的任何尝试都会导致
socket.error: getsockaddrarg: bad family
所以看起来使用socket.fromfd
可能不是我问题的答案。
答案 0 :(得分:0)
看看CPython中当前的socket
软件包implementation,实际上没有pythonic的方法(从2019年1月起,将套接字连接到AF_UNSPEC
地址(即{ {3}}。
下一个最好的事情是在接受的套接字上设置SO_LINGER
选项(直接或通过继承)。启用延迟(并设置为零超时)后,关闭套接字将重置连接。
您必须注意在正确的套接字API级别上设置SO_LINGER
选项,并对选项值(它是结构)使用正确的编码。
示例:
import socket
import struct
import time
s = socket.socket(socket.AF_INET6)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_V6ONLY, 0)
# if we want to inherit this option:
#s.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
s.bind(('', 2323))
s.listen()
con, addr = s.accept()
con.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
time.sleep(1)
con.close()
time.sleep(3)
使用curl连接到该端口:
$ curl localhost:2323
curl: (56) Recv failure: Connection reset by peer
连接到该端口而不发送任何内容:
$ socat - tcp:localhost:2323
使用例如
转储数据包时$ tshark -i lo -f 'tcp port 2323'
在两种情况下,最后一个数据包都应该是RST(从服务器发送到客户端),例如:
39 9758.478140247 127.0.0.1 → 127.0.0.1 TCP 66 2323 → 34494 [RST, ACK]
Seq=1 Ack=1 Win=43776 Len=0 TSval=2787120418 TSecr=2787119417
答案 1 :(得分:-1)
您可以尝试使用SO_LINGER
套接字选项(setsockopt
),并将延迟时间设置为0. close
,套接字SO_LINGER
设置为0秒延迟时间将导致RST而不是FIN。