Python Sockets: habilitando el modo promiscuo en Linux

Sabemos que Python permite habilitar el modo promiscuo en Windows a través de

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

Sin embargo, el RCVALL_ * y SIO_ * solo están disponibles en Windows. Usando C socket api, en Linux, uno puede usar:

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

oa través de

 setsockopt(sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, PACKET_MR_PROMISC) 

¿Hay alguna opción en la API de socket python que nos permita configurar el modo promiscuo en Linux ?

Use un socket AF_NETLINK para emitir una solicitud para activar IFF_PROMISC . Python puede construir sockets AF_NETLINK en Linux:

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

Vea el ejemplo al final de la página del manual de netlink (7) para ver un ejemplo de cómo emitir una solicitud de netlink. Puede usar ctypes (o incluso struct ) para construir el mensaje nlmsghdr serializado para enviar a través del socket netlink. También puede necesitarlo para llamar a sendmsg y recvmsg , ya que Python aún no expone estas API . Alternativamente, hay algunos módulos de terceros disponibles que exponen estas dos API.

Alternativamente, puedes seguir la ruta de la vieja escuela de usar ioctl , que lamentablemente resulta ser bastante más simple.

Primero defina la estructura ifreq usando ctypes:

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

Luego haz un socket para usar con la ioctl :

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

Luego copie un par de valores constantes de / usr / include ya que no están expuestos por Python:

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

Cree una instancia de la estructura ifreq y rellénela para que tenga el efecto deseado:

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

ifr_flags campo ifr_flags con una ioctl para que no obstruya los indicadores que ya están establecidos en la interfaz:

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

Añade la bandera promiscua:

 ifr.ifr_flags |= IFF_PROMISC 

Y establece las banderas en la interfaz:

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

Para eliminar la bandera, cúbrala y ajústela de nuevo:

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

Hay otra manera en la que pensé. Tal vez no tan elegante pero parece funcionar bien.

En linux (con permisos de root), uno puede usar:

 # ifconfig eth0 promisc # ifconfig eth0 -promisc 

Para habilitar / deshabilitar el modo promisc en su interfaz (eth0 en este caso).

Entonces, en python (con permisos de root) uno podría usar:

 import os ret = os.system("ifconfig eth0 promisc") if ret == 0:  

Los comentarios son bienvenidos sobre esta forma de hacerlo.