2012-08-29 14 views
5

Sto scrivendo un programma con un raw socket in modalità promiscua e ho bisogno del socket raw non annusare il pacchetto che invio. Ho bisogno di leggere solo i dati sul cavo rx ethernet (non il cavo tx). È possibile?Raw Socket modalità promiscua non annusando quello che scrivo

Grazie mille.

+1

Quale sistema operativo stai utilizzando? – Eloff

+0

Sto usando linux. –

+0

State mandando e annunciando sulla stessa macchina? questo é un problema. Avrai bisogno di 2 macchine per questo. – Matt

risposta

6

La soluzione è cercare nel pacchetto di lettura se è un PACKET_OUTGOING. Usando questa opzione puoi scegliere il pacchetto che inserisci nel cavo tx ethernet e il pacchetto che leggi dal filo rx.

aprire il socket in modalità promiscua:

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; 
//... 

e leggere. Ora, possiamo distinguere tra il cavo Ethernet Rx e 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. 
} 

Ed è tutto. Usandolo non leggo i dati che scrivo. Evito il loop quando copio i frame della rete 1 sulla rete 2 ei frame della rete 2 sulla rete 1.

0

È possibile filtrare facilmente le informazioni provenienti dall'indirizzo IP dell'utente e escluderle dall'elenco.

+0

Abbiamo due reti e un PC con due dispositivi ethernet (eth0 ed eth1). Il primo è connecto alla prima rete e il secondo alla seconda rete. Ci piace costruire un bridge software a livello 2; utilizzando una presa raw in modalità promiscua leggiamo tutto il traffico della rete 1 e lo copia nella rete 2 e viceversa. Tutto finisce in un ciclo infinito perché i fotogrammi copiati in rete 1 sono copiati in rete 2 e copiati in rete 1 ... Non dobbiamo annusare i frame che scriviamo e questi frame sono al livello 2 (con mac) e provengono da qualsiasi macchina in un full nerwork. –

+0

Non puoi semplicemente fare il tuo filtraggio a livello MAC, allora?Non è troppo difficile solo guardare l'indirizzo MAC e saltare quelli che sai che hai inviato. Cosa mi manca? – kmort

+0

Questo software è utilizzato per fare un ponte tra la rete tramite un collegamento radio. Il pacchetto che ho letto nella rete 1 viene inviato tramite un collegamento radio ad un altro computer (pacchetto in una connessione UDP), unpacket e scrittura nella rete 2 (e viceversa). Pertanto, non posso usare le funzionalità di bridging di linux :-(Credo che ... –

3

È necessario creare il (BSD Packet Filter) Filtro BPF che corrispondono ai pacchetti in entrata:

/* 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; 

E poi il tuo raw socket, e legare e ...:

/* 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 */ 
} 

EDIT: Se vuoi filtrare per Indirizzo Mac, è semplice, genera il tuo filtro in questo modo (io uso il mio indirizzo Mac qui):

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

Stiamo lavorando nel livello 2, con indirizzo MAC. Non abbiamo l'indirizzo IP –

+0

@ JoséMaríaB: beh, questo non cambia nulla, basta filtrare dal tuo indirizzo Mac host.Vedi il mio edit – TOC

+0

Grazie mille. è più facile usare la soluzione PACKET_OUTGOING per questo caso (Merci beaucoup. Je pence que c'est più facile à utiliser la solution PACKET_OUTGOING pour ce cas :-)) –

0

Purtroppo, Linux non offre alcuna opzione per specificare di non ricevere pacchetti in uscita per un socket non elaborato.

Se è consentita la ricostruzione del kernel di Linux, suggerirei di applicare semplicemente il patch al kernel con packet_socket_type.patch.

e al programma utente, si specifica il tipo di pacchetto che si desidera ricevere in questo modo.

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, questa è la soluzione che risolve veramente il problema.

Problemi correlati