13

我正在努力将 scapy 与 twisted 集成,但我在 OSX 上遇到了这个我似乎无法弄清楚的非常奇怪的错误。

基本上我无法通过原始套接字发送有效的 TCP 数据包(包括 IP 标头)。这就是我正在做的事情:

import socket
from scapy.all import IP, TCP
pkt = IP(src='0.0.0.0', dst='127.0.0.1')/TCP()
spkt1 = str(pkt)
outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
outs.sendto(spkt1, ('127.0.0.1', 0))

当我运行它时,我收到以下错误:

outs.sendto(spkt1, ('127.0.0.1', 0)) socket.error: [Errno 22] Invalid argument

如果您没有 scapy 不想使用它,这是 base64 编码的数据包:

import base64
spkt1 = base64.b64decode("RQAAKAABAABABvvOAAAAAH8AAAEAFABQAAAAAAAAAABQAiAAEH4AAA==")

非常奇怪的是,一个几乎相同的数据包似乎被正确发送:

spkt2 = base64.b64decode("RQBAAAWwAAACBgAAAAAAAH8AAAEAyAOEAAAAAAAAAACwAgDIAHsAAAIEBbQBAwMBAQEICk3PUjMAAAAABAIAAA==")

这是两个数据包的样子:

SPKT1
0000   45 00 00 28 00 01 00 00  40 06 FB CE 00 00 00 00   E..(....@.......
0010   7F 00 00 01 00 14 00 50  00 00 00 00 00 00 00 00   .......P........
0020   50 02 20 00 10 7E 00 00                            P. ..~..
SPKT2
0000   45 00 40 00 05 B0 00 00  02 06 00 00 00 00 00 00   E.@.............
0010   7F 00 00 01 00 C8 03 84  00 00 00 00 00 00 00 00   ................
0020   B0 02 00 C8 00 7B 00 00  02 04 05 B4 01 03 03 01   .....{..........
0030   01 01 08 0A 4D CF 52 33  00 00 00 00 04 02 00 00   ....M.R3........

通过在wireshark中检查它们,它们仅在TCP部分有所不同。

我做了很多不同的实验,最后我能够通过设置某些特定的 TCP 选项来发送数据包,但是这样的数据包不应该工作是没有意义的。

有人知道为什么会发生这种情况吗?

编辑:

此数据包似乎确实有效:

pkt = IP(len=16384, src='0.0.0.0', dst='127.0.0.1',
     id=RandShort(), ttl=2)/TCP(sport=255,
      dport=900, flags="S", window=200,
      options=[('MSS', 1460), ('WScale', 2)])
spkt = bytes(pkt)
spkt += '\x00'*20

如果您不添加零,则它不起作用。

4

6 回答 6

3

我最终决定原始套接字只是为了使用而被窃听。特别是由于该软件需要跨平台,OSX 的怪癖可能不适用于其他操作系统。

目前我只是简单地包装了 scapy 提供的“套接字”。将来我会写一些只依赖于 libdnet 的东西(因为这是 scapy 写原始帧的方法)。

你可以在这里找到这个实现:

https://github.com/hellais/txscapy

于 2012-06-13T14:34:51.200 回答
1

IP 标头必须具有 32 位的倍数才能有效。最后还有一个填充区域。

因此,根据标头中设置的 IP 选项(占用可变数量的位),需要计算位填充。

看起来不同的操作系统以不同的方式处理这个问题。有人可能会认为一个聪明的操作系统会为你做这个填充。

于 2015-09-16T22:46:45.640 回答
0

0.0.0.0 在我看来不是一个有效的 IP 源地址。将其更改为任何其他值有什么不同吗?

于 2012-06-12T21:38:05.397 回答
0
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53) 
[GCC 4.5.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import socket
>>> from scapy.all import IP, TCP
WARNING: No route found for IPv6 destination :: (no default route?)
>>> pkt = IP(src='0.0.0.0', dst='127.0.0.1')/TCP()
>>> spkt1 = str(pkt)
>>> 
>>> outs = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_RAW)
>>> outs.setsockopt(socket.SOL_IP, socket.IP_HDRINCL, 1)
>>> outs.sendto(spkt1, ('127.0.0.1', 0))
40

我在编写特定的数据包集时似乎没有任何错误——我使用的是 x86_64 和 2.6.38-* Gnu/Linux 内核。

也许您的问题与原始套接字的某些 Mac OS X 脑损伤有关?

于 2012-06-12T21:49:09.873 回答
0

另一个相关的问题。Pythonimpacket模块具有ping.pyping 主机的脚本。在 Mac OS X Lion 上,使用此脚本时出现错误:

Traceback (most recent call last):
  File "/private/var/www/env/bin/ping.py", line 73, in <module>
    s.sendto(ip.get_packet(), (dst, 0))
socket.error: [Errno 22] Invalid argument

但在 Ubuntu 上一切正常,我收到了主机的回复。

于 2012-08-21T20:17:57.987 回答
0

我没有确凿的证据,但我认为这可能与以太网最小有效负载大小有关。

来自维基百科

存在 802.1Q 标签时,最小有效载荷为 42 个八位字节,不存在时为 46 个八位字节。

您的第一个示例数据包只有 40 个字节,因此在任何一种情况下都低于限制。您可以尝试将填充从 20 个字节更改为这些值,以验证它是否在某个限制处停止工作。

如果是这样,那么这种行为就很合理了;操作系统拒绝数据包,因为您没有提供足够的数据来构造有效的数据包。

于 2012-08-21T22:04:05.380 回答