Python 套接字:在 Linux 中启用混杂模式 [英] Python Sockets: Enabling Promiscuous Mode in Linux

查看:25
本文介绍了Python 套接字:在 Linux 中启用混杂模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们知道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 中设置混杂模式?

解决方案

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

<预><代码>>>>从套接字导入 AF_NETLINK、SOCK_DGRAM、套接字>>>s = 套接字(AF_NETLINK,SOCK_DGRAM)>>>

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

或者,您可以使用 ioctl 的老派路线,遗憾的是,结果证明它相当简单.

首先使用ctypes定义ifreq结构:

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

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

导入套接字s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

然后从/usr/include 复制几个常量值,因为它们没有被 Python 暴露:

IFF_PROMISC = 0x100SIOCGIFFLAGS = 0x8913SIOCSIFFLAGS = 0x8914

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

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

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

import fcntlfcntl.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_PROMISCfcntl.ioctl(s.fileno(), SIOCSIFFLAGS, ifr)

We know that Python Allows enabling promiscuous mode under Windows through

s.ioctl(socket.SIO_RCVALL, socket.RCVALL_ON)

However, The RCVALL_* and SIO_* is only available in windows. Using C socket api, in Linux, one can use :

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

or through,

setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, PACKET_MR_PROMISC)

Is there any option in python socket API that allows us to set promiscuous mode in Linux?

解决方案

Use an AF_NETLINK socket to issue a request to turn on IFF_PROMISC. Python can construct AF_NETLINK sockets on Linux:

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

See the example at the end of the netlink(7) manual page for an example of how to issue a netlink request. You can use ctypes (or even struct) to construct the serialized nlmsghdr message to send over the netlink socket. You may also need it to call sendmsg and recvmsg, since Python still doesn't expose these APIs. Alternatively, there are some third-party modules available which expose these two APIs.

Alternatively, you can go the old school route of using ioctl, which sadly turns out to be rather simpler.

First define the ifreq structure using ctypes:

import ctypes

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

Then make a socket to use with the ioctl call:

import socket

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

Then copy a couple constant values out of /usr/include since they're not exposed by Python:

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

Create an instance of the ifreq struct and populate it to have the desired effect:

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

Populate the ifr_flags field with an ioctl call so that you don't clobber whatever flags are already set on the interface:

import fcntl

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

Add the promiscuous flag:

ifr.ifr_flags |= IFF_PROMISC

And set the flags on the interface:

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

To remove the flag, mask it off and set again:

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

这篇关于Python 套接字:在 Linux 中启用混杂模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆