arp.c 7.1 KB

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