Trouble with implementing a C program that sends and receives raw ethernet frames

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • bkim125
    New Member
    • Apr 2013
    • 2

    #1

    Trouble with implementing a C program that sends and receives raw ethernet frames

    Hi everyone,

    First off, I am fairly new to the topic of the ethernet and the data link layer and I am trying to write a C program which allows the sending and receiving of ethernet frames.

    I am trying to have my program send the ethernet frame to myself, so the program will have the same source and destination mac addresses.

    The program that I'm using is a modified version of the code from http://hacked10bits.blogspot.com/201...in-6-easy.html.

    I keep having trouble with the recvfrom() function, it seems to just be blocking and the program doesn't terminate. From the code, I am trying send the ethernet frame and have the recvfrom() function be able to retrieve the frame and store it in a buffer. But because recvfrom() function is just blocking, it seems to me that the sendto() function was not able to successfully send the frame.

    Any ideas how I can fix this?

    Here is my code:
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <sys/socket.h>    /* Must precede if*.h */
    #include <linux/if.h>
    #include <linux/if_ether.h>
    #include <linux/if_packet.h>
    #include <sys/ioctl.h>
    
    union ethframe
    {
      struct
      {
        struct ethhdr    header;
        unsigned char    data[ETH_DATA_LEN];
      } field;
      unsigned char    buffer[ETH_FRAME_LEN];
    };
    
    int main(int argc, char **argv) {
      char *iface = "eth0";
      unsigned char dest[ETH_ALEN]
               = { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 };
      unsigned short proto = 0x1234;
      unsigned char *data = "hello world";
      unsigned short data_len = strlen(data);
     
      int s;
      if ((s = socket(AF_PACKET, SOCK_RAW, htons(proto))) < 0) {
        printf("Error: could not open socket\n");
        return -1;
      }
     
      struct ifreq buffer;
      int ifindex;
      memset(&buffer, 0x00, sizeof(buffer));
      strncpy(buffer.ifr_name, iface, IFNAMSIZ);
      if (ioctl(s, SIOCGIFINDEX, &buffer) < 0) {
        printf("Error: could not get interface index\n");
        close(s);
        return -1;
      }
      ifindex = buffer.ifr_ifindex;
     
      unsigned char source[ETH_ALEN];
      if (ioctl(s, SIOCGIFHWADDR, &buffer) < 0) {
        printf("Error: could not get interface address\n");
        close(s);
        return -1;
      }
    
      memcpy((void*)source, (void*)(buffer.ifr_hwaddr.sa_data),
             ETH_ALEN);
      
      //edited part... here we have it so that the destination mac address is
      //the same as the source mac address
      memcpy((void*)dest, (void*)(buffer.ifr_hwaddr.sa_data),
           ETH_ALEN);
     
      //probe source mac address
      int k;
      for(k = 0; k !=ETH_ALEN; k++)
      {
        printf("%x\n",source[k]);
        printf("%x\n",dest[k]);
      }
        
      union ethframe frame;
      memcpy(frame.field.header.h_dest, dest, ETH_ALEN);
      memcpy(frame.field.header.h_source, source, ETH_ALEN);
      frame.field.header.h_proto = htons(proto);
      memcpy(frame.field.data, data, data_len);
     
      unsigned int frame_len = data_len + ETH_HLEN;
     
      struct sockaddr_ll saddrll;
      memset((void*)&saddrll, 0, sizeof(saddrll));
      saddrll.sll_family = PF_PACKET;   
      saddrll.sll_ifindex = ifindex;
      saddrll.sll_halen = ETH_ALEN;
      memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);
     
      if (sendto(s, frame.buffer, frame_len, 0,
                 (struct sockaddr*)&saddrll, sizeof(saddrll)) > 0)
        printf("Frame successfully sent!\n");
      else
        printf("Error, could not send\n");
     
    
      struct sockaddr_ll saddrll_receive;
      memset((void*)&saddrll_receive, 0, sizeof(saddrll_receive));
      socklen_t sll_len = (socklen_t)sizeof(saddrll_receive);
      
      int recv_result;
      char buffer_receive[ETH_FRAME_LEN];
      recv_result = recvfrom(s, buffer_receive, ETH_FRAME_LEN, 0,
    			 (struct sockaddr*)&saddrll_receive, &sll_len);
     
    
      close(s);
     
      return 0;
    }
    edit: this is on a linux machine by the way.
  • Banfa
    Recognized Expert Expert
    • Feb 2006
    • 9067

    #2
    I think the mistake you are making is trying to do all this on 1 thread/process.

    You are assuming that when you call sendto at line 83 the data sent is somehow stored somewhere so you can retrieve it with a recvfrom at line 96. However there is no such buffering, when you call sendto the frame is sent, if anyone is listening right then they receive it.

    At the time you call sendto you are not waiting to receive it so the frame is lost, then you call recvfrom and block waiting for a frame that has already been received and discarded.

    If you look at the code in the article you reference it only does the send not the receive for this reason.

    You need to make sure that you have already called recvfrom and are blocking when you make the sendto call. If this is a single process that implies multiple threads otherwise you could not call sendto while you are blocked on recvfrom, hence my first comment. Another option would be to split this into 2 applications, 1 that received and 1 that sent.

    Comment

    • bkim125
      New Member
      • Apr 2013
      • 2

      #3
      Hi Banfa,

      Thanks for helping a beginner. So I've just tried out what you recommended: split the recvfrom and sendto functions into two applications, lets call them "receive_progra m" and "send_progr am".

      The way in which I was tested the two applications was by 1. setting up two command windows 2. then having the receive_program be run and be blocking on one of the command windows 3. and have the send_program run on the other.

      It turns out that the receive_program is still blocking, which means that it never received any data. I'm pretty sure I've set the correct mac address and everything, I think I'm missing something.

      Here are my two programs:

      send_program:

      Code:
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <sys/socket.h>    /* Must precede if*.h */
      #include <linux/if.h>
      #include <linux/if_ether.h>
      #include <linux/if_packet.h>
      #include <sys/ioctl.h>
      
      union ethframe
      {
        struct
        {
          struct ethhdr    header;
          unsigned char    data[ETH_DATA_LEN];
        } field;
        unsigned char    buffer[ETH_FRAME_LEN];
      };
      
      int main(int argc, char **argv) {
        char *iface = "eth0";
        unsigned char dest[ETH_ALEN]
          = { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 };
        unsigned short proto = 0x1234;
        unsigned char *data = "hello world";
        unsigned short data_len = strlen(data);
       
        int s;
        if ((s = socket(AF_PACKET, SOCK_RAW, htons(proto))) < 0) {
          printf("Error: could not open socket\n");
          return -1;
        }
       
        struct ifreq buffer;
        int ifindex;
        memset(&buffer, 0x00, sizeof(buffer));
        strncpy(buffer.ifr_name, iface, IFNAMSIZ);
        if (ioctl(s, SIOCGIFINDEX, &buffer) < 0) {
          printf("Error: could not get interface index\n");
          close(s);
          return -1;
        }
        ifindex = buffer.ifr_ifindex;
       
        unsigned char source[ETH_ALEN];
        if (ioctl(s, SIOCGIFHWADDR, &buffer) < 0) {
          printf("Error: could not get interface address\n");
          close(s);
          return -1;
        }
      
        memcpy((void*)source, (void*)(buffer.ifr_hwaddr.sa_data),
               ETH_ALEN);
        
        //edited part... here we have it so that the destination mac address is
        //the same as the source mac address
       
       
        //probe source mac address
        int k;
        for(k = 0; k !=ETH_ALEN; k++)
        {
          printf("%x\n",dest[k]);
        }
          
        union ethframe frame;
        memcpy(frame.field.header.h_dest, dest, ETH_ALEN);
        memcpy(frame.field.header.h_source, source, ETH_ALEN);
        frame.field.header.h_proto = htons(proto);
        memcpy(frame.field.data, data, data_len);
       
        unsigned int frame_len = data_len + ETH_HLEN;
       
        struct sockaddr_ll saddrll;
        memset((void*)&saddrll, 0, sizeof(saddrll));
        saddrll.sll_family = PF_PACKET;   
        saddrll.sll_ifindex = ifindex;
        saddrll.sll_halen = ETH_ALEN;
        memcpy((void*)(saddrll.sll_addr), (void*)dest, ETH_ALEN);
       
        if (sendto(s, frame.buffer, frame_len, 0,
                   (struct sockaddr*)&saddrll, sizeof(saddrll)) > 0)
          printf("Frame successfully sent!\n");
        else
          printf("Error, could not send\n");
       
      
        close(s);
       
        return 0;
      }
      receive_program :

      Code:
      #include <stdio.h>
      #include <stdlib.h>
      #include <string.h>
      #include <sys/socket.h>    /* Must precede if*.h */
      #include <linux/if.h>
      #include <linux/if_ether.h>
      #include <linux/if_packet.h>
      #include <sys/ioctl.h>
      
      union ethframe
      {
        struct
        {
          struct ethhdr    header;
          unsigned char    data[ETH_DATA_LEN];
        } field;
        unsigned char    buffer[ETH_FRAME_LEN];
      };
      
      int main(int argc, char **argv) {
        char *iface = "eth0";
        unsigned char dest[ETH_ALEN]
                 = { 0x00, 0x12, 0x34, 0x56, 0x78, 0x90 };
        unsigned short proto = 0x1234;
        unsigned char *data = "hello world";
        unsigned short data_len = strlen(data);
       
        int s;
        if ((s = socket(AF_PACKET, SOCK_RAW, htons(proto))) < 0) {
          printf("Error: could not open socket\n");
          return -1;
        }
       
        struct ifreq buffer;
        int ifindex;
        memset(&buffer, 0x00, sizeof(buffer));
        strncpy(buffer.ifr_name, iface, IFNAMSIZ);
        if (ioctl(s, SIOCGIFINDEX, &buffer) < 0) {
          printf("Error: could not get interface index\n");
          close(s);
          return -1;
        }
        ifindex = buffer.ifr_ifindex;
       
        unsigned char source[ETH_ALEN];
        if (ioctl(s, SIOCGIFHWADDR, &buffer) < 0) {
          printf("Error: could not get interface address\n");
          close(s);
          return -1;
        }
      
        memcpy((void*)source, (void*)(buffer.ifr_hwaddr.sa_data),
               ETH_ALEN);
        
        //edited part... here we have it so that the destination mac address is
        //the same as the source mac address
        memcpy((void*)dest, (void*)(buffer.ifr_hwaddr.sa_data),
             ETH_ALEN);
       
        //probe source mac address
        int k;
        for(k = 0; k !=ETH_ALEN; k++)
        {
          printf("%x\n",source[k]);
          printf("%x\n",dest[k]);
        }
          
        union ethframe frame;
        memcpy(frame.field.header.h_dest, dest, ETH_ALEN);
        memcpy(frame.field.header.h_source, source, ETH_ALEN);
        frame.field.header.h_proto = htons(proto);
        memcpy(frame.field.data, data, data_len);
       
        unsigned int frame_len = data_len + ETH_HLEN;
       
        struct sockaddr_ll saddrll;
        memset((void*)&saddrll, 0, sizeof(saddrll));
        socklen_t sll_len = (socklen_t)sizeof(saddrll);
        
        int recv_result;
        char buffer_receive[ETH_FRAME_LEN];
        recv_result = recvfrom(s, buffer_receive, ETH_FRAME_LEN, 0,
      			 (struct sockaddr*)&saddrll, &sll_len);
       
        if(recv_result > 0)
          printf("frame successfully received\n");
        close(s);
       
        return 0;
      }

      Comment

      Working...