Python 简单的 UDP 服务器不接收带有 IP 选项的消息

Python simple UDP server does not receive message with IP options

我有一个简单的 udp server/client 设置,我从客户端发送消息并将其打印在服务器上。这适用于常规 IP 数据包,但当我向数据包添加 IP 选项 header 时未收到消息,即使我可以使用 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 选项的数据包 header:

###[ 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

我已经坚持了几天,如果有人能解决这个问题我会很高兴。

谢谢

刚刚玩过,下面的作品作为我的 self-contained/minimal 工作示例 Python 3.7.1 在 OSX 和 Linux[=17= 下]

正在生成一组有效的 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))

这应该导致 "server" 显示如下行:

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 选项的辅助数据,但数据显示在数据包嗅探器中。

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

感谢大家的帮助和指点!