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, ðreq);
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)
There is another way I thought of. Maybe not as elegant but seems to work fine.
In linux (with root permissions), one can use :
# ifconfig eth0 promisc
# ifconfig eth0 -promisc
To enable/ disable promisc mode on your interface (eth0 in this case).
So, in python (with root permissions) one could use :
import os
ret = os.system("ifconfig eth0 promisc")
if ret == 0:
<Do something>
Comments are welcome on this way of doing it.