我正在编写一个应用程序来测试网络驱动程序以处理损坏的数据。我想使用原始套接字发送这些数据,因此发送机器的TCP-IP堆栈不会纠正它。
我只在Linux上编写这个应用程序。我有在系统调用中使用原始套接字的代码示例,但我真的希望尽可能保持测试的动态,并在Python中编写大部分(如果不是全部的话)。
我在网上搜索了一些关于在python中使用原始套接字的解释和示例,但是没有找到任何真正有启发性的东西。只是一个非常古老的代码示例,演示了这个想法,但绝不是有效的。
从我收集的内容来看,Python中的Raw Socket使用在语义上几乎与UNIX的原始套接字完全相同,但没有定义数据包结构的struct
s。
我想知道在Python中编写测试的原始套接字部分是否更好,但在C中使用系统调用,并从主Python代码调用它?
你这样做:
首先禁用网卡的自动校验和:
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)
完成。
套接字系统调用(或Windows上的Winsocks)已经包含在标准模块socket
:intro,reference中。
我从来没有使用过原始套接字,但看起来它们可以用于这个模块:
最后一个示例显示了如何在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)
this是你提到的旧代码吗?它对我来说很合理,但我自己没有测试过(或者使用了很多原始套接字)。文档中的This example显示了如何使用原始套接字来嗅探数据包,它看起来很相似。
最终这个案例的最佳解决方案是用C编写整个事物,因为它不是一个大的应用程序,所以用一种以上的语言编写这么小的东西会受到更大的惩罚。
经过多次使用C和python RAW套接字后,我最终选择了C RAW套接字。 RAW套接字需要少于8位组的位级修改才能写入包头。有时只写4位或更少。 python没有定义任何帮助,而Linux C有一个完整的API。
但是我绝对相信如果只是在python中方便地处理了这一点头文件初始化,我就不会在这里使用C了。
s = socket(AF_PACKET, SOCK_RAW)
s = socket(PF_PACKET, SOCK_RAW)
结果:
[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 ]]]....
套接字类应该有所帮助。如果不是,您需要在C中编写Python模块或只使用C.请参阅http://mail.python.org/pipermail/python-list/2001-April/077454.html。
基本的谷歌搜索发现。
我实际上尝试过“unwind”指出的代码示例。 AF_PACKET在python 2.7.4中为我工作
FTR,如果你想要2级访问(以太网,RadioTap ......),这在Windows上是不可能的(截至今天)。
如果你想使用跨平台方法访问那些,那么首选的选择是libpcap
及其Python绑定(因为它将使用Npcap/WinPcap
在Windows上运行)。
您可以在各种级别(非常高或非常低)使用libpcap的各种Python绑定。
我的建议是使用scapy
的套接字(即使你没有用它来剖析),实现Native和Libpcap调用,(并让你用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
您可以使用此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()