C言語で、Gratuitous ARPパケットを送信するサンプル

自分用メモ。

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <netdb.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <sys/param.h>
#include <sys/sysctl.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <net/if_arp.h>
#include <net/route.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <linux/if_packet.h>
#include <linux/if_ether.h>
#include <netinet/ether.h>

void get_ifinfo(char *devname, struct ifreq *ifreq, int flavor) {
  int iofd;
  
  if ((iofd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
    perror("ioctl socket creation");
    exit(1);
  }
  
  memset(ifreq, '\0', sizeof(*ifreq));
  strcpy(ifreq->ifr_name, devname);
  
  if (ioctl(iofd, flavor, ifreq) < 0) {
    perror("ioctl");
    exit(1);
  }
  
  return;
}

void send_gratuitous_arp(const int ifIndex, const char *devname, const char *ipaddress, const char *src_mac_address, const char *dst_mac_address){
  int rawfd;
  struct ether_arp arpbody;
  struct sockaddr_ll ll_from, ll_to;
  struct ether_addr src_mac_addr;
  struct ether_addr dst_mac_addr;

  ether_aton_r(src_mac_address, &src_mac_addr);
  ether_aton_r(dst_mac_address, &dst_mac_addr);

  arpbody.arp_hrd = htons(ARPHRD_ETHER);
  arpbody.arp_pro = htons(ETH_P_IP);
  arpbody.arp_hln = 6;
  arpbody.arp_pln = 4;
  arpbody.arp_op  = htons(ARPOP_REQUEST);
  memcpy(&(arpbody.arp_sha[0]), src_mac_addr.ether_addr_octet, ETH_ALEN); //arpbody.arp_sha
  memcpy(&(arpbody.arp_tha[0]), dst_mac_addr.ether_addr_octet, ETH_ALEN); //arpbody.arp_tha
  *((int *)&(arpbody.arp_spa[0])) = inet_addr(ipaddress); //arpbody.arp_spa
  *((int *)&(arpbody.arp_tpa[0])) = inet_addr(ipaddress); //arpbody.arp_tpa

  
  ll_from.sll_family = AF_PACKET;
  ll_from.sll_protocol = htons(ETH_P_ARP);
  ll_from.sll_ifindex = ifIndex;
  ll_from.sll_hatype = 0; //ARPHRD_ETHER;
  ll_from.sll_pkttype = 0; //PACKET_BROADCAST;
  ll_from.sll_halen = ETH_ALEN;
  //ll_from.sll_addr = NULL;
  memcpy(ll_from.sll_addr, src_mac_addr.ether_addr_octet, sizeof(src_mac_addr.ether_addr_octet));
  
  ll_to.sll_family = AF_PACKET;
  ll_to.sll_protocol = htons(ETH_P_ARP);
  ll_to.sll_ifindex = ifIndex;
  ll_to.sll_hatype = 0; //ARPHRD_ETHER;
  ll_to.sll_pkttype = 0; //PACKET_BROADCAST;
  ll_to.sll_halen = ETH_ALEN;
  //ll_to.sll_addr = NULL;
  memcpy(ll_to.sll_addr, dst_mac_addr.ether_addr_octet, sizeof(dst_mac_addr.ether_addr_octet));
  
  if ((rawfd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ARP))) < 0) {
    perror("raw socket creatin");
    exit(1);
  } 
  
  if (bind(rawfd, (struct sockaddr *)&ll_from, sizeof(ll_from)) < 0) {
    perror("bind");
    exit(1);
  }
  
  int size=0;
  if ( (size = sendto(rawfd, (void *)&arpbody, sizeof(struct ether_arp), 0, (struct sockaddr *)&ll_to, sizeof(ll_to))) <= 0) {
    perror("write");
    exit(1);
  }
}

int main(int argc, char **argv){
  int ifindex = 0;
  char *devname = "eth0";
  char *ipaddr = "10.0.7.1";
  char *src_macaddr = "00:12:34:56:78:9a";
  char *dst_macaddr = "00:00:00:00:00:00";
  struct ifreq ifreq;

  memset(&ifreq, '\0', sizeof(ifreq));

  //ifindex
  get_ifinfo( devname, &ifreq, SIOCGIFINDEX);
  ifindex = ifreq.ifr_ifindex;

  send_gratuitous_arp(ifindex, devname, ipaddr, src_macaddr, dst_macaddr);
  return 0;
  
}