Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Sockets: Enabling Promiscuous Mode in Linux

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?

like image 514
TanB Avatar asked May 20 '11 04:05

TanB


People also ask

What is promiscuous mode Linux?

In an Ethernet local area network (LAN), promiscuous mode ensures that every data packet that is transmitted is received and read by a network adapter. This means the adapter does not filter packets. Instead, it passes each packet on to the operating system (OS) or any monitoring application installed on the network.

What is the use of socket Recvfrom () method?

recvfrom(data, address) − This method receives data from the socket. Two pair (data, address) value is returned by this method. Data defines the received data and address specifies the address of socket sending the data.

What is Setsockopt Python?

DESCRIPTION. The setsockopt() function shall set the option specified by the option_name argument, at the protocol level specified by the level argument, to the value pointed to by the option_value argument for the socket associated with the file descriptor specified by the socket argument.


2 Answers

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)
like image 71
Jean-Paul Calderone Avatar answered Nov 10 '22 07:11

Jean-Paul Calderone


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.

like image 30
TanB Avatar answered Nov 10 '22 05:11

TanB