Home | History | Annotate | Download | only in pending
      1 /* arp.c - manipulate the system ARP cache
      2  *
      3  * Copyright 2014 Sandeep Sharma <sandeep.jack2756 (at) gmail.com>
      4  * Copyright 2014 Kyungwan Han <asura321 (at) gamil.com>
      5  * No Standard
      6 
      7 USE_ARP(NEWTOY(arp, "vi:nDsdap:A:H:[+Ap][!sd]", TOYFLAG_USR|TOYFLAG_BIN))
      8 
      9 config 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 
     38 GLOBALS(
     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 
     48 struct arpreq req; //Global request structure
     49 
     50 struct type {
     51   char *name;
     52   int val;
     53 };
     54 
     55 struct type hwtype[] = {
     56   {"ether", ARPHRD_ETHER },
     57   {"loop" ,ARPHRD_LOOPBACK},
     58   {"ppp" ,ARPHRD_PPP},
     59   {"infiniband" ,ARPHRD_INFINIBAND},
     60   {NULL, -1},
     61 };
     62 
     63 struct type aftype[] = {
     64   {"inet", AF_INET },
     65   {"inet6" ,AF_INET6},
     66   {"unspec" ,AF_UNSPEC},
     67   {NULL, -1},
     68 };
     69 
     70 struct type flag_type[] = {
     71   {"PERM", ATF_PERM },
     72   {"PUB" ,ATF_PUBL},
     73   {"DONTPUB" ,ATF_DONTPUB},
     74   {"TRAIL" ,ATF_USETRAILERS},
     75   {NULL, -1},
     76 };
     77 
     78 static 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 
     88 void 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 
    106 static 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 
    121 static 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 
    158 static 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 
    185 static 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 
    200 static 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 
    214 void 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 = xopen("/proc/net/arp", O_RDONLY);
    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