简体   繁体   中英

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

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/2011/12/sending-raw-ethernet-frames-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:

#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;
}

This is on a Linux machine of course.

You must have root privileges to use Raw socket.

Try to set the socket to Non blocking mode :

flags = fcntl (sock, F_GETFL);
fcntl (sock, F_SETFL, flags | O_NONBLOCK);

Your code snippet is same as the one which is posted at the Blog! First you have to be sure your interface name is "eth0".Then you have to set destination MAC address to be the MAC address of your computer - because it seems you want to send and receive data in your machine. currently your code is using a Hypothetical destination MAC address.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM