raw sockets



  • Hallo!

    Ich mache gerade ein Projekt für die Uni. Dabei ist die Aufgabe einen MAC in einen bereits bestehenden Microcontroller zu integrieren. PHY befindet sich schon am Board. Hardware-mäßig (was auch die Hauptaufgabe ist) läuft alles glatt, jedoch habe ich Probleme bei der PC- Seite.
    Das Ding arbeitet nach IEEE 802.3. Im Datenblatt gibt es die genaue Spezifikation der Ethernet-Frames. Da es sich um normale Ethernet- Frames (ohne darüberliegendes Protokoll) handelt arbeite ich mit Raw Sockets. Leider habe ich damit überhaupt keine Erfahrung.

    Da ich die Hardware nur sehr begrenzt zur Verfügung habe, wollte ich einfach mal Ethernet- Frames zwischen 2 Notebooks (per LAN-Kabel verbunden) austauschen. Geht das so einfach? Also einfach LAN-Kabel drann und die 2 Programme laufen lassen?

    Hier die beiden Codes:

    einmal das Senden:

    int main() 
    {	
    	int sendRetVal = 0;
    	int sDescr = 0;
    	int len = 0;
    	int flags = 0;
    	char* msg = NULL;
    	int i = 0;
    
    	MacAddress localMac;
    	MacAddress destMac = {0x00,0x1B,0x38,0x3D,0x39,0xD6};
    
    	struct sockaddr_ll destAddr;
    	struct ifreq ifr;
    
    	short int etherTypeT = htons(0x8200);
    
    	char buffer[BUFFER_LEN];
    	char data[DATA_LEN];
    
    	memset(buffer,0x00,BUFFER_LEN);
    
    	sDescr = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
    	if (sDescr < 0)
    	{
    		printf("Error! socket() call failed (error no: %d \"%s\").\n",errno,strerror(errno));
    		exit(1);
    	}
    
    	memset(&ifr,0x00,sizeof(ifr));
    	strcpy(ifr.ifr_name,"eth0");
    	ioctl(sDescr,SIOCGIFHWADDR,&ifr);
    
    	for (i = 0; i < MAC_ADDR_LEN; i ++)
    	{
    		localMac[i] = (unsigned char)ifr.ifr_hwaddr.sa_data[i];
    	}
    
    	memset(&destAddr,0,sizeof(struct sockaddr_ll));
    	destAddr.sll_family = PF_PACKET;
    	destAddr.sll_protocol = htons(ETH_P_ALL);
    	destAddr.sll_halen = 6;
    	destAddr.sll_ifindex = 2;
    
    	memcpy(&(destAddr.sll_addr),destMac,MAC_ADDR_LEN);
    
    	/* header */
    	memcpy(buffer,destMac,MAC_ADDR_LEN);
    	memcpy(buffer+MAC_ADDR_LEN,localMac,MAC_ADDR_LEN);
    	memcpy(buffer+2*MAC_ADDR_LEN,&etherTypeT,sizeof(etherTypeT));
    
    	/* data */
    	for (i = 0; i < DATA_LEN; i ++)
    	{
    		data[i] = (char)i;
    	}
    
    	memcpy(buffer+(sizeof(etherTypeT)+(2*MAC_ADDR_LEN)),data,DATA_LEN);
    
    	printf("here\n");
    
    	for (i = 0; i < 1000; i ++)
    	{
    		printf("sending frame %d\n",i);
    
    		sendRetVal = sendto(sDescr,msg,len,flags,(struct sockaddr*)&destAddr,sizeof(struct sockaddr_ll));
    		if (sendRetVal < 0)
    		{
    			printf("Error! sendto() call failed (error no: %d \"%s\").\n",errno,strerror(errno));
    			exit(1);
    		}
    
    		else
    		{
    			printf("sent\n");
    		}
    
    		usleep(1000);
    	}
    
     	return 0;
    }
    

    und einmal das Empfangen:

    int main() 
    {
    	int i = 0;
    	int sDescr = 0;
    	int len = 0;
    	int fn = 0;
    
    	char buffer[ETH_FRAME_LEN];
    
    	memset(buffer,'\0',ETH_FRAME_LEN);
    
    	sDescr = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
    	if (sDescr < 0)
    	{
    		printf("Error! socket() call failed (error no: %d \"%s\").\n",errno,strerror(errno));
    		exit(1);
    	}
    
    	printf("start listening!\n");
    
    	for(;;)
    	{
    		len = recvfrom(sDescr,buffer,ETH_FRAME_LEN,0,(struct sockaddr*)0,(socklen_t*)0);
    
    		if (len < 0)
    		{
    			printf ("error receiving frame!\n");
    		}
    
    		else
    		{
    			printf("frame %d: ",fn);
    
    			for (i = 0; i < len; i ++)
    			{
    				printf("%02X",buffer[i]);
    			}
    
    			printf("\n");
    			fn ++;
    		}
    	}
    
     	return 0;
    }
    

    Leider kommen die Frames nicht an. Jedoch wenn ich im Netz surfe werden vom Programm das die Frames empfangen soll Daten empfangen. Muss ich beim BS noch irgendwelche Einstellungen vornehmen? Oder liegt der Fehler wo anders?

    Danke im Voraus 🙂



  • Ich habe jetzt die Sender-Seite noch um ein bind erweitert. Es liefert zwar keine Fehler, jedoch wird immer noch nichts empfangen...

    int main() 
    {	
    	int sendRetVal = 0;
    	int sDescr = 0;
    	int len = 0;
    	int flags = 0;
    	char* msg = NULL;
    	int i = 0;
    
    	MacAddress localMac;
    	MacAddress destMac = {0x00,0x1B,0x38,0x3D,0x39,0xD6};
    
    	struct sockaddr_ll destAddr;
    	struct ifreq ifr;
    
    	short int etherTypeT = htons(0x8200);
    
    	char buffer[BUFFER_LEN];
    	char data[DATA_LEN];
    
    	int bindRes = 0;
    	int if_index = 0;
    
    	memset(buffer,0x00,BUFFER_LEN);
    
    	sDescr = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
    	if (sDescr < 0)
    	{
    		printf("Error! socket() call failed (error no: %d \"%s\").\n",errno,strerror(errno));
    		exit(1);
    	}
    
    	memset(&ifr,0x00,sizeof(ifr));
    	strcpy(ifr.ifr_name,"eth0");
    
    	if (ioctl(sDescr,SIOCGIFINDEX,&ifr) < 0)
    	{
    		printf("Error! ioctl() call failed (error no: %d \"%s\").\n",errno,strerror(errno));
    		exit(1);
    	}
    
    	if_index = ifr.ifr_ifindex;
    
    	if (ioctl(sDescr,SIOCGIFHWADDR,&ifr) < 0)
    	{
    		printf("Error! ioctl() call failed (error no: %d \"%s\").\n",errno,strerror(errno));
    		exit(1);
    	}
    
    	for (i = 0; i < MAC_ADDR_LEN; i ++)
    	{
    		localMac[i] = (unsigned char)ifr.ifr_hwaddr.sa_data[i];
    	}
    
    	memset(&destAddr,0,sizeof(struct sockaddr_ll));
    	destAddr.sll_family = AF_PACKET;
    	destAddr.sll_protocol = htons(ETH_P_ALL);
    	destAddr.sll_halen = 6;
    	destAddr.sll_ifindex = if_index;
    
    	destAddr.sll_pkttype = PACKET_OTHERHOST|PACKET_BROADCAST|PACKET_MULTICAST|PACKET_HOST;
    
    	memcpy(&(destAddr.sll_addr),destMac,MAC_ADDR_LEN);
    
    	bindRes = bind(sDescr,(struct sockaddr*)&destAddr,sizeof(struct sockaddr_ll));
    	if (bindRes < 0)
    	{
    		printf("Error! bind() call failed (error no: %d \"%s\").\n",errno,strerror(errno));
    		exit(1);
    	}
    
    	/* header */
    	memcpy(buffer,destMac,MAC_ADDR_LEN);
    	memcpy(buffer+MAC_ADDR_LEN,localMac,MAC_ADDR_LEN);
    	memcpy(buffer+2*MAC_ADDR_LEN,&etherTypeT,sizeof(etherTypeT));
    
    	/* data */
    	for (i = 0; i < DATA_LEN; i ++)
    	{
    		data[i] = (char)i;
    	}
    
    	memcpy(buffer+(sizeof(etherTypeT)+(2*MAC_ADDR_LEN)),data,DATA_LEN);
    
    	for (i = 0; i < 1000; i ++)
    	{
    		printf("sending frame %d\n",i);
    
    		sendRetVal = sendto(sDescr,msg,len,flags,(struct sockaddr*)&destAddr,sizeof(struct sockaddr_ll));
    		if (sendRetVal < 0)
    		{
    			printf("Error! sendto() call failed (error no: %d \"%s\").\n",errno,strerror(errno));
    			exit(1);
    		}
    
    		else
    		{
    			printf("sent\n");
    		}
    
    		usleep(1000);
    	}
    
     	return 0;
    }
    


  • Du verwendest auch brav Wireshark zum Debugging?



  • Wireshark?



  • Habe jetzt auf beiden Notebooks Wireshark. Wenn ich es auf beiden Notebooks starte und dann die beiden Programme ausführe, friert das BS auf dem Notebook mit dem Programm zum Senden ein und Caps Lock blinkt.



  • Lag wohl am Notebook. Verwende jetzt ein anderes.

    Danke für den Tipp mit Wireshark, auf der Empfängerseite kommen Frames an, jedoch bin ich mir noch nicht sicher ob sie richtig ankommen und das Programm zum empfangen funktioniert (noch) nicht. Zumindest weiß ich jetzt wo ich den Fehler suchen muss 🙂
    Falls irgendjemand den Fehler findet wäre ich dankbar für Hinweise, wenn nicht poste ich den Code wenn es funktioniert. Vielleicht hat ja noch jemand Probleme mit raw-sockets 😃



  • Wieso nimmst du zwei Computer? Schalte doch das Gehirn ein und verwende virtuelle Maschinen.



  • Studenten sind halt keine Praktiker, weder vor noch nach dem Diplom.



  • Weil ich sie gerade zur Hand hatte und nur schnell testen wollte ob es funktioniert. Das geht schneller als eine virtuelle Maschine aufzusetzen 😉

    Mitleid schrieb:

    Studenten sind halt keine Praktiker, weder vor noch nach dem Diplom.

    😃 und du als Praktiker hast den echt dummen Fehler in meinem Code nicht gleich gesehen?

    So einen dummen Fehler habe ich schon lange nicht mehr gemacht...
    Seht euch mal msg und len an die ich in der Funktion "sendto" verwende. msg durch buffer ersetzen und len berechnen und schon funktioniert es 🙂



  • @ JJMax

    du hast in deinem Code den VariablenTyp MacAddress verwendet, welche
    header-Dateien muss ich einbinden um diesen Variablentyp zu verwenden?



  • Kristallfee schrieb:

    du hast in deinem Code den VariablenTyp MacAddress verwendet, welche header-Dateien muss ich einbinden um diesen Variablentyp zu verwenden?

    CamelCase ist in den meisten (Netzwerk-)Standardlibraries eher unüblich, sieht eher nach einem simplen Byte-Array aus, das sich der User selbst definiert hat. Wahrscheinlich unsigned char oder so.


Anmelden zum Antworten