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

时间:2011-05-20 04:16:14

标签: python sockets networking

我们知道Python允许在Windows下通过

启用混杂模式
s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

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

ethreq.ifr_flags |= IFF_PROMISC;
ioctl(sock, SIOCSIFFLAGS, &ethreq);

或通过,

setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, PACKET_MR_PROMISC)

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

2 个答案:

答案 0 :(得分:15)

使用AF_NETLINK套接字发出启用IFF_PROMISC的请求。 Python可以在Linux上构建AF_NETLINK套接字:

>>> from socket import AF_NETLINK, SOCK_DGRAM, socket 
>>> s = socket(AF_NETLINK, SOCK_DGRAM)
>>>

有关如何发出netlink请求的示例,请参阅netlink(7)手册页末尾的示例。您可以使用ctypes(或甚至struct)构造序列化的nlmsghdr消息,以通过netlink套接字发送。自Python still doesn't expose these APIs起,您可能还需要它来致电sendmsgrecvmsg。或者,有一些third-party modules可用,它们公开了这两个API。

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

首先使用ctypes定义ifreq结构:

import ctypes

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

然后设置一个套接字用于ioctl调用:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

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

IFF_PROMISC = 0x100
SIOCGIFFLAGS = 0x8913
SIOCSIFFLAGS = 0x8914

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

ifr = ifreq()
ifr.ifr_ifrn = "eth4"

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

import fcntl

fcntl.ioctl(s.fileno(), SIOCGIFFLAGS, ifr) # G for Get

添加混杂标志:

ifr.ifr_flags |= IFF_PROMISC

并在界面上设置标志:

fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifr) # S for Set

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

ifr.ifr_flags &= ~IFF_PROMISC
fcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifr)

答案 1 :(得分:3)

还有另一种我想到的方式。也许不那么优雅,但似乎工作得很好。

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

# ifconfig eth0 promisc
# ifconfig eth0 -promisc

在接口上启用/禁用promisc模式(在本例中为eth0)。

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

import os
ret =  os.system("ifconfig eth0 promisc")
if ret == 0:
     <Do something>

欢迎以这种方式发表评论。