Python Sockets: Enabling Promiscuous Mode in Linux

前端 未结 2 1279
轮回少年
轮回少年 2020-12-13 16:07

We know that Python Allows enabling promiscuous mode under Windows through

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

However, The RCVAL

相关标签:
2条回答
  • 2020-12-13 16:30

    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.

    0 讨论(0)
  • 2020-12-13 16:56

    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)
    
    0 讨论(0)
提交回复
热议问题