【问题标题】:Python simple UDP server does not receive message with IP optionsPython 简单 UDP 服务器不接收带有 IP 选项的消息
【发布时间】:2019-01-09 17:35:09
【问题描述】:

我有一个简单的 udp 服务器/客户端设置,我从客户端发送消息并将其打印到服务器上。这适用于常规 IP 数据包,但是当我向数据包添加 IP 选项标头时未收到消息,即使我可以使用 scapy 嗅探数据包。 这是没有 IP 选项的数据包

###[ Ethernet ]###
dst       = 00:04:00:00:04:01
src       = 00:aa:00:02:00:04
type      = 0x800
###[ IP ]###
 version   = 4L
 ihl       = 5L
 tos       = 0x0
 len       = 47
 id        = 1
 flags     =
 frag      = 0L
 ttl       = 61
 proto     = udp
 chksum    = 0x62f4
 src       = 10.0.2.101
 dst       = 10.0.4.101
 \options   \
###[ UDP ]###
    sport     = 10001
    dport     = 3478
    len       = 27
    chksum    = 0x2bd1
###[ Raw ]###
       load      = 'message from a game'

这是带有 IP 选项标头的数据包:

###[ Ethernet ]###
dst       = 00:04:00:00:04:01
src       = 00:aa:00:02:00:04
type      = 0x800
###[ IP ]###
 version   = 4L
 ihl       = 8L
 tos       = 0x0
 len       = 59
 id        = 1
 flags     =
 frag      = 0L
 ttl       = 61
 proto     = udp
 chksum    = 0x5fe8
 src       = 10.0.2.101
 dst       = 10.0.4.101
 \options   \
  |###[ IPOption ]###
  |  copy_flag = 1L
  |  optclass  = control
  |  option    = 31L
  |  length    = 12
  |  value     = '\x00\x01\x00\x00RTGAME'
###[ UDP ]###
    sport     = 10001
    dport     = 3478
    len       = 27
    chksum    = 0x2bd1
###[ Raw ]###
    load      = 'message from a game'

这里是 UDP 服务器:

sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(('', args.port))

while True:
    try:
        data, addr = sock.recvfrom(1024)
        print("received: %s" % data)
    except KeyboardInterrupt:
        sock.close()
        break

我已经被这个问题困扰了几天,如果有人能解决这个问题,我会很高兴的。

谢谢

【问题讨论】:

  • 只是为了确认;当您说“嗅探”时,我认为您的意思是在运行“服务器”代码的同一主机上?即它都是本地主机或通过网络实现的。我假设您使用 AF_PACKET 来查看较低层,但是如果您使用 AF_INET 系列会发生什么
  • 正确。我编写了一个单独的程序来使用 scapy 嗅探数据包,并在与 udp 服务器相同的主机上运行它。所以数据包确实到达了服务器,但不知何故没有收到。 AF_PACKET 部分只是一个错字。我已经尝试过了,但它也没有工作。现在只使用 AF_INET,我已经更新了问题以反映这一点
  • 首先,我认为这与python没有任何关系。你可以很容易地使用nc -l -u 3478(并删除python标签)。这似乎可能是特定于操作系统的问题(假设接收到的数据包确实有效)。你没有说你正在使用什么操作系统;那会有所帮助。查看 linux 内核源代码,一方面,我看不出带有(未知)IP 选项的相同 UDP 数据包不会传送到您的服务器的任何原因(同样,如果数据包有效)。我不只是用 scapy 嗅探,而是用wireshark 嗅探,并确保wireshark 认为数据包是有效的。
  • @DancingHippo 我认为这与您的环境有关……我可以发送具有相同 IP 选项集的数据包(在 OSX 下使用 Python 3.7.1 进行测试)并且类似的 Python“服务器”代码会看到数据包正如我所料。

标签: sockets udp


【解决方案1】:

刚刚玩过,以下是我在 OSX 和 Linux 下使用 Python 3.7.1 的独立/最小工作示例

生成一组有效的 IP 选项:

from scapy.all import IPOption, raw

ipopts = raw(IPOption(
    copy_flag=1, optclass='control', option=31,
    value='\x00\x01\x00\x00RTGAME'))

(如果你没有 Scapy,上面应该生成:b'\x9f\x0c\x00\x01\x00\x00RTGAME'

客户端代码:

import socket
from time import sleep

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    s.connect(('127.0.0.1', 3478))
    s.setsockopt(socket.IPPROTO_IP, socket.IP_OPTIONS, ipopts)

    while True:
        s.send(b'message from a game')
        sleep(1)

服务器代码:

import socket

with socket.socket(socket.AF_INET, socket.SOCK_DGRAM) as s:
    s.bind(('', 3478))
    s.setsockopt(socket.IPPROTO_IP, socket.IP_RECVOPTS, 1)

    while True:
        print(*s.recvmsg(4096, 1024))

这应该导致“服务器”显示如下行:

b'message from a game\n' [(0, 6, b'\x9f\x0c\x00\x01\x00\x00RTGAME')] 0 ('127.0.0.1', 46047)

此外,我可以通过运行以下命令来观察数据包在网络上的移动:

sudo tcpdump -i lo0 -vvv -n 'udp and port 3478'

在命令行,或者在 Scapy 中:

sniff(iface='lo0', filter='udp and port 3478', prn=lambda x: x.show())

由于某种原因,我实际上并没有收到包含 OSX 下 IP 选项的辅助数据,但数据显示在数据包嗅探器中。

【讨论】:

  • 我试过了,它在我的 OSX 上运行良好。所以我开始寻找其他地方,并在 IPv4 校验和中发现了问题。我发布了一个答案。
【解决方案2】:

问题是由于 IPv4 校验和不正确造成的。我没有在问题中提到我在带有自定义开关的 mininet 环境中运行它。交换机在传输过程中添加了 IP 选项,但校验和未更新。一旦我解决了这个问题,数据包就会到达服务器。

感谢大家的帮助和指点!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-02-10
    • 1970-01-01
    相关资源
    最近更新 更多