如何在Python中使用原始套接字?

48 投票
8 回答
127349 浏览
提问于 2025-04-15 12:52

我正在写一个应用程序,用来测试网络驱动程序处理损坏数据的能力。我想通过原始套接字发送这些数据,这样发送机器的TCP-IP协议栈就不会对数据进行修正。

我这个应用程序完全是在Linux上写的。我有一些关于在系统调用中使用原始套接字的代码示例,但我希望我的测试尽可能动态,尽量用Python来写大部分甚至全部的代码。

我在网上查了一些关于在Python中使用原始套接字的解释和示例,但没有找到什么特别有用的东西。只找到一个非常旧的代码示例,虽然展示了这个想法,但根本不能用。

根据我了解到的,Python中使用原始套接字的方式和UNIX的原始套接字几乎是一样的,只是没有定义数据包结构的struct

我在想,是否更好把测试中的原始套接字部分用C语言和系统调用来写,然后从主Python代码中调用它呢?

8 个回答

2

这是你提到的那个旧代码吗?我觉得看起来还不错,但我自己没有测试过(也不太常用原始套接字)。文档中的这个例子展示了如何使用原始套接字来嗅探数据包,看起来也挺像的。

10

在计算机中,套接字系统调用(在Windows上叫做Winsocks)已经被封装在标准模块socket里。你可以查看这些链接了解更多:入门介绍参考文档

我自己从来没有用过原始套接字,但看起来可以通过这个模块来使用它们:

最后一个例子展示了如何在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)
62

你可以这样做:

首先,你需要关闭网络卡的自动校验和功能:

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)

完成。

撰写回答