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 = 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