2012-08-29 6 views
5

Ich schreibe ein Programm mit einem Raw-Socket im Promiscuous-Modus und ich brauche den Raw-Socket nicht schnüffeln das Paket, das ich sende. Ich muss nur die Daten über das Ethernet-RX-Kabel lesen (nicht das TX-Kabel). Es ist möglich?Raw Socket Promiscuous-Modus nicht schnüffeln, was ich schreibe

Vielen Dank.

+1

Welches Betriebssystem verwenden Sie? – Eloff

+0

Ich benutze Linux. –

+0

Schicken und schnüffeln Sie beide auf derselben Maschine? das ist ein Problem. Sie benötigen dafür 2 Maschinen. – Matt

Antwort

6

Die Lösung ist, in das gelesene Paket zu schauen, wenn es ein PACKET_OUTGOING ist. Mit dieser Option können Sie das Paket, das Sie in die Ethernet-TX-Leitung legen, und das Paket, das Sie von der RS-Leitung lesen, unterscheiden.

Öffnen Sie den Sockel in den Promiscuous-Modus:

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

und lesen. Nun können wir zwischen den Rx und Tx Ethernet-Kabel unterscheiden:

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. 
} 

Und es ist alles. Ich lese nicht die Daten, die ich schreibe. Ich vermeide die Schleife, wenn ich die Netzwerk 1 Frames zu Netzwerk 2 und die Netzwerk 2 Frames zu Netzwerk 1 kopiere.

0

Sie können leicht nach Dingen filtern, die von Ihrer IP-Adresse kamen, und sie einfach von Ihrer Liste ausschließen.

+0

Wir haben zwei Netzwerke und einen PC mit zwei Ethernet-Geräten (eth0 und eth1). Der erste ist eine Verbindung zum ersten Netzwerk und der zweite zum zweiten Netzwerk. Wir bauen gerne eine Software-Brücke auf Level 2; Mit einem rohen Socket im Promiscuous-Modus lesen wir den gesamten Verkehr des Netzwerks 1 und kopieren ihn in das Netzwerk 2 und umgekehrt. Alles, was in einer Endlosschleife endet, weil die Frames, die wir in Netzwerk 1 kopieren, in Netzwerk 2 kopiert und nach Netzwerk 1 kopiert werden ... Wir müssen die Frames, die wir schreiben, nicht schnüffeln und diese Frames sind auf Layer 2 (mit Mac) und sind von jeder Maschine in einem vollen Netzwerk. –

+0

Können Sie nicht einfach auf MAC-Ebene filtern?Es ist nicht schwer, nur die MAC-Adresse zu betrachten und die zu überspringen, von denen Sie wissen, dass Sie sie gesendet haben. Was vermisse ich? – kmort

+0

Diese Software wird verwendet, um eine Brücke zwischen dem Netzwerk über eine Funkverbindung herzustellen. Das im Netzwerk 1 gelesene Paket wird über eine Funkverbindung an einen anderen Computer (Paket in einer UDP-Verbindung) gesendet, entpackt und in das Netzwerk 2 geschrieben (und umgekehrt). Daher kann ich die Linux-Bridging-Fähigkeiten nicht nutzen :-(glaube ich ... –

3

Sie benötigen die BPF (BSD Packet Filter) Filter, um eingehende Pakete entsprechen zu erstellen:

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

Und dann Ihre RAW-Buchse, und binden und ...:

/* 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: Wenn Sie nach Mac-Adresse filtern möchten, ist es einfach, generieren Sie Ihren Filter so (ich benutze meine Mac-Adresse hier):

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

Wir arbeiten in Schicht 2, mit MAC-Adresse Wir haben keine IP-Adresse –

+0

@ JoséMariaB: Nun, das ändert nichts nichts nur Filter von Ihrem Host Mac Adresse.Siehe meine Bearbeitung – TOC

+0

Vielen Dank, denke ich ist einfacher, die PACKET_OUTGOING Lösung für diesen Fall zu verwenden (Merci beaucoup. Je pense que c'est plus facile à utiliser la Lösung PACKET_OUTGOING pour ce cas :-)) –

0

Leider bietet Linux keine Optionen um zu spezifizieren, keine ausgehenden Pakete für einen rohen Socket zu empfangen.

Wenn der Linux-Kernel neu erstellt werden soll, würde ich vorschlagen, nur den Kernel mit packet_socket_type.patch zu patchen.

und im Benutzerprogramm geben Sie an, welche Art von Paket Sie so erhalten möchten.

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, das ist die Lösung, die das Problem wirklich löst.

Verwandte Themen