2012-08-29 16 views
5

Estoy escribiendo un programa con un Socket Raw en modo promiscuo y necesito que el socket raw no olfatee el paquete que envío. Necesito leer solo los datos a través del cable ethernet rx (no el cable tx). Es posible?Modo promiscuo de Socket Raw no olfateando lo que escribo

Muchas gracias.

+1

¿Qué sistema operativo está utilizando? – Eloff

+0

Estoy usando linux. –

+0

¿Están enviando y olfateando en la misma máquina? eso es un problema. Necesitarás 2 máquinas para esto. – Matt

Respuesta

6

La solución es buscar en el paquete de lectura si es un PACKET_OUTGOING. Usando esta opción, puede diferenciar el paquete que coloca en el cable ethernet tx y el paquete que lee del cable rx.

abrir el socket en modo promiscuo:

char* i = "eth0"; 
int fd; 
struct ifreq ifr; 
struct sockaddr_ll interfaceAddr; 
struct packet_mreq mreq; 

if ((fd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL))) < 0) 
    return -1; 

memset(&interfaceAddr,0,sizeof(interfaceAddr)); 
memset(&ifr,0,sizeof(ifr)); 
memset(&mreq,0,sizeof(mreq)); 

memcpy(&ifr.ifr_name,i,IFNAMSIZ); 
ioctl(fd,SIOCGIFINDEX,&ifr); 

interfaceAddr.sll_ifindex = ifr.ifr_ifindex; 
interfaceAddr.sll_family = AF_PACKET; 

if (bind(fd, (struct sockaddr *)&interfaceAddr,sizeof(interfaceAddr)) < 0) 
    return -2; 


mreq.mr_ifindex = ifr.ifr_ifindex; 
mreq.mr_type = PACKET_MR_PROMISC; 
mreq.mr_alen = 6; 

if (setsockopt(fd,SOL_PACKET,PACKET_ADD_MEMBERSHIP, 
    (void*)&mreq,(socklen_t)sizeof(mreq)) < 0) 
     return -3; 
//... 

y leer. Ahora, podemos diferenciar entre el cable ethernet Rx y Tx:

unsigned char buf[1500]; 
struct sockaddr_ll addr; 
socklen_t addr_len = sizeof(addr); 
n = recvfrom(fd, buf, 2000, 0, (struct sockaddr*)&addr, &addr_len); 
if (n <= 0) 
{ 
    //Error reading 
} 
else if (addr.sll_pkttype == PACKET_OUTGOING) 
{ 
    //The read data are not writing by me. 
    //Use only this data to copy in the other network. 
} 

Y es todo. Utilicándolo no leo los datos que escribo. Evito el bucle cuando copio la red 1 fotogramas a la red 2 y la red 2 fotogramas a la red 1.

0

Puede filtrar fácilmente las cosas que provienen de su dirección IP y simplemente excluirlas de su lista.

+0

Tenemos dos redes y una PC con dos dispositivos ethernet (eth0 y eth1). El primero es connecto a la primera red y el segundo a la segunda red. Nos gusta construir un puente de software en el nivel 2; utilizando un socket sin procesar en modo promiscuo leemos todo el tráfico de la red 1 y lo copiamos en la red 2 y viceversa. Todo termina en un bucle infinito porque los cuadros que copiamos en la red 1 son copiar a la red 2 y copiar a la red 1 ... No necesitamos olfatear los marcos que escribimos y estos cuadros están en la capa 2 (con mac) y son de cualquier máquina en un nerwork completo. –

+0

¿No puedes simplemente hacer tu filtrado en el nivel MAC entonces?No es demasiado difícil simplemente mirar la dirección MAC y omitir las que sabe que ha enviado. ¿Qué me estoy perdiendo? – kmort

+0

Este software se utiliza para hacer un puente entre a la red a través de un enlace de radio. El paquete que leo en la red 1 se envía a través de un enlace de radio a otra computadora (paquete en una conexión UDP), desempaqueta y escribe en la red 2 (y viceversa). Por lo tanto, no puedo usar las capacidades de puente de Linux :-(Creo que ... –

3

Es necesario crear la (BSD filtro de paquetes) de filtro BPF que corresponden a los paquetes entrantes:

/* To obtain the BPF filter corresponding to incoming traffic: 
* sudo tcpdump -dd -i eth0 dst host YOUR_IP_ADDRESS and not src host YOUR_IP_ADDRESS 
* The filter given below is what i get on my local machine (192.168.1.7): 
* sudo tcpdump -dd -i eth0 dst host 192.168.1.7 and not src host 192.168.1.7 
*/ 
struct sock_filter incoming_filter[] = {  
    { 0x28, 0, 0, 0x0000000c }, 
    { 0x15, 0, 4, 0x00000800 }, 
    { 0x20, 0, 0, 0x0000001e }, 
    { 0x15, 0, 9, 0xc0a80107 }, 
    { 0x20, 0, 0, 0x0000001a }, 
    { 0x15, 7, 6, 0xc0a80107 }, 
    { 0x15, 1, 0, 0x00000806 }, 
    { 0x15, 0, 5, 0x00008035 }, 
    { 0x20, 0, 0, 0x00000026 }, 
    { 0x15, 0, 3, 0xc0a80107 }, 
    { 0x20, 0, 0, 0x0000001c }, 
    { 0x15, 1, 0, 0xc0a80107 }, 
    { 0x6, 0, 0, 0x0000ffff }, 
    { 0x6, 0, 0, 0x00000000 }, 
}; 

int s; 
struct sockaddr_ll sock_address; 
struct sock_fprog prog; 

/* Init the program filter */ 
prog.len = 14; 
prog.filter = incoming_filter; 

Y entonces su conector directo, y de vinculación y ...:

/* Create the raw socket */ 
s = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 
if (s < 0) 
{ 
    /* Error handling */ 
} 

/* Build our socket */ 
sock_address.sll_family = AF_PACKET; 
sock_address.sll_protocol = htons(ETH_P_IP); 
sock_address.sll_ifindex = if_nametoindex(your_interface_name); 

/* Bind */ 
if (bind(s, (struct sockaddr*)&sock_address, sizeof(sock_address)) < 0) 
{ 
    /* Error handling */ 
} 

/* Apply the filter */ 
if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER, &prog, sizeof(prog)) < 0) 
{ 
    /* Error handling */ 
} 

/* Infinite listen loop */ 
while (1) 
{ 

    /* Handle received packet */ 
} 

EDITAR: Si desea filtrar por dirección MAC, es simple, genere su filtro de esta manera (uso mi dirección Mac aquí):

sudo tcpdump -dd -i eth0 ether dst 00:0f:b0:68:0f:92 and not ether src 00:0f:b0:68:0f:92 
{ 0x20, 0, 0, 0x00000002 }, 
{ 0x15, 0, 7, 0xb0680f92 }, 
{ 0x28, 0, 0, 0x00000000 }, 
{ 0x15, 0, 5, 0x0000000f }, 
{ 0x20, 0, 0, 0x00000008 }, 
{ 0x15, 0, 2, 0xb0680f92 }, 
{ 0x28, 0, 0, 0x00000006 }, 
{ 0x15, 1, 0, 0x0000000f }, 
{ 0x6, 0, 0, 0x0000ffff }, 
{ 0x6, 0, 0, 0x00000000 }, 
+0

Estamos trabajando en la capa 2, con la dirección MAC. No tenemos la dirección IP –

+0

@ JoséMaríaB: Bueno, esto no cambia nada, solo filtre por su dirección de host de Mac. Vea mi edición – TOC

+0

Muchas gracias. es más fácil usar la solución PACKET_OUTGOING para este caso (Merci beaucoup. Je pense que c'est plus facile à utiliser la solution PACKET_OUTGOING pour ce cas :-)) –

0

Lamentablemente, Linux no ofrece ninguna opción para especificar que no se reciben paquetes salientes para un socket sin formato.

Si está permitido reconstruir el kernel de Linux, sugeriría simplemente parchear el kernel con packet_socket_type.patch.

y en el programa de usuario, especifica qué tipo de paquete le gustaría recibir de esta manera.

int mask=0; 
mask = PACKET_MASK_ANY & ~(1<<PACKET_OUTGOING) & ~(1 << PACKET_LOOPBACK); 
setsockopt(raw_sock, SOL_PACKET, PACKET_RECV_TYPE, &mask, sizeof(mask)); 

IMO, esta es la solución que realmente resuelve el problema.

Cuestiones relacionadas