Lectura desde un dispositivo de red promiscuo
linux sockets (5)
Quiero escribir una herramienta de análisis en tiempo real para el tráfico inalámbrico.
¿Alguien sabe cómo leer desde un dispositivo promiscuo (o sniffing) en C?
Sé que necesitas tener acceso de root para hacerlo. Me preguntaba si alguien sabe qué funciones son necesarias para hacer esto. Los enchufes normales no parecen tener sentido aquí.
Puede usar la biblioteca pcap (vea http://www.tcpdump.org/pcap.htm ) que también es utilizada por tcpdump y Wireshark.
En Linux, utiliza un socket PF_PACKET para leer datos de un dispositivo sin procesar, como una interfaz de Ethernet que se ejecuta en modo promiscuo:
s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))
Esto enviará copias de cada paquete recibido hasta su socket. Sin embargo, es bastante probable que en realidad no desee todos los paquetes. El kernel puede realizar un primer nivel de filtrado utilizando BPF, el filtro de paquetes de Berkeley . BPF es esencialmente una máquina virtual basada en pila: maneja un pequeño conjunto de instrucciones tales como:
ldh = load halfword (from packet)
jeq = jump if equal
ret = return with exit code
El código de salida de BPF le dice al kernel si debe copiar el paquete al socket o no. Es posible escribir programas BPF relativamente pequeños directamente, usando setsockopt (s, SOL_SOCKET, SO_ATTACH_FILTER,). (ADVERTENCIA: El núcleo toma una estructura sock_fprog, no una struct bpf_program, no las mezcle o su programa no funcionará en algunas plataformas).
Para cualquier cosa razonablemente compleja, realmente quieres usar libpcap. BPF está limitado en lo que puede hacer, en particular en la cantidad de instrucciones que puede ejecutar por paquete. libpcap se ocupará de dividir un filtro complejo en dos partes, con el kernel realizando un primer nivel de filtrado y el código de espacio de usuario más capaz que arroja los paquetes que en realidad no quería ver.
libpcap también abstrae la interfaz del kernel de su código de aplicación. Linux y BSD usan API similares, pero Solaris requiere DLPI y Windows usa algo más.
Una vez tuve que escuchar en marcos brutos de ethernet y terminé creando un envoltorio para esto. Al llamar a la función con el nombre del dispositivo, ex eth0
obtuve un socket a cambio que estaba en modo promiscuo. Lo que debe hacer es crear un socket sin procesar y luego ponerlo en modo promiscuo. Así es como lo hice.
int raw_init (const char *device)
{
struct ifreq ifr;
int raw_socket;
memset (&ifr, 0, sizeof (struct ifreq));
/* Open A Raw Socket */
if ((raw_socket = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL))) < 1)
{
printf ("ERROR: Could not open socket, Got #?/n");
exit (1);
}
/* Set the device to use */
strcpy (ifr.ifr_name, device);
/* Get the current flags that the device might have */
if (ioctl (raw_socket, SIOCGIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not retrive the flags from the device./n");
exit (1);
}
/* Set the old flags plus the IFF_PROMISC flag */
ifr.ifr_flags |= IFF_PROMISC;
if (ioctl (raw_socket, SIOCSIFFLAGS, &ifr) == -1)
{
perror ("Error: Could not set flag IFF_PROMISC");
exit (1);
}
printf ("Entering promiscuous mode/n");
/* Configure the device */
if (ioctl (raw_socket, SIOCGIFINDEX, &ifr) < 0)
{
perror ("Error: Error getting the device index./n");
exit (1);
}
return raw_socket;
}
Luego, cuando tenga su zócalo, puede usar seleccionar para manejar los paquetes a medida que llegan.
WireShark en Linux tiene la capacidad de capturar la información de encabezado PLCP (protocolo de convergencia de capa física).