Raw socket e Ipv6

di il
43 risposte

Raw socket e Ipv6

Salve ho un problema riguardo i raw socket. Ho la necessita di accedere all'interfaccia eth0 direttamente dall'interfaccia di rete senza passare per TCP o UDP. Seguendo alcuni topic in giro per siti e alcune guide ho tirato fuori questo programma:
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <stdio.h>
#include <netdb.h>
#include <errno.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>


int main() {
	
int sock,i;

struct sockaddr_in6 *address;
struct protoent *proto;
struct ifreq ethreq, Interface, Interface1;
unsigned char buffer[2048];
unsigned char tbuff[2048];
unsigned char *iphead, *ethhead,*phead;


static const uint8_t mys6_addr[16]={0x54,0x04,0x20,0x49,0x0e,0x40,0xc7,0x03,0xa0};
proto=getprotobyname("ipv6");


sock=socket(AF_INET6, SOCK_RAW,proto->p_proto);

if(sock<0) {
		perror("socket");
exit(1);
}

strncpy(ethreq.ifr_name, "eth0", IFNAMSIZ);

if (ioctl(sock,SIOCGIFFLAGS, &ethreq) == -1) {
    perror("ioctl");
    close(sock);
    exit(1);
}

ethreq.ifr_flags |= IFF_PROMISC;

if (ioctl(sock, SIOCSIFFLAGS, &ethreq) == -1) {
    perror("ioctl");
    close(sock);
    exit(1);
}

memset(&Interface, 0, sizeof(Interface));
strncpy(Interface.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);

if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, &Interface, sizeof(Interface))<0)
	close(sock);

 int s = socket (AF_INET6, SOCK_RAW, proto->p_proto);

     struct sockaddr_in6 sin6;

     memset(&sin6,0,sizeof(sin6));

     sin6.sin6_family = AF_INET6;
     sin6.sin6_port = htons(0);
     memcpy(sin6.sin6_addr.s6_addr, mys6_addr, sizeof(mys6_addr));
    

     memset(&Interface1, 0, sizeof(Interface1));
     strncpy(Interface1.ifr_ifrn.ifrn_name, "eth0", IFNAMSIZ);
     if (setsockopt(s, SOL_SOCKET, SO_BINDTODEVICE, &Interface1, sizeof(Interface1)) < 0) { close(s); }

while (1) {
	
    printf("----------------------\n");
    i = recvfrom(sock, buffer, sizeof(buffer), 0, NULL, NULL);
    printf("%d bytes read\n", i);

   
    if (i < 42) {
        perror("recvfrom():");
        printf("Incomplete packet (errno is %d)\n", errno);
        close(sock);
        exit(0);
    }

    phead = buffer + 14;
    memcpy(tbuff,phead,i-14); 
    iphead=tbuff;
    if (*iphead == 0x45) {
        int ptrindex= iphead[9];
        switch(ptrindex){

         case 1:
                printf("The transport protocl is:ICMP\n");
                break;
         case 2:
                printf("The transport protol is:IGMP\n");
                break;
         case 6:
               printf("The transport protocol is:TCP\n");
               break;
         case 17:
               printf("The transport protocol is:UDP\n");
               break;
         case 103:
              printf("The transport protocol is:PIM\n"); 
              break; 
         default:
             printf("The transport protocol is:%d\n",iphead[9]);
        }           
        
        printf("Source Address: %d.%d.%d.%d, Port: %d\n",
            iphead[12], iphead[13], iphead[14], iphead[15], (iphead[20] << 8) + iphead[21]);
        printf("Dest Address: %d.%d.%d.%d, Port: %d\n",
            iphead[16], iphead[17], iphead[18], iphead[19], (iphead[22] << 8) + iphead[23]);
	
	if(send(s,tbuff,i-14,0)<0)
		printf("error\n");

     else{printf("\nThe received packet is send\n");}

     memset(buffer,0,sizeof(buffer));
     memset(tbuff,0,sizeof(tbuff));

    }
   else{ printf("The non ip had received");}

    }
       close(sock);


	

return 0;
}
Il programma si blocca alla prima printf del while. Perchè? Ho letto in qualche sito che i raw socket hanno qualche problema nell'invio di pacchetti ipv6 o non sono predisposti per farlo è vero?

43 Risposte

  • Re: Raw socket e Ipv6

    Aiutati con il debug + un tool per sniffare i pacchetti.
    Se non riesci lo guarderò il prossimo fine settimana - prima non posso -
    Ho letto in qualche sito che i raw socket hanno qualche problema nell'invio di pacchetti ipv6 o non sono predisposti per farlo è vero?
    Questo è assurdo. Di che anno era il post che hai letto?
  • Re: Raw socket e Ipv6

    La data non la so! Comunque ok grazie mille Ora vedo un attimo con il debug
  • Re: Raw socket e Ipv6

    Il codice che hai proposto è errato nel setsockopt: i dati non arrivano.
    Per prelevare solo i pacchetti di una specifica interfaccia usa bind [man bind(2)] specificando l'indirizzo nella struct sockaddr_ll.
    A tal proposito esiste la recente AF_PACKET [man packet] per agire sul livello 2 (OSI) del driver di device. Un'altra
    soluzione di semplicemente implementazione consiste nell'utilizzo di pcap.

    Ti ho scritto un pezzo per sniffare tutti i pacchetti su layer 2.
    Puoi fare un parsing sul MAC address oppure come detto prima usa la bind.
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <unistd.h>
    #include <sys/socket.h>
    #include <netpacket/packet.h>
    #include <net/ethernet.h> /* the L2 protocols */
    #include <arpa/inet.h>
    #ifndef ETH_FRAME_LEN
    #define ETH_FRAME_LEN 1518
    #endif
    
    struct _ethernet
    {
      /* 
       * it's just defined in <linux/if_ether.h>
       * Ethernet Version 2 || DIX frame 
       */
      
      unsigned char dst [6];
      unsigned char src [6];
      unsigned char type[2];
    };
    
    
    
    
    void dump_x(unsigned char *s, unsigned int l, const char separator)
    {
      int nl=1;
      
      while (l--)
      {
        printf ("%02X%c",*s++,(l)?separator:' ');
        if (!(nl++%16))
          printf ("\n");
      }
      printf ("\n");
    }
    
    void dump_eth (unsigned char *s, unsigned int l)
    {
      struct _ethernet ethernet;
      memcpy (&ethernet,s,sizeof(struct _ethernet));
      printf ("Destination: "); dump_x(ethernet.dst, sizeof (ethernet.dst), ':');
      printf ("Source     : "); dump_x(ethernet.src, sizeof (ethernet.src), ':');
      printf ("Type       : "); dump_x(ethernet.type,sizeof (ethernet.type), ':');
    }
    
    
    
    
    
    
    int main ()
    {
      void* buffer;
      int packet_socket;
      ssize_t packet_size;
      
      
      
      if (( buffer = (void*)malloc(ETH_FRAME_LEN))==NULL)
        perror ("malloc");
      
      if ((packet_socket=socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL)))<0)
        perror ("socket");
    
      while (1)
      {
       
        printf("----------------------\n");
        packet_size = recvfrom(packet_socket, buffer, ETH_FRAME_LEN, 0, NULL, NULL);
        if (packet_size<0)
          perror ("recvmsg");
        else
        {
          printf("%zd bytes read\n", packet_size);
          dump_eth ((unsigned char *)buffer, (unsigned int) packet_size);
          dump_x ((unsigned char *)buffer,(unsigned int) packet_size,' ');
          
        }
        
      }
      
      close (packet_socket);
      free (buffer);
      
      return 0;
    }
    
    
    
    Per ovvi motivi non ti allego nessun output!

    Ma leggendo la tua richiesta mi sembra di capire che tu non conosca come funzionano i 7 livelli OSI e i relativi incapsulamenti. Ti consiglio almeno un'infarinatura generale
  • Re: Raw socket e Ipv6

    I 7 livelli ISO/OSI li conosco, per motivi di studio devo tentare di accedere all'interfaccia di rete (in questo eth0, ma in generale qualsiasi interfaccia) e inviare pacchetti ipv6 direttamente al sottostrato datalink/mac
  • Re: Raw socket e Ipv6

    Cioè in pratica devi forgiare dei frame al livello 2 OSI che contengono il livello di internetworking IPV6?

    edit:
    Permettimi una curiosità: a che cosa ti servirebbe?
  • Re: Raw socket e Ipv6

    Devo progettare un gateway per la mia tesi di laurea! Essendo un neofita sul campo dei raw socket avevo chiesto qui comunque ora provo con i packet
  • Re: Raw socket e Ipv6

    Si, altrimenti come detto precedentemente puoi usare pcap

    edit:
    from: man packet #notes
    For portable programs it is suggested to use AF_PACKET via pcap(3); although this only covers a subset of the
    AF_PACKET features.

    The SOCK_DGRAM packet sockets make no attempt to create or parse the IEEE 802.2 LLC header for a IEEE 802.3
    frame. When ETH_P_802_3 is specified as protocol for sending the kernel creates the 802.3 frame and fills out
    the length field; the user has to supply the LLC header to get a fully conforming packet. Incoming 802.3
    packets are not multiplexed on the DSAP/SSAP protocol fields; instead they are supplied to the user as proto-
    col ETH_P_802_2 with the LLC header prepended. It is thus not possible to bind to ETH_P_802_3; bind to
    ETH_P_802_2 instead and do the protocol multiplex yourself. The default for sending is the standard Ethernet
    DIX encapsulation with the protocol filled in.

    Packet sockets are not subject to the input or output firewall chains.

    Compatibility
    In Linux 2.0, the only way to get a packet socket was by calling socket(AF_INET, SOCK_PACKET, protocol). This
    is still supported but strongly deprecated. The main difference between the two methods is that SOCK_PACKET
    uses the old struct sockaddr_pkt to specify an interface, which doesn't provide physical layer independence.
  • Re: Raw socket e Ipv6

    Allora ho usato il protocollo AF_PACKET e ora riesco ad inviare e ricevere pacchetti ma non sono sicuro che il risultato sia corretto. Qualcuno può dirmi se ho sbagliato qualcosa. La stampa degli indirizzi non mi torna perchè?

    Ecco il codice:
  • Re: Raw socket e Ipv6

    Come pretendi di avere una risposta inviando PROVAAAA come frame?

    edit: allegato il tuo codice
    
    #include <sys/socket.h>
    #include <netpacket/packet.h>
    #include <net/ethernet.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <arpa/inet.h>
    #include <sys/ioctl.h>
    #include <net/if.h>
    
    #ifndef ETH_FRAME_LEN 
    #define ETH_FRAME_LEN 1518
    #endif
    
    #define DEVICE "wlan0"
    PrintInHex(char *mesg, unsigned char *p, int len);
    
    int main() {
    
    	unsigned char *iphead, *ethhead;
    
    	struct ethhdr *eth;
    	
    	struct ifreq ifr, ifr1;
    
    	int sock1,sock2;
    
    	ssize_t slength=0,rlength=0;
    	
    	
    	void* buffer1=NULL;
    	char buffer[ETH_FRAME_LEN]={"PROVAAAA"};
    	struct sockaddr_ll address,address1;
    	
    	//open two socket for read and write 
    
    	sock1=socket(AF_PACKET,SOCK_RAW,ETH_P_ALL);
    
    
    
    	if(sock1==-1) {
    		perror("socket");
    		exit(1);
    	}
    	
    	//insert in the struct ifreq name of device
    	//request ioctl for get the index and HW address
    	
    	memset(&ifr, 0, sizeof(struct ifreq));
    
    	strncpy(ifr.ifr_name,DEVICE, IFNAMSIZ);
    
    
    	if((ioctl(sock1, SIOCGIFINDEX, &ifr))==-1) {
    		printf("ciao");
    		perror("ioctl");
    		close(sock1);
    		exit(1); 		
    	}
    
    	address.sll_family=AF_PACKET;
    	address.sll_protocol=htons(ETH_P_ALL);
    	address.sll_ifindex=ifr.ifr_ifindex;
    
    	//bind my socket to address
    
    	if(bind(sock1,(const struct sockaddr*)&address, sizeof(struct sockaddr_ll))==-1) {
    		perror("bind");
    	}
    
    
    	//open socket for read
    
    	
    	sock2=socket(AF_PACKET,SOCK_RAW,ETH_P_ALL);
    	
    	if(sock2==-1) {
    		perror("socket");
    		exit(1);
    	}
    
    	memset(&ifr,0,sizeof(struct ifreq));
    	
    	strncpy(ifr1.ifr_name,DEVICE, IFNAMSIZ);
    
    	
    	if((ioctl(sock2, SIOCGIFINDEX, &ifr1))==-1) {
    		printf("ciao");
    		perror("ioctl");
    		close(sock1);
    		exit(1); 		
    	}
    
    	address1.sll_family=AF_PACKET;
    	address1.sll_protocol=htons(ETH_P_ALL);
    	address1.sll_ifindex=ifr1.ifr_ifindex;
    
    	//bind my socket to address
    
    	if(bind(sock2,(const struct sockaddr*)&address1, sizeof(struct sockaddr_ll))==-1) {
    		perror("bind");
    	}
    	
    	//invio e ricevo i pacchetti e stampo gli header
    	int j=0;
    	while(j<=10)
    	{
    		slength=send(sock1, buffer, ETH_FRAME_LEN,MSG_DONTROUTE);
    		if(slength==-1) {perror("send\n");}
    		else {
    			printf("%d", (int)slength);
    	      		printf("\ninviato\n");
    		}
    		
    		if (( buffer1 = (void*)malloc(ETH_FRAME_LEN))==NULL)
      		      {perror ("malloc");}
    		rlength=recv(sock2,buffer1, ETH_FRAME_LEN,0);
    		if(rlength==-1) {perror("recv");}
    		else { 
    		       printf("%d", (int)rlength);
    		       printf("\nricevuto\n"); 	
    		       ethhead = buffer;
    	               eth=(struct ethhdr *) ethhead;	
    			if(eth!=NULL) {
    					PrintInHex("Destination MAC: ", eth->h_dest, 6);
    					printf("\n");
    					/* Second set of 6 bytes are Source MAC */
    					PrintInHex("Source MAC: ", eth->h_source, 6);
    					printf("\n");
    					/* Last 2 bytes in the Ethernet header are the protocol it carries */
    					PrintInHex("Protocol: ",(void *)&eth->h_proto, 2);
    					printf("\n");
    			}
    
    					
        		  	
     		}    
    		
    	j++;
    	}
    
    	return 0;
    
    }	
    
    PrintInHex(char *mesg, unsigned char *p, int len)
    {
    	printf(mesg);
    
    	while(len--)
    	{
    		printf("%.2X ",*p);
    		p++;
    	}
    
    }
    
    
  • Re: Raw socket e Ipv6

    Se guardi attentamente la risposta
    trovi il tuo PROVAAA nell'header di risposta!!!

    edit:
    Destrination MAC: 50 52 4F 56 41 41 ( P R O V A A)
    Source MAC 41 41 00 00 00 .. (A A ...)
  • Re: Raw socket e Ipv6

    Per la bind non occorre specificare il family nella struct sockaddr_ll.
    ...
    Only the sll_protocol and the sll_ifindex address fields are used for purposes of binding
    ...
  • Re: Raw socket e Ipv6

    Una pulitina al codice bisognerebbe darla...
    
    Ethernet.c:17:1: warning: data definition has no type or storage class
    Ethernet.c:17:1: warning: type defaults to ‘int’ in declaration of ‘PrintInHex’
    Ethernet.c: In function ‘main’:
    Ethernet.c:123:18: warning: pointer targets in assignment differ in signedness
    Ethernet.c:21:17: warning: unused variable ‘iphead’
    Ethernet.c: At top level:
    Ethernet.c:147:1: warning: return type defaults to ‘int’
    Ethernet.c: In function ‘PrintInHex’:
    Ethernet.c:157:1: warning: control reaches end of non-void function
    
  • Re: Raw socket e Ipv6

    Ok grazie e scusa per il disagio!
  • Re: Raw socket e Ipv6

    Nessuno problema.... anzi chiedi spesso perché l'argomento mi piace troppo
Devi accedere o registrarti per scrivere nel forum
43 risposte