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 IF 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; //Global request structure 
  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
  87
  88void get_hw_add(char *hw_addr, char *ptr) 
  89{
  90  char *p = ptr, *hw = hw_addr;
  91
  92  while (*hw_addr && (p-ptr) < 6) {
  93    int val, len = 0;
  94
  95    if (*hw_addr == ':') hw_addr++;
  96    sscanf(hw_addr, "%2x%n", &val, &len);
  97    if (!len || len > 2) break;
  98    hw_addr += len;
  99    *p++ = val;
 100  }
 101
 102  if ((p-ptr) != 6 || *hw_addr)
 103    error_exit("bad hw addr '%s'", hw);
 104}
 105
 106static void resolve_host(char *host, struct sockaddr *sa)
 107{
 108  struct addrinfo hints, *res = NULL;
 109  int ret;
 110
 111  memset(&hints, 0, sizeof hints);
 112  hints.ai_family = AF_INET;
 113  hints.ai_socktype = SOCK_STREAM;
 114  if ((ret = getaddrinfo(host, NULL, &hints, &res))) 
 115    perror_exit("%s", gai_strerror(ret));
 116
 117  memcpy(sa, res->ai_addr, res->ai_addrlen);
 118  freeaddrinfo(res);
 119}
 120
 121static void check_flags(int *i, char** argv)
 122{
 123  struct sockaddr sa;
 124  int flag = *i, j;
 125  struct flags {
 126    char *name;
 127    int or, flag;
 128  } f[] = {
 129    {"pub",  1 ,ATF_PUBL},
 130    {"priv", 0 ,~ATF_PUBL},
 131    {"trail", 1, ATF_USETRAILERS},
 132    {"temp", 0, ~ATF_PERM},
 133    {"dontpub",1, ATF_DONTPUB},
 134  };
 135  
 136  for (;*argv; argv++) {
 137    for (j = 0;  j < ARRAY_LEN(f); j++) { 
 138      if (!strcmp(*argv, f[j].name)) {
 139        (f[j].or) ?(flag |= f[j].flag):(flag &= f[j].flag);
 140        break;
 141      }
 142    }
 143    if (j > 4 && !strcmp(*argv, "netmask")) {
 144      if (!*++argv) error_exit("NULL netmask");
 145      if (strcmp(*argv, "255.255.255.255")) {
 146        resolve_host(toys.optargs[0], &sa);
 147        memcpy(&req.arp_netmask, &sa, sizeof(sa));
 148        flag |= ATF_NETMASK;
 149      } else argv++; 
 150    } else if (j > 4 && !strcmp(*argv, "dev")) {
 151      if (!*++argv) error_exit("NULL dev");
 152      TT.device = *argv;
 153    } else if (j > 4) error_exit("invalid arg");
 154  }
 155  *i = flag;
 156}
 157
 158static int set_entry(void) 
 159{
 160  int flags = 0;
 161  
 162  if (!toys.optargs[1]) error_exit("bad syntax");
 163
 164  if (!(toys.optflags & FLAG_D)) get_hw_add(toys.optargs[1], (char*)&req.arp_ha.sa_data);
 165  else {
 166    struct ifreq ifre;
 167
 168    xstrncpy(ifre.ifr_name, toys.optargs[1], IFNAMSIZ);
 169    xioctl(TT.sockfd, SIOCGIFHWADDR, &ifre);
 170    if ((toys.optflags & FLAG_H) && (ifre.ifr_hwaddr.sa_family != ARPHRD_ETHER)) 
 171      error_exit("protocol type mismatch");
 172    memcpy(&req.arp_ha, &(ifre.ifr_hwaddr), sizeof(req.arp_ha));
 173  }
 174
 175  flags = ATF_PERM | ATF_COM;
 176  if (toys.optargs[2]) check_flags(&flags, (toys.optargs+2));
 177  req.arp_flags = flags;
 178  xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
 179  xioctl(TT.sockfd, SIOCSARP, &req);
 180  
 181  if (toys.optflags & FLAG_v) xprintf("Entry set for %s\n", toys.optargs[0]);
 182  return 0;
 183}
 184
 185static int ip_to_host(struct sockaddr *sa, int flag) 
 186{
 187  int status = 0;
 188  char hbuf[NI_MAXHOST] = {0,}, sbuf[NI_MAXSERV] = {0,}; 
 189  socklen_t len = sizeof(struct sockaddr_in6);
 190  
 191  *toybuf = 0;
 192  if (!(status = getnameinfo(sa, len, hbuf, sizeof(hbuf), sbuf, 
 193          sizeof(sbuf), flag))) {
 194    strcpy(toybuf, hbuf);
 195    return 0;
 196  }
 197  return 1;
 198}
 199
 200static int delete_entry(void)
 201{
 202  int flags;
 203  
 204  flags = ATF_PERM;
 205  if (toys.optargs[1]) check_flags(&flags, (toys.optargs+1));
 206  req.arp_flags = flags;
 207  xstrncpy(req.arp_dev, TT.device, sizeof(req.arp_dev));
 208  xioctl(TT.sockfd, SIOCDARP, &req);
 209  
 210  if (toys.optflags & FLAG_v) xprintf("Delete entry for  %s\n", toys.optargs[0]);
 211  return 0;
 212}
 213
 214void arp_main(void)
 215{
 216  struct sockaddr sa;
 217  char ip[128], hw_addr[128], mask[12], dev[128], *host_ip = NULL, *buf;
 218  int h_type, type, flag, i, fd, entries = 0, disp = 0;
 219
 220  TT.device = "";
 221  memset(&sa, 0, sizeof(sa));
 222  memset(&req, 0, sizeof(req));
 223  TT.sockfd = xsocket(AF_INET, SOCK_STREAM, 0);
 224
 225  if ((toys.optflags & FLAG_A) || (toys.optflags & FLAG_p)) {
 226    if ((type = get_index(aftype, 
 227            (TT.af_type_A)?TT.af_type_A:TT.af_type_p)) != AF_INET) 
 228      error_exit((type != -1)?"only inet supported by kernel":"unknown family");
 229  } 
 230
 231  req.arp_ha.sa_family = ARPHRD_ETHER;
 232  if (toys.optflags & FLAG_H) {
 233    if ((type = get_index(hwtype, TT.hw_type)) != ARPHRD_ETHER) 
 234      error_exit((type != -1)?"h/w type not supported":"unknown h/w type");
 235    req.arp_ha.sa_family = type;
 236  }
 237
 238  if (((toys.optflags & FLAG_s) || toys.optflags & FLAG_d)) { 
 239    if (!toys.optargs[0]) error_exit("host name req");
 240    resolve_host(toys.optargs[0], &sa);
 241    memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
 242  }
 243
 244  if ((toys.optflags & FLAG_s) && !set_entry()) return;
 245  if ((toys.optflags & FLAG_d) && !delete_entry()) return; 
 246
 247  //show arp chache
 248  fd = xopenro("/proc/net/arp");
 249  buf = get_line(fd);
 250  free(buf); //skip first line
 251
 252  if (toys.optargs[0]) {
 253    resolve_host(toys.optargs[0], &sa);
 254    ip_to_host(&sa, NI_NUMERICHOST);
 255    host_ip = xstrdup(toybuf);
 256  }
 257
 258  while ((buf = get_line(fd))) {
 259    char *host_name = "?";
 260    
 261    if ((sscanf(buf, "%s 0x%x 0x%x %s %s %s\n", ip,
 262        &h_type, &flag, hw_addr, mask, dev )) != 6) break;
 263    entries++;
 264    if (((toys.optflags & FLAG_H) && (get_index(hwtype, TT.hw_type) != h_type))
 265     || ((toys.optflags & FLAG_i) && strcmp(TT.interface, dev))
 266     || (toys.optargs[0] && strcmp(host_ip, ip))) {
 267      free(buf);
 268      continue;
 269    }
 270
 271    resolve_host(buf, &sa);
 272    if (!(toys.optflags & FLAG_n)) { 
 273      if (!ip_to_host(&sa, NI_NAMEREQD)) host_name = toybuf;
 274    } else ip_to_host(&sa, NI_NUMERICHOST);
 275    
 276    disp++;
 277    printf("%s (%s) at" , host_name, ip);
 278
 279    for (i = 0; hwtype[i].name; i++) 
 280      if (hwtype[i].val & h_type) break;
 281    if (!hwtype[i].name) error_exit("unknown h/w type");
 282
 283    if (!(flag & ATF_COM)) {
 284      if ((flag & ATF_PUBL)) printf(" *");
 285      else printf(" <incomplete>");
 286    } else printf(" %s [%s]", hw_addr, hwtype[i].name);
 287
 288    if (flag & ATF_NETMASK) printf("netmask %s ", mask);
 289
 290    for (i = 0; flag_type[i].name; i++) 
 291      if (flag_type[i].val & flag) printf(" %s", flag_type[i].name);
 292
 293    printf(" on %s\n", dev);
 294    free(buf);
 295  }
 296  
 297  if (toys.optflags & FLAG_v) 
 298    xprintf("Entries: %d\tSkipped: %d\tFound: %d\n",
 299        entries, entries - disp, disp);
 300  if (!disp) xprintf("No Match found in %d entries\n", entries);
 301  
 302  if (CFG_TOYBOX_FREE) {
 303    free(host_ip);
 304    free(buf);
 305    xclose(fd);
 306  }
 307}
 308