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