Datenstruktur per Fifo/named Pipe übergeben.



  • Ich empfange in einem Prozess Ethernetpakete (kein TCP/IP). Diese möchte ich an mein Hauptprogramm weitergeben. Kann ich das direkt mit einer Fifo Queue machen, oder muss ich mein Ethernetpaket im Empfangsprogramm in klartext auslesen und dann rübergeben.

    Noch mal fürs Verständnis:
    Prozess a: Empfängt Ethernetpaket (Zieladresse, Queladresse, Ethertype ...)

    read(sock,packet,packetsize);
    

    --> übergibt dieses packet an Prozess b: Hier lese ich mein empfangenes Paket aus und zerstückel es, wie benötigt.

    So lese ich meine Pakete bisher testweise aus und da klappt es. Diese Daten müsste ich übergeben.

    int packetsize = sizeof(struct ether_header) + sizeof(struct MEINPAKETINHALT) 
         char packet[packetsize]; 
         struct ether_header *ethhdr = (struct ether_header *) packet;
         struct MEINPAKETINHALT *mpi = (struct MEINPAKETINHALT *)(packet + sizeof(struct ether_header));
    
         // Raw Socket oeffnen
         if( (sock = socket(AF_INET,SOCK_PACKET,htons(MEINETHERTYPE))) == -1) { perror("socket"); exit(1); }
    
         // Lese Pakete aus dem Raw Socket  
         while(1)
         {
         i++; 
         printf ("Empfangenes Paket Nr.: %d ; Packetsize: %d\n",i,packetsize);
         read(sock,packet,packetsize);//Original
         printf("Ziel:%s  ", ether_ntoa (ethhdr->ether_dhost));
         printf ("Quelle: %s  - Ethertype: %X\n ",ether_ntoa (ethhdr->ether_shost), ethhdr->ether_type);
    	...
     }
    

    Kann ich das empfangene paket als ein Block übergeben und im Prozess b auslesen?

    Ich habe bisher nur Sachen gesehen, die Text oder Zahlen übergeben, aber keine Stuctures.
    Vielen Dank für jede Hilfe



  • möglicherweise wäre es sinnvoller, ein unix datagram socket zu verwenden, da ein fifo ein stream ist und du eh schon pakete hast, die anscheinend auch noch eine fixe größe haben. verschicken kannst du über einen filedescriptor sowieso alles. die byteorder musst du bei lokalen sockets nicht beachten.

    EDIT:
    laut socket(2) is SOCK_PACKET veraltet. schau dir vielleicht packet(7) an.



  • Hm, wenn ich jetzt SOCK_DGRAM anstatt SOCK_PACKET benuzte bringt mir sendto eine Fehlermeldung. Leider weiß ich nicht, was damit gemeint ist. Folgendermaßen versende ich die Pakete (ZielAdresse ist eine Broadcast MAC Adresse):

    // Includes
         #include <stdio.h> 
         #include <stdlib.h> 
         #include <string.h> 
         #include <netinet/in.h> 
         #include <net/ethernet.h> 
         #include <unistd.h>//sleep()
    
      // Main part
         int main(void)
         {  
         int sock;
         struct sockaddr addr;
          unsigned int packetsize = sizeof (struct Meintestpaket)+ sizeof(struct ether_header);
         unsigned char packet[packetsize];
         struct ether_header *ethhdr = (struct ether_header *)packet;
          struct MEINPAKETINHALT *mpi = (struct MEINPAKETINHALT *)(packet + sizeof(struct ether_header));
         char smac[18], dmac[18];//source MAC Adresse und ZielMACadresse
         char *quellmac;
         char dev1[6];
    
         strncpy(dmac,"01:15:01:00:00:01",18);//ZielMAC
         strncpy(smac,"00:01:23:45:67:89",18);//QuellMAC 
         strncpy(dev1,"eth0",6);
    
         // Packet Buffer initialisieren
         memset(packet,0,packetsize); 
    
         // Erstelle einen Socket Deskriptor
         if( ( sock = socket(PF_PACKET,SOCK_DGRAM,htons(MEINETHERTYPE))) == -1 ) { perror("socketfehler"); exit(1); }
    
         // Ethernet Header Optionen
         memcpy(ethhdr->ether_dhost,(u_char *)ether_aton(dmac),ETHADDRLENGTH); // Destination MAC
         memcpy(ethhdr->ether_shost,(u_char *)ether_aton(smac),ETHADDRLENGTH); // Source MAC
         ethhdr->ether_type = htons(MEINETHERTYPE); 
    
        // Schicke das Paket auf die Reise
        strncpy(addr.sa_data,dev1,sizeof(addr.sa_data)); 
        int i=0;
    
       while(i<16){
         printf ("Packetsize: %d\n",packetsize);
         printf("Sending Packet Nr.:%d\n",i); 
         printf("Ziel:%s  ", ether_ntoa (ethhdr->ether_dhost));
         printf ("Quelle: %s  Ethertype: %X\n",ether_ntoa (ethhdr->ether_shost), ethhdr->ether_type);
         //usleep (1000000);
    
         if( (sendto(sock,packet,packetsize,0,&addr,sizeof(struct sockaddr))) == -1 )
        {
         perror("sendto");
         // exit(1);
         }
        i++;
        printf("i ist gleich %d \n  ",i);
            }
       //printf("Paketlänge:%d\n",packetsize); 
       exit (0);
    }
    

    So sah der Code für meinen Socketdescriptor vorher aus:

    if( ( sock = socket(AF_INET,SOCK_PACKET,htons(MEINETHERTYPE))) == -1 ) { perror("socket"); exit(1); }
    

    Beim Ausführen bekomme ich jetzt die Meldung
    sendto: Invalid Argument

    Kann mir jemand weiterhelfen und einen Tip geben, wo das Problem liegt? Beim Erstellen des Sockets meckert er nicht und bei sendto habe ich nichts geändert. Weiß jemand welches Argument gemeint ist?
    Vielen Dank für jede Hilfe.



  • ein kleines beispielprogramm:

    #include <sys/socket.h>
    #include <netpacket/packet.h>
    #include <net/ethernet.h>
    #include <netinet/ether.h>
    #include <sys/ioctl.h> 
    #include <net/if.h>
    
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    #define PROTO 0x1234
    #define PAYLOAD_LENGTH 1024
    
    int main(void) {
      struct sockaddr_ll addr;
      struct ether_addr eaddr;
      int s;
      char payload[PAYLOAD_LENGTH];
      struct ifreq ifreq;
    
      memset(payload, 'a', PAYLOAD_LENGTH);
      ether_aton_r("00:30:18:a4:e0:2e", &eaddr);
      strncpy(ifreq.ifr_name, "eth0", IFNAMSIZ);
    
      addr.sll_family = AF_PACKET;
      addr.sll_protocol = PROTO;
      addr.sll_hatype = ARPHRD_ETHER;
      addr.sll_pkttype = 0;
      addr.sll_halen = sizeof(struct ether_addr);
      memcpy(addr.sll_addr, &eaddr, sizeof(struct ether_addr));
    
      if((s = socket(PF_PACKET, SOCK_DGRAM, PROTO)) == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
      }
      if(ioctl(s, SIOCGIFINDEX, &ifreq) == -1) {
        perror("socket");
        exit(EXIT_FAILURE);
      }
      addr.sll_ifindex = ifreq.ifr_ifindex;
      if(sendto(s, payload, PAYLOAD_LENGTH, 0, (struct sockaddr*)&addr, sizeof(struct sockaddr_ll)) == -1) {
        perror("sendto");
        exit(EXIT_FAILURE);
      }
    
      close(s);
      return EXIT_SUCCESS;
    }
    

    für ein SOCK_DGRAM musst du eine adresse vom typ sockaddr_ll an sendto übergeben. das ioctl wird dazu verwendet, zu einem device namen den interface index herauszufinden. du musst dann den ethernet header nicht als daten mitgeben, sondern nur die payload.



  • Danke für das Beispiel. Ich habe es jetzt hinbekommen. Ich hatte die Funktionsweise der structure sockaddr_ll nicht richtig verstanden und hätte vermutlich noch länger dran rumgedoktert, von dem ioctl ganz zu schweigen. Wieder was gelernt. Prima 😃


Anmelden zum Antworten