无法使用python将UDP数据包发送到本地端口,根据WireShark的校验和失败

时间:2014-03-04 05:23:33

标签: python sockets networking udp socks

我一直把头发拉过来。我正在尝试用Python编写SOCKS5服务器来隧道传输UDP流量。我绑定到一个端口,并收到数据。然后我解析SOCKS5 UDP头(不是典型的UDP头),并将数据报转发到请求的端点。

一切都很好。然后我监听端点的响应(如果超时则重新发送),并获得响应。太好了!

这是我失去理智的地方 -

我从端点获取数据报。我根据SOCKS5 RFC重新封装了返回的数据报,这是与之前相同的UDP头,除了我现在已经将目标地址和端口更改为原始调用者。我用:

sock_client = socket.socket(socket.AF_INET, # Internet
                            socket.SOCK_DGRAM) # UDP
sock_client.sendto(packed_datagram, (self.client_ip, self.client_port))

将数据报发送回客户端。客户永远不会收到回复!永远!

看看WireShark,它说:Header校验和:0x0000 [不正确,应该是0xcd1f(可能是由“IP校验和卸载”造成的?)

设置socket.DGRAM的python套接字实现不应该自动将数据正确地打包在UDP头中并计算相应的校验和吗?为什么设置为0x0000?我用十六进制检查了有效负载,校验和确实设置错误。到底是怎么回事?

4 个答案:

答案 0 :(得分:1)

校验和计算由操作系统中的驱动程序完成。在可能的情况下,计算由网卡本身完成。 IIRC,Wireshark在将本地数据包传递到网络堆栈之前抓取它们。所有本地生成的数据包的校验和错误都很常见。

答案 1 :(得分:1)

我没有准确地遵循两条SOCKS5规范。

  

当UDP连接的TCP连接时,UDP关联终止   ASSOCIATE请求终止。

我在完成UDP中继握手后立即终止TCP套接字。 TCP必须保持打开状态,直到来回完成。

  

当UDP中继服务器从远程接收回复数据报时   主机,它必须使用上面的UDP请求封装该数据报   标头,以及任何依赖于身份验证方法的封装。

我使用客户端的IP和端口作为数据报中的值。它必须是远程服务器的IP和端口,本质上UDP头封装是客户端传入的克隆。

解决了这两个问题后,SOCKS5服务器按预期工作。

答案 2 :(得分:0)

如果我正确理解了您的部分代码,您可以创建一个新的套接字以将数据发送回客户端。因此,这将是具有随机源IP的新套接字,例如,从客户端的角度来看,您有以下数据包流:

client_ip:client_port  -> socks5_ip:socks_port
client_ip:client_port  <- socks5_ip:random_port

客户端可能已连接到socks5服务器的套接字,因此需要来自socks5_ip:socks_port的回复,而不是random_port。 因此,您不应该为客户端创建一个新的套接字,而是使用从客户端接收数据的现有套接字进行回复。

答案 3 :(得分:0)

使用linux命令关闭tx-checksumming:

ethtool -K eth0 tx off

或使用此函数计算校验和

def checksum(data):
    s = 0
    n = len(data) % 2
    for i in range(0, len(data)-n, 2):
        s+= ord(data[i]) + (ord(data[i+1]) << 8)
    if n:
        s+= ord(data[i+1])
    while (s >> 16):
        s = (s & 0xFFFF) + (s >> 16)
    s = ~s & 0xffff
    return s

数据是伪标题