toybox/toys/pending/arping.c
<<
>>
Prefs
   1/* arping - send ARP REQUEST to a neighbour host.
   2 *
   3 * Copyright 2013 Sandeep Sharma <sandeep.jack2756@gmail.com>
   4 * Copyright 2013 Kyungwan Han <asura321@gmail.com>
   5 *
   6 * No Standard.
   7
   8USE_ARPING(NEWTOY(arping, "<1>1s:I:w#<0c#<0AUDbqf[+AU][+Df]", TOYFLAG_USR|TOYFLAG_SBIN))
   9
  10config ARPING
  11  bool "arping"
  12  default n
  13  help
  14    usage: arping [-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP
  15
  16    Send ARP requests/replies
  17
  18    -f         Quit on first ARP reply
  19    -q         Quiet
  20    -b         Keep broadcasting, don't go unicast
  21    -D         Duplicated address detection mode
  22    -U         Unsolicited ARP mode, update your neighbors
  23    -A         ARP answer mode, update your neighbors
  24    -c N       Stop after sending N ARP requests
  25    -w TIMEOUT Time to wait for ARP reply, seconds
  26    -I IFACE   Interface to use (default eth0)
  27    -s SRC_IP  Sender IP address
  28    DST_IP     Target IP address
  29*/
  30#define FOR_arping
  31#include "toys.h"
  32#include <netinet/ether.h>
  33#include <netpacket/packet.h>
  34
  35GLOBALS(
  36    long count;
  37    unsigned long time_out;
  38    char *iface;
  39    char *src_ip;
  40
  41    int sockfd;
  42    unsigned long start, end;
  43    unsigned sent_at, sent_nr, rcvd_nr, brd_sent, rcvd_req, brd_rcv,
  44             unicast_flag;
  45)
  46
  47struct sockaddr_ll src_pk, dst_pk; 
  48struct in_addr src_addr, dest_addr;
  49extern void *mempcpy(void *dest, const void *src, size_t n);
  50
  51// Gets information of INTERFACE and updates IFINDEX, MAC and IP.
  52static void get_interface(char *interface, int *ifindex, uint32_t *oip, 
  53    uint8_t *mac)
  54{
  55  struct ifreq req;
  56  struct sockaddr_in *ip;
  57  int fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW);
  58
  59  req.ifr_addr.sa_family = AF_INET;
  60  xstrncpy(req.ifr_name, interface, IFNAMSIZ);
  61  req.ifr_name[IFNAMSIZ-1] = '\0';
  62
  63  xioctl(fd, SIOCGIFFLAGS, &req);
  64  if (!(req.ifr_flags & IFF_UP)) return;
  65
  66  if (oip) {
  67    xioctl(fd, SIOCGIFADDR, &req);
  68    ip = (struct sockaddr_in*) &req.ifr_addr;
  69    *oip = ntohl(ip->sin_addr.s_addr);
  70  }
  71  if (ifindex) {
  72    xioctl(fd, SIOCGIFINDEX, &req);
  73    *ifindex = req.ifr_ifindex;
  74  }
  75  if (mac) {
  76    xioctl(fd, SIOCGIFHWADDR, &req);
  77    memcpy(mac, req.ifr_hwaddr.sa_data, 6);
  78  }
  79  xclose(fd);
  80}
  81
  82// SIGINT handler, Print Number of Packets send or receive details.
  83static void done(int sig)
  84{
  85  if (!(toys.optflags & FLAG_q)) {
  86    xprintf("Sent %u probe(s) (%u broadcast(s))\n", TT.sent_nr, TT.brd_sent);
  87    xprintf("Received %u repl%s (%u request(s), %u broadcast(s))\n", 
  88        TT.rcvd_nr, TT.rcvd_nr == 1 ? "y":"ies", TT.rcvd_req, TT.brd_rcv);
  89  }
  90  if (toys.optflags & FLAG_D) exit(!!TT.rcvd_nr);
  91  //In -U mode, No reply is expected.
  92  if (toys.optflags & FLAG_U) exit(EXIT_SUCCESS); 
  93  exit(!TT.rcvd_nr);
  94}
  95
  96// Create and Send Packet 
  97static void send_packet()
  98{
  99  int ret;
 100  unsigned char sbuf[256] = {0,};
 101  struct arphdr *arp_h = (struct arphdr *) sbuf;
 102  unsigned char *ptr = (unsigned char *)(arp_h + 1);
 103
 104  arp_h->ar_hrd = htons(ARPHRD_ETHER);
 105  arp_h->ar_pro = htons(ETH_P_IP);
 106  arp_h->ar_hln = src_pk.sll_halen;
 107  arp_h->ar_pln = 4;  
 108  arp_h->ar_op = (toys.optflags & FLAG_A) ? htons(ARPOP_REPLY) 
 109    : htons(ARPOP_REQUEST);
 110
 111  ptr = mempcpy(ptr, &src_pk.sll_addr, src_pk.sll_halen);
 112  ptr = mempcpy(ptr, &src_addr, 4);
 113  ptr = mempcpy(ptr,
 114                (toys.optflags & FLAG_A) ? &src_pk.sll_addr : &dst_pk.sll_addr,
 115                src_pk.sll_halen);
 116  ptr = mempcpy(ptr, &dest_addr, 4);
 117
 118  ret = sendto(TT.sockfd, sbuf, ptr - sbuf, 0, 
 119      (struct sockaddr *)&dst_pk, sizeof(dst_pk));
 120  if (ret == ptr - sbuf) {
 121    struct timeval tval;
 122
 123    gettimeofday(&tval, NULL);
 124    TT.sent_at = tval.tv_sec * 1000000ULL + tval.tv_usec;
 125    TT.sent_nr++;
 126    if (!TT.unicast_flag) TT.brd_sent++;
 127  }
 128}
 129
 130// Receive Packet and filter with valid checks.
 131static void recv_from(struct sockaddr_ll *from, int *recv_len)
 132{
 133  struct in_addr s_ip, d_ip;
 134  struct arphdr *arp_hdr = (struct arphdr *)toybuf;
 135  unsigned char *p = (unsigned char *)(arp_hdr + 1);
 136
 137  if (arp_hdr->ar_op != htons(ARPOP_REQUEST) && 
 138      arp_hdr->ar_op != htons(ARPOP_REPLY)) return; 
 139
 140  if (from->sll_pkttype != PACKET_HOST && from->sll_pkttype != PACKET_BROADCAST
 141      && from->sll_pkttype != PACKET_MULTICAST) return; 
 142
 143  if (arp_hdr->ar_pro != htons(ETH_P_IP) || (arp_hdr->ar_pln != 4) 
 144      || (arp_hdr->ar_hln != src_pk.sll_halen) 
 145      || (*recv_len < (int)(sizeof(*arp_hdr) + 2 * (4 + arp_hdr->ar_hln))))
 146    return; 
 147
 148  memcpy(&s_ip.s_addr, p + arp_hdr->ar_hln, 4);
 149  memcpy(&d_ip.s_addr, p + arp_hdr->ar_hln + 4 + arp_hdr->ar_hln, 4); 
 150
 151  if (dest_addr.s_addr != s_ip.s_addr) return;
 152  if (toys.optflags & FLAG_D) {
 153    if (src_addr.s_addr && src_addr.s_addr != d_ip.s_addr) return;
 154    if (!memcmp(p, &src_pk.sll_addr, src_pk.sll_halen)) return;
 155  } else if (src_addr.s_addr != d_ip.s_addr ) return;
 156
 157  if (!(toys.optflags & FLAG_q)) {
 158    printf("%scast re%s from %s [%s]",
 159        from->sll_pkttype == PACKET_HOST ? "Uni" : "Broad",
 160        arp_hdr->ar_op == htons(ARPOP_REPLY) ? "ply" : "quest",
 161        inet_ntoa(s_ip), ether_ntoa((struct ether_addr *) p));
 162    if (TT.sent_at) {  
 163      unsigned delta;
 164      struct timeval tval;
 165
 166      gettimeofday(&tval, NULL);
 167      delta = (tval.tv_sec * 1000000ULL + (tval.tv_usec)) - TT.sent_at;
 168      xprintf(" %u.%03ums\n", delta / 1000, delta % 1000);
 169    }
 170  }
 171  TT.rcvd_nr++;
 172  if (from->sll_pkttype != PACKET_HOST) TT.brd_rcv++;
 173  if (arp_hdr->ar_op == htons(ARPOP_REQUEST)) TT.rcvd_req++;
 174  if (toys.optflags & FLAG_f) done(0);
 175  if (!(toys.optflags & FLAG_b)) {
 176    memcpy(dst_pk.sll_addr, p, src_pk.sll_halen);
 177    TT.unicast_flag = 1;
 178  }
 179}
 180
 181// Alarm signal Handle, send packets in one second interval.
 182static void send_signal(int sig)
 183{
 184  struct timeval start;
 185
 186  gettimeofday(&start, NULL);
 187  if (!TT.start) 
 188    TT.end = TT.start = start.tv_sec * 1000 + start.tv_usec / 1000;
 189  else TT.end = start.tv_sec*1000 + start.tv_usec / 1000;
 190  if (toys.optflags & FLAG_c) {
 191    if (!TT.count) done(0);
 192    TT.count--; 
 193  }
 194  if ((toys.optflags & FLAG_w) && ((TT.end - TT.start) > 
 195        ((TT.time_out)*1000))) done(0);
 196  send_packet();
 197  alarm(1);
 198}
 199
 200void arping_main(void)
 201{
 202  struct ifreq ifr;
 203  struct sockaddr_ll from;
 204  socklen_t len;
 205  int if_index, recv_len;
 206
 207  if (!(toys.optflags & FLAG_I)) TT.iface = "eth0";
 208  TT.sockfd = xsocket(AF_PACKET, SOCK_DGRAM, 0);
 209
 210  memset(&ifr, 0, sizeof(ifr));
 211  xstrncpy(ifr.ifr_name, TT.iface, IFNAMSIZ);
 212  get_interface(TT.iface, &if_index, NULL, NULL);
 213  src_pk.sll_ifindex = if_index;
 214
 215  xioctl(TT.sockfd, SIOCGIFFLAGS, (char*)&ifr);
 216  if (!(ifr.ifr_flags & IFF_UP) && !(toys.optflags & FLAG_q))
 217    error_exit("Interface \"%s\" is down", TT.iface);
 218  if ((ifr.ifr_flags & (IFF_NOARP | IFF_LOOPBACK))
 219      && !(toys.optflags & FLAG_q)) {
 220    xprintf("Interface \"%s\" is not ARPable\n", TT.iface);
 221    toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2;
 222    return;
 223  }
 224  if (!inet_aton(*toys.optargs, &dest_addr)) {
 225    struct hostent *hp = gethostbyname2(*toys.optargs, AF_INET);
 226
 227    if (!hp) perror_exit("bad address '%s'", *toys.optargs);
 228    memcpy(&dest_addr, hp->h_addr, 4);
 229  }
 230  if ((toys.optflags & FLAG_s) && !(inet_aton(TT.src_ip, &src_addr))) 
 231    perror_exit("invalid source address '%s'",TT.src_ip);
 232  if (!(toys.optflags & FLAG_D) && (toys.optflags & FLAG_U) 
 233      && !src_addr.s_addr) src_addr = dest_addr;
 234  if (!(toys.optflags & FLAG_D) || src_addr.s_addr) {
 235    struct sockaddr_in saddr;
 236    int p_fd = xsocket(AF_INET, SOCK_DGRAM, 0);
 237
 238    if (setsockopt(p_fd, SOL_SOCKET, SO_BINDTODEVICE, TT.iface,
 239          strlen(TT.iface))) perror_exit("setsockopt");
 240
 241    memset(&saddr, 0, sizeof(saddr));
 242    saddr.sin_family = AF_INET;
 243    if (src_addr.s_addr) {
 244      saddr.sin_addr = src_addr;
 245      if (bind(p_fd, (struct sockaddr*)&saddr, sizeof(saddr))) 
 246        perror_exit("bind");
 247    } else {
 248      uint32_t oip;
 249
 250      saddr.sin_port = htons(1025);
 251      saddr.sin_addr = dest_addr;
 252      if (connect(p_fd, (struct sockaddr *) &saddr, sizeof(saddr)))
 253        perror_exit("cannot connect to remote host");
 254      get_interface(TT.iface, NULL, &oip, NULL);
 255      src_addr.s_addr = htonl(oip);
 256    }
 257    xclose(p_fd);
 258  }
 259
 260  src_pk.sll_family = AF_PACKET;
 261  src_pk.sll_protocol = htons(ETH_P_ARP);
 262  if (bind(TT.sockfd, (struct sockaddr *)&src_pk, sizeof(src_pk))) 
 263    perror_exit("bind");
 264
 265  socklen_t alen = sizeof(src_pk);
 266  getsockname(TT.sockfd, (struct sockaddr *)&src_pk, &alen);
 267  if (!src_pk.sll_halen) {
 268    perror_msg("src is not arpable");
 269    toys.exitval = (toys.optflags & FLAG_D) ? 0 : 2;
 270    return;
 271  }
 272  if (!(toys.optflags & FLAG_q)) {
 273    xprintf("ARPING to %s", inet_ntoa(dest_addr));
 274    xprintf(" from %s via %s\n", inet_ntoa(src_addr), TT.iface);
 275  }
 276
 277  dst_pk = src_pk;
 278  //First packet always broadcasts.
 279  memset(dst_pk.sll_addr, -1, dst_pk.sll_halen);
 280  signal(SIGINT, done);
 281  signal(SIGALRM, send_signal);
 282
 283  send_signal(0); // Send first Broadcast message.
 284  while (1) {
 285    len = sizeof(from);
 286    recv_len = recvfrom(TT.sockfd, toybuf, 4096, 0,
 287        (struct sockaddr *)&from, &len);
 288    if (recv_len < 0) continue;
 289    recv_from(&from, &recv_len);
 290  }
 291}
 292