Python套接字:在Linux中启用混杂模式

Tan*_*anB 10 python sockets networking

我们知道Python允许在Windows下启用混杂模式

s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)
Run Code Online (Sandbox Code Playgroud)

但是,RCVALL_*和SIO_*仅在Windows中可用.使用C socket api,在Linux中,可以使用:

ethreq.ifr_flags |= IFF_PROMISC;
ioctl(sock, SIOCSIFFLAGS, &ethreq);
Run Code Online (Sandbox Code Playgroud)

或通过,

setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, PACKET_MR_PROMISC)
Run Code Online (Sandbox Code Playgroud)

python socket API中是否有任何选项允许我们在Linux中设置混杂模式

Jea*_*one 17

使用AF_NETLINK套接字发出打开请求IFF_PROMISC.Python可以AF_NETLINK在Linux上构建套接字:

>>> from socket import AF_NETLINK, SOCK_DGRAM, socket 
>>> s = socket(AF_NETLINK, SOCK_DGRAM)
>>>
Run Code Online (Sandbox Code Playgroud)

有关如何发出netlink请求的示例,请参阅netlink(7)手册页末尾的示例.您可以使用ctypes(或甚struct至)构造序列化的nlmsghdr消息以通过netlink套接字发送.您可能还需要它来打电话sendmsgrecvmsg,因为Python的还是不公开这些API.或者,有一些第三方模块可以公开这两个API.

或者,你可以去旧学校使用的路线ioctl,遗憾的是它变得相当简单.

首先使用ctypes定义ifreq结构:

import ctypes

class ifreq(ctypes.Structure):
    _fields_ = [("ifr_ifrn", ctypes.c_char * 16),
                ("ifr_flags", ctypes.c_short)]
Run Code Online (Sandbox Code Playgroud)

然后创建一个与ioctl调用一起使用的套接字:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
Run Code Online (Sandbox Code Playgroud)

然后从/ usr/include中复制几个常量值,因为它们不会被Python公开:

IFF_PROMISC = 0x100
SIOCGIFFLAGS = 0x8913
SIOCSIFFLAGS = 0x8914
Run Code Online (Sandbox Code Playgroud)

创建ifreq结构的实例并填充它以获得所需的效果:

ifr = ifreq()
ifr.ifr_ifrn = "eth4"
Run Code Online (Sandbox Code Playgroud)

ifr_flags使用ioctl调用填充字段,这样就不会破坏接口上已设置的任何标志:

import fcntl

fcntl.ioctl(s.fileno(), SIOCGIFFLAGS, ifr) # G for Get
Run Code Online (Sandbox Code Playgroud)

添加混杂标志:

ifr.ifr_flags |= IFF_PROMISC
Run Code Online (Sandbox Code Playgroud)

并在界面上设置标志:

fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifr) # S for Set
Run Code Online (Sandbox Code Playgroud)

要删除该标志,请将其屏蔽并再次设置:

ifr.ifr_flags &= ~IFF_PROMISC
fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifr)
Run Code Online (Sandbox Code Playgroud)


Tan*_*anB 5

我还想到了另外一个办法。也许不那么优雅,但似乎工作得很好。

在linux(具有root权限)中,可以使用:

# ifconfig eth0 promisc
# ifconfig eth0 -promisc
Run Code Online (Sandbox Code Playgroud)

在您的接口(本例中为 eth0)上启用/禁用混杂模式。

因此,在 python 中(具有 root 权限)可以使用:

import os
ret =  os.system("ifconfig eth0 promisc")
if ret == 0:
     <Do something>
Run Code Online (Sandbox Code Playgroud)

欢迎对这种做法提出意见。

  • 使用较新的“ip”实用程序的类似方法是运行“ip link set eth0 promisc on”。在子进程中调用 ifconfig 可能会执行与我在答案中给出的相同的 ioctl。在子进程中调用 ip 将执行我提到但实际上没有详细说明的 AF_NETLINK 操作(因为它更难:)。 (3认同)