使用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 套接字发送。您可能还需要调用sendmsg 和recvmsg,因为Python still doesn't expose these APIs。或者,有一些 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"
使用ioctl 调用填充ifr_flags 字段,这样您就不会破坏接口上已经设置的任何标志:
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)