原始套接字和python中的sendto

时间:2012-06-12 20:22:01

标签: python networking tcp ip scapy

我正在努力将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 on,不想使用它,这是数据包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

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

6 个答案:

答案 0 :(得分:3)

我最终决定将Raw Sockets改为可用。特别是因为该软件需要跨平台,OSX的怪癖可能不适用于其他操作系统。

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

你可以在这里找到这个:

https://github.com/hellais/txscapy

答案 1 :(得分:1)

要求IP头具有32位的倍数才有效。最后还有一个填充区域。

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

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

答案 2 :(得分:0)

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

答案 3 :(得分: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脑损伤有关?

答案 4 :(得分:0)

另一个相关问题。 Python impacket模块有ping.py脚本来ping主机。在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上一切正常,我收到了来自主机的回复。

答案 5 :(得分:0)

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

来自wikipedia

  

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

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

如果是这样,这种行为就很有意义;操作系统拒绝该数据包,因为您没有提供足够的数据来构建有效的数据包。