TP4 : Réseaux locaux - transmission et analyse des trames Ethernet (sur architectures x86 et ARM) Dans ce TP nous allons écrire/utiliser des applications de transfert des messages et des fichiers directemment au niveau de la couche physique Ethernet. La configuration du TP est basée sur 6 ordinateurs PC traditionnels (architecture x86) et 6 cartes Raspberry-Pi conçus sur l'architecture ARM. Le système d'exploitation est Ubuntu (Debian) pour les PC et Raspbian (Debian) pour les Raspberry PI. L'ensemble est connecté en réseau local avec les adresses IP distribuées dynamiquement par le protocole DHCP. Le développement de 2 applications : 1. Emission/diffusion et réception des fichiers 2. Sniffing des trames Ethernet avec les paquets IP doit être réalisé en mode root. Seulement l'utilisateur root a les droits d'exploitation de l'interface Ethernet par le biais de la programmation avec raw-sockets. Nous allons donc contourner la pile de protocoles (Ethernet/IP/TCP-UDP) pour s'attaquer directemment à la couche physique. En plus nous allons communiquer entre les systèmes basés sur les architectures matérielles différentes : x86 et ARM. Avant de se lancer dans la programmation nous proposons de lire le texte suivant concernant l'interface de programmation raw-sockets.
Introduction à la programmation avec l'api Raw-Sockets Dans les TP précédants nous avons dévellopé un certain nombre d'applications s'appuyant sur les primitives socket fonctionnant au niveau de la couche de transport en mode datagramme (protocole UDP) et en mode connecté (protocole TCP). Un programmeur avec les droits de root peut ếgalement accéder aux niveaux inférieurs de la pile TCP- UDP/IP/Ethernet par le biais des mécanismes raw-socket. On commence par la création d'un socket en mode raw: int s; s = socket(pf_packet, SOCK_RAW, htons(eth_p_all)); Le socket s peut fonctionner directement au niveau des paquets envoyés/réçus par le protocole Ethernet. Dans une trame Ethernet on peut insérer un paquet IP et un segment TCP ou un datagramme UDP. Dans ce contexte on peut, soit suivre les standards Internet et reproduire le fonctionnement des protocoles IP/TCP-UDP soit développer sa propre pile de protocoles. Envoi d'une trame Ethernet L'envoi d'une trame Ethernet nécessite la préparation de l'adresse source (6 octets), l'adresse de destination (6 octets), le type de protocole utilisateur (2 octets) plus les données utilisateur à transmettre par la trame. Fig.1. Trame Ethernet
Rappelons qu'une trame Ethernet est composée: de 2 adresses (source et destination) de 6 octets, d'un champs de contrôle de 2 octets, d'un champs de données de min 46 et max 1500 octets, et de la somme de test sur 4 octet qui est générée automatiquement par le l'interface. La structure ci-dessous doit être préparée avant son utilisation dans la fonction sendto(). struct sockaddr_ll destaddr; // addresse d'un socket au niveau de lien Les adresses Ethernet peuvent être préparées/initialisées comme suit: MacAddress localmac = 0x00,0x00,0x00,0x00,0x00,0x00; //MacAddress localmac = 0x00,0x17,0xB3,0x00,0xa0,0x20; MacAddress destmac = 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; //MacAddress destmac= 0x00,0xB0,0xD0,0x4C,0xD5,0xC6; La trame avec ses données est préparée dans un tampon: char buffer[buffer_len]; avant son utilisation la structure destaddr et le buffer doivent être initialisés par: memset(&destaddr, 0, sizeof(struct sockaddr_ll)); memset(buffer, 0, BUFFER_LEN); Puis la structure destaddr doit être remplie par: 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); Ensuite nous préparons l'en-tête de la trame: short int ethertypet = htons(0x8200); // champs de controle memcpy(buffer,destmac,mac_addr_len); memcpy((buffer+mac_addr_len),localmac,mac_addr_len); memcpy((buffer+(2*mac_addr_len)),&(ethertypet),sizeof(ethertypet)); Pour finir la création de la trame nous y ajoutons nos données (mes_data): memcpy((buffer+ethertype_len+(2*mac_addr_len)),mes_data,len); Enfin la trame est envoyée par la fonction sendto(): int tl= 14+len; int ssockll = sizeof(struct sockaddr_ll); sendto(sockfd,buffer,tlen,0,(struct sockaddr *)&(destaddr),ssockll);
Réception d'une trame Ethernet La réception d'une trame Ethernet nécessite la préparation de l'interface qui doit capter les trames. Cet interface peut fonctionner en mode normal ou mode de promiscuité. Dans le mode normal seulement les trames destinées à cette interface serons captées par la station (les trames en diffusion inclues). Dans le mode de promiscuité une interface peut capter/sniffer toutes les trames. Dans chaque cas il faut identifier (bind) l'interface à utiliser par la captage des trames. Voici les éléménts d'un programme permettant de capter les trames envoyées sur l'interface donnée avec l'adressage UNICAST et l'adressage BROADCAST. Réception en mode normal La fonction de la création d'un socket en mode raw: int CreateRawSocket(int protocol) int rs; if((rs = socket(pf_packet,sock_raw,htons(protocol)))== 1) printf("error creating raw socket: "); exit( 1); return rs; La fonction de la réception d'une trame dans le buffer: unsigned char* ReceiveRawEth(int sd) unsigned char* buffer = (unsigned char*)malloc(eth_frame_len); memset(buffer, '\0', ETH_FRAME_LEN); // frame buffer reset int l = 0; // frame buffer length l=recvfrom(sd,buffer,eth_frame_len,0,(struct sockaddr *)0,(int*)0); return buffer;
Réception en mode de promiscuité Pour effectuer la lecture de toutes les trames nous avons besoin de mettre l'interface Ethernet en mode de fonctionnement en promiscuité. L'interface doit être explicitement liée au socket avant l'application du mode en promiscuité. Ci-dessous la fonction qui crée et lie le socket à l'interface Ethernet spécifiée (bind) et qui ajoute le mode de promiscuité. La fonction possède 1 argument: nom de l'interface à sniffer. int CreatePromiscuousSocket(char *name) int sd; struct ifreq ifr; struct sockaddr_ll interfaceaddr; struct packet_mreq mreq; if ((sd = socket(pf_packet,sock_raw,htons(eth_p_all))) < 0) return 1; // clearing the interfaceaddr link layer socket address memset(&interfaceaddr,0,sizeof(interfaceaddr)); // clearing the ifr interface control registers memset(&ifr,0,sizeof(ifr)); // clearing mreq packet control registers memset(&mreq,0,sizeof(mreq)); // preparing the interface name memcpy(&ifr.ifr_name,name,ifnamsiz); // setting the interface name to find the interface index ioctl(sd,siocgifindex,&ifr); // setting the interface index interfaceaddr.sll_ifindex = ifr.ifr_ifindex; // setting the address family for interface interfaceaddr.sll_family = AF_PACKET; // binding the socket to the identified interface if (bind(sd, (struct sockaddr *)&interfaceaddr,sizeof(interfaceaddr)) < 0) return 2; // preparing the interface index in packet control mreq.mr_ifindex = ifr.ifr_ifindex; // preparing the promiscuous mode for packet sniffing mreq.mr_type = PACKET_MR_PROMISC; // setting the MAC address size mreq.mr_alen = 6; // setting the promiscuous mode to the interface for packet sniffing if (setsockopt(sd,sol_packet,packet_add_membership, (void*)&mreq,(socklen_t)sizeof(mreq)) < 0) return 3; return sd;
Dans la fonction principale main() nous pouvons lire/capter les paquets Ethernet par la fonction recvfrom(): int len; unsigned char buffer[2000]; struct sockaddr_ll paddr; int spaddr = sizeof(packet_info); len = recvfrom(raw,buffer,2000,0,(struct sockaddr*)&paddr,&spaddr); Le paquet est reçu dans le buffer, la taille de la trame réçue est enregistrée dans la varaible len. La fonction suivante permet de visualiser/imprimer le contenu de la trame en caractères héxadécimaux: void PrintPacketInHex(unsigned char *packet, int len, int com) unsigned char *p = packet; int beg,end,num; int ip=0; int udp=0,tcp=0; static int count=0; count++; beg=0;end=0; ip=(*(packet+12)==0x08 && *(packet+13)==0x00); //IP protocol in ETH frame udp= ip && (*(packet+23)==0x11); // UDP protocol in IP packet tcp= ip && (*(packet+23)==0x06); // TCP protocol in IP packet switch (com) case 0: beg=0;end=len;break; // print all packet case 1: beg=0;end=13;break; // print header case 2: beg=0;end=5;break; // print destination address case 3: beg=6;end=11;break; // print source address case 4: beg=14;end=len 14;break; // print data only case 5: if(ip)beg=14;end=33;;break; // print IP header 8 bytes case 6: if(udp)beg=34;end=41;;break; // print UDP header 8 bytes case 7: if(tcp)beg=34;end=53;;break; // print TCP header 20 bytes // Exercise: here you put your modes: // 5 IP header // 6 IP/UDP header // 7 IP/TCP header default: beg=0;end=len; // print all packet printf("\n\n Packet nr %d size %d \n\n",count,len); if(end)num=end beg+1; else num=0; while(num ) printf("%.2x ", *(p+beg)); p++; printf("\n\n Packet ends \n"); Remarque Après cette introduction générale à l'utilisation de l'interface raw-socket dans le réseau Ethernet nous proposons 2 sujets de développement à partir du code préparé. Le premier sujet est une application qui permet de diffuser et de récevoir les fichiers transmis directement dans les trames Ethernet. Cette application ne peut fonctionner que sur un réseau local. Le deuxième sujet est préparé pour l'analyse des trames Ethernet portant les protocoles de plus haut niveau: le protocole IP, puis le protocoles UDP et TCP.
Sujet 1: Ecrire une application qui permet de diffuser/émettre et récevoir sur le réseau local les fichiers transmis directemment dans les trames Ethernet. L'émetteur doit fonctionner en mode de diffusion (BROADCAST) et en mode simple (UNICAST). Eléments de l'application faire des modifications/versions du programme fourni dans l'annexe: 1. programme/processus émetteur qui envoie les trames en diffusion ou en unicast 2. programme récépteur qui réçoit les trames lui destinées (BROADCAST ou UNICAST) Nous avons besoin de déterminer la valeur du champ ethertypefname pour pouvoir différencier notre protocole des protocoles existants sur le réseau et de différencier les types de données à envoyer dans les trames. Par exemple nous pouvons proposer: x0201 : pour la trame qui porte le nom du fichier à lire sur le poste distant x0202: pour la trame qui porte le contenu/fragment du fichier envoyé par le poste distant Le protocoles standard tels que IP ou ARP utilisent des valeurs spécifiques: IP 0x0800, ARP - 0x0806 Rappelons que la longueur d'un segment doit être limitée à 1500 octets ou moins selon la taille du tampon de réception. int CreateRawSocket(int protocol) int rs; if((rs = socket(pf_packet,sock_raw,htons(protocol)))== 1) printf("error creating raw socket: "); exit( 1); return rs; Le programme de l'émmeteur doit pouvoir fonctionner avec une adresse simple ou une adresse de diffusion: MacAddress localmac = 0x00,0x00,0x00,0x00,0x00,0x00; //MacAddress localmac = 0x00,0x17,0xB3,0x00,0xa0,0x20; MacAddress destmacbrd = 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF; //MacAddress destmacuni= 0x00,0xB0,0xD0,0x4C,0xD5,0xC6; Le programme du serveur/émetteur doit créer et envoyer une trame avec le type (x0201) et le nom du fichier à créer sur le poste du client puis envoyer le fichier, segment par segment, vers le client/récepteur avec le type Ethernet égal à x0202. Attention: L'ensemble peut fonctionner seulement avec un seul serveur/émetteur et un fiichier transmis à l'instant donné. Imaginez une amelioration qui permet d'identifier les séquences de trames (sessions) de
transmission appartennant au même fichier envoyé par un ou plusieurs serveurs. Annexe: Voici le programme complet du transfert des fichiers ( émetteur et récepteur ) à comprendre et à re-utiliser pour la création/intégration de votre application. Emetteur/diffuseur des fichiers #include <stdio.h> #include <stdlib.h> #include <errno.h> #include <string.h> #include <sys/types.h> #include <sys/socket.h> #include <linux/if_ether.h> #include <netpacket/packet.h> extern int errno; #define ETHERTYPE_LEN 2 #define MAC_ADDR_LEN 6 #define BUFFER_LEN 320 #include <net/ethernet.h> #include <netinet/ether.h> typedef unsigned char MacAddress[MAC_ADDR_LEN]; // frame buffer // 6+6+2+2+data:for data 320 16=304 //MacAddress localmac = 0x00, 0x00, 0x00, 0x00, 0x00, 0x00; // unknown MacAddress localmac = 0x00, 0xB0, 0xD0, 0x4C, 0xD5, 0xC6; //MacAddress destmac= 0x00, 0xB0, 0xD0, 0x4C, 0xD5, 0xC6; MacAddress destmac = 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF; // broadcast int main(int c, char *a[]) int sd = 0, retvalue = 0, len=0; int fd = 0; unsigned short nb=1; char buffer[buffer_len]; struct sockaddr_ll destaddr; short int ethertypet = htons(0x8200); short int ethertypefname = htons(0x0201); // send name short int ethertypefdata = htons(0x0202); // send data short int dlen; // data length if(getuid()) printf("you must be root (uid=0) to run this program!\n"); exit(0); memset(&destaddr, 0, sizeof(struct sockaddr_ll)); memset(buffer, 0, BUFFER_LEN); if((sd = socket(pf_packet, SOCK_RAW, htons(eth_p_all))) < 0) printf("socket() error\n"); exit(1); printf("socket creation success.\n"); fd=open(a[1],0); // local file to open and send if(fd<0) printf("no such file: %s\n",a[1]); exit(2); 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); // Ethernet Header Construction: addresses 2*6 bytes memcpy(buffer, destmac, MAC_ADDR_LEN); memcpy((buffer+mac_addr_len), localmac, MAC_ADDR_LEN); // Ethernet Header Construction: type 2 bytes memcpy((buffer+(2*mac_addr_len)), &(ethertypefname), 2); // protocol type field: file name or file data memcpy((buffer+(2*mac_addr_len)+ethertype_len), &dlen, 2); // protocol data field length dlen=htons(strlen(a[2])+1); // file name memcpy((buffer+(2*mac_addr_len)+ethertype_len)+2, a[2], strlen(a[2])+1); len = 2*6+2+2+strlen(a[2])+1; // total frame length // sending the frame with the file name to be created at receiver side retvalue = sendto(sd, buffer, len, 0, (struct sockaddr *)&(destaddr), sizeof(struct sockaddr_ll)); while(nb) // reading the local file into frame buffer nb = read(fd,buffer+16,sizeof(buffer) 16); // preparing the frame header memcpy((buffer+(2*mac_addr_len)), &(ethertypefdata), 2); dlen=htons(nb); // convert short value in network format memcpy((buffer+(2*mac_addr_len)+ethertype_len), &dlen, 2); // sending the file data frame if((retvalue = sendto(sd, buffer, nb+16, 0, (struct sockaddr *)&(destaddr), sizeof(struct sockaddr_ll))) < 0) printf("sendto()) error \n"); exit(3); printf("send success (%d).\n", retvalue); // waiting for 200 microseconds before sending next frame usleep(200); return(0);
Récepteur des fichiers #include <stdio.h> #include <stdlib.h> #include <sys/socket.h> #include <linux/if_packet.h> #include <linux/if_ether.h> #include <linux/if_arp.h> #include <string.h> #define ETHERTYPE_LEN 2 #define MAC_ADDR_LEN 6 #define ETH_FRAME_LEN 320 int main(int c, char **a) int nb=1, fd; unsigned short count=1; int sd; // socket descriptor if(geteuid()) printf("you must be root (uid=0) to run this program! %d\n",geteuid()); exit(0); sd = socket(af_packet, SOCK_RAW, ntohs(eth_p_all)); if (sd == 1) printf("socket() error\n"); exit(1); // prepare the frame buffer unsigned char* buffer = (unsigned char*)malloc(eth_frame_len); memset(buffer, '\0', ETH_FRAME_LEN); // frame buffer reset int len = 0; // frame buffer length while(count) len = recvfrom(sd,buffer,eth_frame_len,0,(struct sockaddr *) 0,(int *) 0); printf("len:%d\n",len); if (len == 1) printf("error while receiving ethernet frame...\n"); exit(2); else printf("frame type %4.4x\n",*(buffer+12)); // frame type on 12th and 13th byte memcpy(&count,buffer+14,2); printf("counter %.4x\n",ntohs(count)); // print number of data bytes in frame : convert to host format if(*(buffer+12)==0x02 && *(buffer+13)==0x01) printf("name: %s\n",buffer+16); fd=creat(buffer+16,0777); // frame with file name : create the file if(*(buffer+12)==0x02 && *(buffer+13)==0x02) write(fd,buffer+16,ntohs(count)); // frame with file data : write to the file memset(buffer, '\0', ETH_FRAME_LEN); close(sd); close(fd);
Sujet 2: Ecrire une application qui permet de récevoir les trames en mode de promiscuité et d'afficher le contenu formaté des trames captées. 1. Afficher les en-têtes de trames Ethernet. 2. Afficher les en-têtes de trames Ethernet et des paquets IP et segments TCP/UDP portés dans les trames. Elements de l'application: int CreatePromiscuousSocket(char *name) int sd; struct ifreq ifr; struct sockaddr_ll interfaceaddr; struct packet_mreq mreq; if ((sd = socket(pf_packet,sock_raw,htons(eth_p_all))) < 0) return 1; // clearing the interfaceaddr link layer socket address memset(&interfaceaddr,0,sizeof(interfaceaddr)); // clearing the ifr interface control registers memset(&ifr,0,sizeof(ifr)); // clearing mreq packet control registers memset(&mreq,0,sizeof(mreq)); // preparing the interface name memcpy(&ifr.ifr_name,name,ifnamsiz); // setting the interface name to find the iterface index ioctl(sd,siocgifindex,&ifr); // setting the interface index interfaceaddr.sll_ifindex = ifr.ifr_ifindex; // setting the address family for interface interfaceaddr.sll_family = AF_PACKET; // binding the socket to the identified interface if (bind(sd, (struct sockaddr *)&interfaceaddr,sizeof(interfaceaddr)) < 0) return 2; // preparing the interface index in packet control mreq.mr_ifindex = ifr.ifr_ifindex; // preparing the promiscuous mode for packet sniffing mreq.mr_type = PACKET_MR_PROMISC; // setting the MAC address size mreq.mr_alen = 6; // setting the promiscuous mode to the interface for packet sniffing if (setsockopt(sd,sol_packet,packet_add_membership, (void*)&mreq,(socklen_t)sizeof(mreq)) < 0) return 3; return sd;
unsigned char* ReceiveRawEth(int sd) unsigned char* buffer = (unsigned char*)malloc(eth_frame_len); memset(buffer, '\0', ETH_FRAME_LEN); // frame buffer reset int l = 0; // frame buffer length l=recvfrom(sd,buffer,eth_frame_len,0,(struct sockaddr *)0,(int*)0); return buffer; void PrintPacketInHex(unsigned char *packet, int len, int com) unsigned char *p = packet; int beg,end,num; int ip=0; int udp=0,tcp=0; static int count=0; count++; beg=0;end=0; ip=(*(packet+12)==0x08 && *(packet+13)==0x00); //IP protocol in ETH frame udp= ip && (*(packet+23)==0x11); // UDP protocol in IP packet tcp= ip && (*(packet+23)==0x06); // TCP protocol in IP packet switch (com) case 0: beg=0;end=len;break; // print all packet case 1: beg=0;end=13;break; // print header case 2: beg=0;end=5;break; // print destination address case 3: beg=6;end=11;break; // print source address case 4: beg=14;end=len 14;break; // print data only case 5: if(ip)beg=14;end=33;;break; // print IP header 8 bytes case 6: if(udp)beg=34;end=41;;break; // print UDP header 8 bytes case 7: if(tcp)beg=34;end=53;;break; // print TCP header 20 bytes // Exercise: here you put your modes: // 5 IP header // 6 IP/UDP header // 7 IP/TCP header default: beg=0;end=len; // print all packet printf("\n\n Packet nr %d size %d \n\n",count,len); if(end)num=end beg+1; else num=0; while(num ) printf("%.2x ", *(p+beg)); p++; printf("\n\n Packet ends \n"); Attention: Cette fonction doit être completée afin de pouvoir imprimer/afficher les en-têtes du protocole IP et des protocoles TCP/UDP.
Le format d'un en-tête de protocole IP de base est donné ci-dessous (sans options 20 octets): La valeur du champ Protocol est 6 (0x06) pour TCP et 17 (0x11) pour UDP Le format d'un en-tête UDP est illustré ci-dessous (8 octets): Le format d'u en-tête TCP est donné ci-dessous (20 octets sans options):
Annexe: #include<stdio.h> #include<stdlib.h> #include<sys/socket.h> #include<features.h> #include<linux/if_packet.h> #include<linux/if_ether.h> #include<errno.h> #include<sys/ioctl.h> #include<net/if.h> int CreatePromiscuousSocket(char *name) int sd; struct ifreq ifr; struct sockaddr_ll interfaceaddr; struct packet_mreq mreq; if ((sd = socket(pf_packet,sock_raw,htons(eth_p_all))) < 0) return 1; // clearing the interfaceaddr link layer socket address memset(&interfaceaddr,0,sizeof(interfaceaddr)); // clearing the ifr interface control registers memset(&ifr,0,sizeof(ifr)); // clearing mreq packet control registers memset(&mreq,0,sizeof(mreq)); // preparing the interface name memcpy(&ifr.ifr_name,name,ifnamsiz); // setting the interface name to find the iterface index ioctl(sd,siocgifindex,&ifr); // setting the interface index interfaceaddr.sll_ifindex = ifr.ifr_ifindex; // setting the address family for interface interfaceaddr.sll_family = AF_PACKET; // binding the socket to the identified interface if (bind(sd, (struct sockaddr *)&interfaceaddr,sizeof(interfaceaddr)) < 0) return 2; // preparing the interface index in packet control mreq.mr_ifindex = ifr.ifr_ifindex; // preparing the promiscuous mode for packet sniffing mreq.mr_type = PACKET_MR_PROMISC; // setting the MAC address size mreq.mr_alen = 6; // setting the promiscuous mode to the interface for packet sniffing if (setsockopt(sd,sol_packet,packet_add_membership, (void*)&mreq,(socklen_t)sizeof(mreq)) < 0) return 3; return sd;
void PrintPacketInHex(unsigned char *packet, int len, int com) unsigned char *p = packet; int beg,end,num; int ip=0; int udp=0,tcp=0; static int count=0; count++; beg=0;end=0; ip=(*(packet+12)==0x08 && *(packet+13)==0x00); //IP protocol in ETH frame udp= ip && (*(packet+23)==0x11); // UDP protocol in IP packet tcp= ip && (*(packet+23)==0x06); // TCP protocol in IP packet switch (com) case 0: beg=0;end=len;break; // print all packet case 1: beg=0;end=13;break; // print header case 2: beg=0;end=5;break; // print destination address case 3: beg=6;end=11;break; // print source address case 4: beg=14;end=len 14;break; // print data only case 5: if(ip)beg=14;end=33;;break; // print IP header 8 bytes case 6: if(udp)beg=34;end=41;;break; // print UDP header 8 bytes case 7: if(tcp)beg=34;end=53;;break; // print TCP header 20 bytes // Exercise: here you put your modes: // 5 IP header // 6 IP/UDP header // 7 IP/TCP header default: beg=0;end=len; // print all packet printf("\n\n Packet nr %d size %d \n\n",count,len); if(end)num=end beg+1; else num=0; while(num ) printf("%.2x ", *(p+beg)); p++; printf("\n\n Packet ends \n");
main(int c,char **a) int sd; unsigned char buf[1500]; struct sockaddr_ll addr; socklen_t addr_len = sizeof(addr); int n; int com; if(getuid()) printf("you must be root (uid=0) to run this program!\n"); exit(0); if(c!=3) printf("usage: s2.sniffall interface_name protocol_to_sniff\n"); printf("0 all packet\n"); printf("1 ETH header\n"); printf("2 ETH dest address\n"); printf("3 ETH source address\n"); printf("4 ETH data\n"); printf("5 IP header\n"); printf("6 UDP header\n"); printf("7 TCP header\n"); exit(1); sd=createpromiscuoussocket(a[1]); // a[1] interface name com = atoi(a[2]); // protocol to sniff while(1) n = recvfrom(sd, buf, 2000, 0, (struct sockaddr*)&addr, &addr_len); if (n <= 0) printf("error reading\n"); else PrintPacketInHex(buf,n,com);