toybox/toys/pending/arp.c
<<
>>
Prefs
   1/* arp.c - manipulate the system ARP cache
   2 *
   3 * Copyright 2014 Sandeep Sharma <sandeep.jack2756@gmail.com>
   4 * Copyright 2014 Kyungwan Han <asura321@gamil.com>
   5 * No Standard
   6
   7USE_ARP(NEWTOY(arp, "vi:nDsdap:A:H:[+Ap][!sd]", TOYFLAG_USR|TOYFLAG_BIN))
   8
   9config ARP
  10  bool "arp"
  11  default n
  12  help
  13    usage: arp
  14    [-vn] [-H HWTYPE] [-i IF] -a [HOSTNAME]
  15    [-v]              [-i IF] -d HOSTNAME [pub]
  16    [-v]  [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [temp]
  17    [-v]  [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [netmask MASK] pub
  18    [-v]  [-H HWTYPE] [-i IF] -Ds HOSTNAME IFACE [netmask MASK] pub
  19
  20    Manipulate ARP cache.
  21
  22    -a  Display (all) hosts
  23    -s  Set new ARP entry
  24    -d  Delete a specified entry
  25    -v  Verbose
  26    -n  Don't resolve names
  27    -i IFACE    Network interface
  28    -D  Read <hwaddr> from given device
  29    -A,-p AF    Protocol family
  30    -H HWTYPE   Hardware address type
  31
  32*/
  33
  34#define FOR_arp
  35#include "toys.h"
  36#include <net/if_arp.h>
  37
  38GLOBALS(
  39    char *hw_type;
  40    char *af_type_A;
  41    char *af_type_p;
  42    char *interface;
  43
  44    int sockfd;
  45    char *device;
  46)
  47
  48struct arpreq req;
  49
  50struct type {
  51  char *name;
  52  int val;
  53};
  54
  55struct type hwtype[] = {
  56  {"ether", ARPHRD_ETHER },
  57  {"loop" ,ARPHRD_LOOPBACK},
  58  {"ppp" ,ARPHRD_PPP},
  59  {"infiniband" ,ARPHRD_INFINIBAND},
  60  {NULL, -1},
  61};
  62
  63struct type aftype[] = {
  64  {"inet", AF_INET },
  65  {"inet6" ,AF_INET6},
  66  {"unspec" ,AF_UNSPEC},
  67  {NULL, -1},
  68};
  69
  70struct type flag_type[] = {
  71  {"PERM", ATF_PERM },
  72  {"PUB" ,ATF_PUBL},
  73  {"DONTPUB" ,ATF_DONTPUB},
  74  {"TRAIL" ,ATF_USETRAILERS},
  75  {NULL, -1},
  76};
  77
  78static int get_index(struct type arr[], char *name)
  79{
  80  int i;
  81
  82  for (i = 0; arr[i].name; i++)
  83    if (!strcmp(arr[i].name, name)) break;
  84  return arr[i].val;
  85}
  86
  87static void resolve_host(char *host, struct sockaddr *sa)
  88{
  89  struct addrinfo *ai = xgetaddrinfo(host, NULL, AF_INET, SOCK_STREAM, 0, 0);
  90
  91  memcpy(sa, ai->ai_addr, ai->ai_addrlen);
  92  freeaddrinfo(ai);
  93}
  94
  95static void check_flags(int *i, char** argv)
  96{
  97  struct sockaddr sa;
  98  int flag = *i, j;
  99  struct flags {
 100    char *name;
 101    int or, flag;
 102  } f[] = {
 103    {"pub",  1 ,ATF_PUBL},
 104    {"priv", 0 ,~ATF_PUBL},
 105    {"trail", 1, ATF_USETRAILERS},
 106    {"temp", 0, ~ATF_PERM},
 107    {"dontpub",1, ATF_DONTPUB},
 108  };
 109  
 110  for (;*argv; argv++) {
 111    for (j = 0;  j < ARRAY_LEN(f); j++) { 
 112      if (!strcmp(*argv, f[j].name)) {
 113        (f[j].or) ?(flag |= f[j].flag):(flag &= f[j].flag);
 114        break;
 115      }
 116    }
 117    if (j > 4 && !strcmp(*argv, "netmask")) {
 118      if (!*++argv) error_exit("NULL netmask");
 119      if (strcmp(*argv, "255.255.255.255")) {
 120        resolve_host(toys.optargs[0], &sa);
 121        memcpy(&req.arp_netmask, &sa, sizeof(sa));
 122        flag |= ATF_NETMASK;
 123      } else argv++; 
 124    } else if (j > 4 && !strcmp(*argv, "dev")) {
 125      if (!*++argv) error_exit("NULL dev");
 126      TT.device = *argv;
 127    } else if (j > 4) error_exit("invalid arg");
 128  }
 129  *i = flag;
 130}
 131
 132static int set_entry(void) 
 133{
 134  int flags = 0;
 135  
 136  if (!toys.optargs[1]) error_exit("bad syntax");
 137
 138  if (!FLAG(D)) {
 139    char *ptr = toys.optargs[1];
 140    char *p = ptr, *hw_addr = req.arp_ha.sa_data;
 141
 142    while (*hw_addr && (p-ptr) < 6) {
 143      int val, len;
 144
 145      if (*hw_addr == ':') hw_addr++;
 146      if (!sscanf(hw_addr, "%2x%n", &val, &len)) break;
 147      hw_addr += len;
 148      *p++ = val;
 149    }
 150
 151    if ((p-ptr) != 6 || *hw_addr)
 152      error_exit("bad hw addr '%s'", req.arp_ha.sa_data);
 153  } else {
 154    struct ifreq ifre;
 155
 156    xstrncpy(ifre.ifr_name, toys.optargs[1], IFNAMSIZ);
 157    xioctl(TT.sockfd, SIOCGIFHWADDR, &ifre);
 158    if (FLAG(H) && ifre.ifr_hwaddr.sa_family != ARPHRD_ETHER)
 159      error_exit("protocol type mismatch");
 160    memcpy(&req.arp_ha, &(ifre.ifr_hwaddr), sizeof(req.arp_ha));
 161  }
 162
 163  flags = ATF_PERM | ATF_COM;
 164  if (toys.optargs[2]) check_flags(&flags, (toys.optargs+2));
 165  req.arp_flags = flags;
 166  xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
 167  xioctl(TT.sockfd, SIOCSARP, &req);
 168
 169  if (FLAG(v)) xprintf("Entry set for %s\n", toys.optargs[0]);
 170  return 0;
 171}
 172
 173static int ip_to_host(struct sockaddr *sa, int flag)
 174{
 175  int status = 0;
 176  char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,}; 
 177  socklen_t len = sizeof(struct sockaddr_in6);
 178  
 179  *toybuf = 0;
 180  if (!(status = getnameinfo(sa, len, hbuf, sizeof(hbuf), sbuf, 
 181          sizeof(sbuf), flag))) {
 182    strcpy(toybuf, hbuf);
 183    return 0;
 184  }
 185  return 1;
 186}
 187
 188static int delete_entry(void)
 189{
 190  int flags = ATF_PERM;
 191
 192  if (toys.optargs[1]) check_flags(&flags, (toys.optargs+1));
 193  req.arp_flags = flags;
 194  xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
 195  xioctl(TT.sockfd, SIOCDARP, &req);
 196
 197  if (FLAG(v)) xprintf("Delete entry for  %s\n", toys.optargs[0]);
 198  return 0;
 199}
 200
 201void arp_main(void)
 202{
 203  struct sockaddr sa;
 204  char ip[16], hw_addr[30], mask[16], dev[16], *host_ip = NULL;
 205  FILE *fp;
 206  int h_type, type, flag, i, entries = 0, disp = 0;
 207
 208  TT.device = "";
 209  memset(&sa, 0, sizeof(sa));
 210  TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
 211
 212  if (FLAG(A) || FLAG(p)) {
 213    if ((type = get_index(aftype,
 214            (TT.af_type_A)?TT.af_type_A:TT.af_type_p)) != AF_INET)
 215      error_exit((type != -1)?"only inet supported by kernel":"unknown family");
 216  }
 217
 218  req.arp_ha.sa_family = ARPHRD_ETHER;
 219  if (FLAG(H)) {
 220    if ((type = get_index(hwtype, TT.hw_type)) != ARPHRD_ETHER)
 221      error_exit((type != -1)?"h/w type not supported":"unknown h/w type");
 222    req.arp_ha.sa_family = type;
 223  }
 224
 225  if (FLAG(s) || FLAG(d)) {
 226    if (!toys.optargs[0]) error_exit("-%c needs a host name", FLAG(d)?'d':'s');
 227    resolve_host(toys.optargs[0], &sa);
 228    memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
 229
 230    if (FLAG(s) && !set_entry()) return;
 231    if (FLAG(d) && !delete_entry()) return;
 232  }
 233
 234  // Show arp cache.
 235
 236  if (toys.optargs[0]) {
 237    resolve_host(toys.optargs[0], &sa);
 238    ip_to_host(&sa, NI_NUMERICHOST);
 239    host_ip = xstrdup(toybuf);
 240  }
 241
 242  fp = xfopen("/proc/net/arp", "r");
 243  fgets(toybuf, sizeof(toybuf), fp); // Skip header.
 244  while (fscanf(fp, "%15s 0x%x 0x%x %29s %15s %15s",
 245                ip, &h_type, &flag, hw_addr, mask, dev) == 6) {
 246    char *host_name = "?";
 247
 248    entries++;
 249    if ((FLAG(H) && get_index(hwtype, TT.hw_type) != h_type) ||
 250      (FLAG(i) && strcmp(TT.interface, dev)) ||
 251      (toys.optargs[0] && strcmp(host_ip, ip))) {
 252      continue;
 253    }
 254
 255    resolve_host(ip, &sa);
 256    if (FLAG(n)) ip_to_host(&sa, NI_NUMERICHOST);
 257    else if (!ip_to_host(&sa, NI_NAMEREQD)) host_name = toybuf;
 258
 259    disp++;
 260    printf("%s (%s) at" , host_name, ip);
 261
 262    for (i = 0; hwtype[i].name; i++)
 263      if (hwtype[i].val & h_type) break;
 264    if (!hwtype[i].name) error_exit("unknown h/w type");
 265
 266    if (!(flag & ATF_COM)) {
 267      if ((flag & ATF_PUBL)) printf(" *");
 268      else printf(" <incomplete>");
 269    } else printf(" %s [%s]", hw_addr, hwtype[i].name);
 270
 271    if (flag & ATF_NETMASK) printf("netmask %s ", mask);
 272
 273    for (i = 0; flag_type[i].name; i++)
 274      if (flag_type[i].val & flag) printf(" %s", flag_type[i].name);
 275
 276    printf(" on %s\n", dev);
 277  }
 278
 279  if (FLAG(v))
 280    xprintf("Entries: %d\tSkipped: %d\tFound: %d\n",
 281        entries, entries - disp, disp);
 282  if (toys.optargs[0] && !disp)
 283    xprintf("%s (%s) -- no entry\n", toys.optargs[0], host_ip);
 284
 285  if (CFG_TOYBOX_FREE) {
 286    free(host_ip);
 287    fclose(fp);
 288  }
 289}
 290