46

我正在编写一个应用程序来测试用于处理损坏数据的网络驱动程序。而且我想使用原始套接字发送这些数据,因此发送机器的 TCP-IP 堆栈不会更正它。

我仅在 Linux 上编写此应用程序。我有在系统调用中使用原始套接字的代码示例,但我真的很想保持我的测试尽可能动态,并用 Python 编写大部分(如果不是全部)。

我在网上搜索了一些关于在 python 中使用原始套接字的解释和示例,但没有发现任何真正有启发性的东西。只是一个非常古老的代码示例,它演示了这个想法,但绝不可行。

从我收集到的信息来看,Python 中的 Raw Socket 使用在语义上与 UNIX 的原始套接字几乎相同,但没有struct定义数据包结构的 s。

我想知道是否最好不要在 Python 中编写测试的原始套接字部分,而是在带有系统调用的 C 中编写,然后从主要的 Python 代码中调用它?

4

8 回答 8

59

你这样做:

首先禁用网卡的自动校验和:

sudo ethtool -K eth1 tx off

然后从 python 2 发送你的狡猾帧(你必须自己转换到 Python 3):

#!/usr/bin/env python
from socket import socket, AF_PACKET, SOCK_RAW
s = socket(AF_PACKET, SOCK_RAW)
s.bind(("eth1", 0))

# We're putting together an ethernet frame here, 
# but you could have anything you want instead
# Have a look at the 'struct' module for more 
# flexible packing/unpacking of binary data
# and 'binascii' for 32 bit CRC
src_addr = "\x01\x02\x03\x04\x05\x06"
dst_addr = "\x01\x02\x03\x04\x05\x06"
payload = ("["*30)+"PAYLOAD"+("]"*30)
checksum = "\x1a\x2b\x3c\x4d"
ethertype = "\x08\x01"

s.send(dst_addr+src_addr+ethertype+payload+checksum)

完毕。

于 2011-06-16T15:57:17.963 回答
11

Sockets 系统调用(或 Winsocks,在 Windows 上),已经包装在标准模块中socketintroreference

我从未使用过原始套接字,但看起来它们可以与此模块一起使用:

最后一个例子展示了如何在 Windows 上使用原始套接字编写一个非常简单的网络嗅探器。该示例需要管理员权限才能修改界面:

import socket

# the public network interface
HOST = socket.gethostbyname(socket.gethostname())

# create a raw socket and bind it to the public interface
s = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_IP)
s.bind((HOST, 0))

# Include IP headers
s.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)

# receive all packages
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

# receive a package
print s.recvfrom(65565)

# disabled promiscuous mode
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_OFF)
于 2009-07-13T06:52:13.807 回答
2

这是您提到旧代码吗?这对我来说看起来很明智,但我自己还没有测试过(或者使用了很多原始套接字)。文档中的这个例子展示了如何使用原始套接字来嗅探数据包,它看起来很相似。

于 2009-07-13T06:50:15.340 回答
2

最终,这种情况的最佳解决方案是用 C 编写整个东西,因为它不是一个大应用程序,所以用一种以上的语言编写这么小的东西会招致更大的惩罚。

在玩弄了 C 和 python RAW 套接字之后,我最终更喜欢 C RAW 套接字。RAW 套接字需要少于 8 位组的位级修改来写入数据包标头。有时只写 4 位或更少。python 对此没有定义任何帮助,而 Linux C 对此有完整的 API。

但我绝对相信,如果只是在 python 中方便地处理这一点头初始化,我就不会在这里使用 C。

于 2009-07-27T06:58:51.340 回答
1
s = socket(AF_PACKET, SOCK_RAW)
s = socket(PF_PACKET, SOCK_RAW)

结果:</p>

[root@localhost python]# tcpdump -i eth0

capture size 96 bytes
11:01:46.850438 

01:02:03:04:05:06 (oui Unknown) > 01:02:03:04:05:06 (oui Unknown), ethertype Unknown (0x0801), length 85:

        0x0000:  5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b  [[[[[[[[[[[[[[[[
        0x0010:  5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5b5b 5041  [[[[[[[[[[[[[[PA
        0x0020:  594c 4f41 445d 5d5d 5d5d 5d5d 5d5d 5d5d  YLOAD]]]]]]]]]]]
        0x0030:  5d5d 5d5d 5d5d 5d5d 5d5d 5d5d 5d5d 5d5d  ]]]]]]]]]]]]]]]]
        0x0040:  5d5d 5d00 0000 00                        ]]]....
于 2012-09-28T03:15:43.410 回答
0

套接字类应该有所帮助。如果不是,您需要用 C 编写 Python 模块或只使用 C。请参阅http://mail.python.org/pipermail/python-list/2001-April/077454.html

基本谷歌搜索发现。

我实际上尝试了“展开”指出的代码示例。AF_PACKET 在 python 2.7.4 中确实为我工作

于 2009-07-13T06:49:05.763 回答
0

您可以使用这个 Python 库:rawsocketpy它允许在第 2 层上使用原始套接字 => 无 IP/TCP/UDP 标头。

#!/usr/bin/env python
from rawsocketpy import RawSocket

sock = RawSocket("wlp2s0", 0xEEFA)
sock.send("some data")
sock.send("personal data", dest="\xAA\xBB\xCC\xDD\xEE\xFF")

或服务器形式:

#!/usr/bin/env python
from rawsocketpy import RawRequestHandler, RawAsyncServerCallback
import time

def callback(handler, server):
    print("Testing")
    handler.setup()
    handler.handle()
    handler.finish()

class LongTaskTest(RawRequestHandler):
    def handle(self):
        time.sleep(1)
        print(self.packet)

    def finish(self):
        print("End")

    def setup(self):
        print("Begin") 

def main():
    rs = RawAsyncServerCallback("wlp2s0", 0xEEFA, LongTaskTest, callback)
    rs.spin()

if __name__ == '__main__':
    main()
于 2018-08-09T10:54:25.453 回答
0

FTR,如果您想要 2 级访问(以太网、RadioTap ...),这在 Windows 上是不可能的(截至今天)。

如果您想使用跨平台方法访问那些,首选选择是libpcap及其 Python 绑定(因为它将用于Npcap/WinPcap在 Windows 上工作)。

您可以在各种级别(非常高或非常低)上为 libpcap 提供各种 Python 绑定。

我的建议是使用实现 Native 和 Libpcap 调用的scapy即使你不使用它来剖析)的 Sockets,(并让你选择反对它们conf.use_pcap = True

from scapy.all import conf
# conf.use_pcap = True (will be automatic if required)
socket = conf.L2socket(iface="eth0")
# On any platforms, you have `get_if_list()` in `scapy.all` available, to see the ifaces available. You could also ignore it to use the default one
于 2019-06-08T11:48:21.337 回答