arp.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * arp.c - Manipulate the system ARP cache
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version
  8. * 2 of the License, or (at your option) any later version.
  9. *
  10. * Author: Fred N. van Kempen, <waltje at uwalt.nl.mugnet.org>
  11. * Busybox port: Paul van Gool <pvangool at mimotech.com>
  12. *
  13. * modified for getopt32 by Arne Bernin <arne [at] alamut.de>
  14. */
  15. #include "libbb.h"
  16. #include "inet_common.h"
  17. #include <arpa/inet.h>
  18. #include <net/if.h>
  19. #include <net/if_arp.h>
  20. #include <netinet/ether.h>
  21. #include <netpacket/packet.h>
  22. #define DEBUG 0
  23. #define DFLT_AF "inet"
  24. #define DFLT_HW "ether"
  25. enum {
  26. ARP_OPT_A = (1 << 0),
  27. ARP_OPT_p = (1 << 1),
  28. ARP_OPT_H = (1 << 2),
  29. ARP_OPT_t = (1 << 3),
  30. ARP_OPT_i = (1 << 4),
  31. ARP_OPT_a = (1 << 5),
  32. ARP_OPT_d = (1 << 6),
  33. ARP_OPT_n = (1 << 7), /* do not resolve addresses */
  34. ARP_OPT_D = (1 << 8), /* HW-address is devicename */
  35. ARP_OPT_s = (1 << 9),
  36. ARP_OPT_v = (1 << 10) * DEBUG, /* debugging output flag */
  37. };
  38. enum {
  39. sockfd = 3, /* active socket descriptor */
  40. };
  41. struct globals {
  42. const struct aftype *ap; /* current address family */
  43. const struct hwtype *hw; /* current hardware type */
  44. const char *device; /* current device */
  45. smallint hw_set; /* flag if hw-type was set (-H) */
  46. } FIX_ALIASING;
  47. #define G (*(struct globals*)&bb_common_bufsiz1)
  48. #define ap (G.ap )
  49. #define hw (G.hw )
  50. #define device (G.device )
  51. #define hw_set (G.hw_set )
  52. #define INIT_G() do { \
  53. device = ""; \
  54. } while (0)
  55. static const char options[] ALIGN1 =
  56. "pub\0"
  57. "priv\0"
  58. "temp\0"
  59. "trail\0"
  60. "dontpub\0"
  61. "auto\0"
  62. "dev\0"
  63. "netmask\0";
  64. /* Delete an entry from the ARP cache. */
  65. /* Called only from main, once */
  66. static int arp_del(char **args)
  67. {
  68. char *host;
  69. struct arpreq req;
  70. struct sockaddr sa;
  71. int flags = 0;
  72. int err;
  73. memset(&req, 0, sizeof(req));
  74. /* Resolve the host name. */
  75. host = *args;
  76. if (ap->input(host, &sa) < 0) {
  77. bb_herror_msg_and_die("%s", host);
  78. }
  79. /* If a host has more than one address, use the correct one! */
  80. memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
  81. if (hw_set)
  82. req.arp_ha.sa_family = hw->type;
  83. req.arp_flags = ATF_PERM;
  84. args++;
  85. while (*args != NULL) {
  86. switch (index_in_strings(options, *args)) {
  87. case 0: /* "pub" */
  88. flags |= 1;
  89. args++;
  90. break;
  91. case 1: /* "priv" */
  92. flags |= 2;
  93. args++;
  94. break;
  95. case 2: /* "temp" */
  96. req.arp_flags &= ~ATF_PERM;
  97. args++;
  98. break;
  99. case 3: /* "trail" */
  100. req.arp_flags |= ATF_USETRAILERS;
  101. args++;
  102. break;
  103. case 4: /* "dontpub" */
  104. #ifdef HAVE_ATF_DONTPUB
  105. req.arp_flags |= ATF_DONTPUB;
  106. #else
  107. bb_error_msg("feature ATF_DONTPUB is not supported");
  108. #endif
  109. args++;
  110. break;
  111. case 5: /* "auto" */
  112. #ifdef HAVE_ATF_MAGIC
  113. req.arp_flags |= ATF_MAGIC;
  114. #else
  115. bb_error_msg("feature ATF_MAGIC is not supported");
  116. #endif
  117. args++;
  118. break;
  119. case 6: /* "dev" */
  120. if (*++args == NULL)
  121. bb_show_usage();
  122. device = *args;
  123. args++;
  124. break;
  125. case 7: /* "netmask" */
  126. if (*++args == NULL)
  127. bb_show_usage();
  128. if (strcmp(*args, "255.255.255.255") != 0) {
  129. host = *args;
  130. if (ap->input(host, &sa) < 0) {
  131. bb_herror_msg_and_die("%s", host);
  132. }
  133. memcpy(&req.arp_netmask, &sa, sizeof(struct sockaddr));
  134. req.arp_flags |= ATF_NETMASK;
  135. }
  136. args++;
  137. break;
  138. default:
  139. bb_show_usage();
  140. break;
  141. }
  142. }
  143. if (flags == 0)
  144. flags = 3;
  145. strncpy(req.arp_dev, device, sizeof(req.arp_dev));
  146. err = -1;
  147. /* Call the kernel. */
  148. if (flags & 2) {
  149. if (option_mask32 & ARP_OPT_v)
  150. bb_error_msg("SIOCDARP(nopub)");
  151. err = ioctl(sockfd, SIOCDARP, &req);
  152. if (err < 0) {
  153. if (errno == ENXIO) {
  154. if (flags & 1)
  155. goto nopub;
  156. printf("No ARP entry for %s\n", host);
  157. return -1;
  158. }
  159. bb_perror_msg_and_die("SIOCDARP(priv)");
  160. }
  161. }
  162. if ((flags & 1) && err) {
  163. nopub:
  164. req.arp_flags |= ATF_PUBL;
  165. if (option_mask32 & ARP_OPT_v)
  166. bb_error_msg("SIOCDARP(pub)");
  167. if (ioctl(sockfd, SIOCDARP, &req) < 0) {
  168. if (errno == ENXIO) {
  169. printf("No ARP entry for %s\n", host);
  170. return -1;
  171. }
  172. bb_perror_msg_and_die("SIOCDARP(pub)");
  173. }
  174. }
  175. return 0;
  176. }
  177. /* Get the hardware address to a specified interface name */
  178. static void arp_getdevhw(char *ifname, struct sockaddr *sa,
  179. const struct hwtype *hwt)
  180. {
  181. struct ifreq ifr;
  182. const struct hwtype *xhw;
  183. strcpy(ifr.ifr_name, ifname);
  184. ioctl_or_perror_and_die(sockfd, SIOCGIFHWADDR, &ifr,
  185. "cant get HW-Address for '%s'", ifname);
  186. if (hwt && (ifr.ifr_hwaddr.sa_family != hw->type)) {
  187. bb_error_msg_and_die("protocol type mismatch");
  188. }
  189. memcpy(sa, &(ifr.ifr_hwaddr), sizeof(struct sockaddr));
  190. if (option_mask32 & ARP_OPT_v) {
  191. xhw = get_hwntype(ifr.ifr_hwaddr.sa_family);
  192. if (!xhw || !xhw->print) {
  193. xhw = get_hwntype(-1);
  194. }
  195. bb_error_msg("device '%s' has HW address %s '%s'",
  196. ifname, xhw->name,
  197. xhw->print((unsigned char *) &ifr.ifr_hwaddr.sa_data));
  198. }
  199. }
  200. /* Set an entry in the ARP cache. */
  201. /* Called only from main, once */
  202. static int arp_set(char **args)
  203. {
  204. char *host;
  205. struct arpreq req;
  206. struct sockaddr sa;
  207. int flags;
  208. memset(&req, 0, sizeof(req));
  209. host = *args++;
  210. if (ap->input(host, &sa) < 0) {
  211. bb_herror_msg_and_die("%s", host);
  212. }
  213. /* If a host has more than one address, use the correct one! */
  214. memcpy(&req.arp_pa, &sa, sizeof(struct sockaddr));
  215. /* Fetch the hardware address. */
  216. if (*args == NULL) {
  217. bb_error_msg_and_die("need hardware address");
  218. }
  219. if (option_mask32 & ARP_OPT_D) {
  220. arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL);
  221. } else {
  222. if (hw->input(*args++, &req.arp_ha) < 0) {
  223. bb_error_msg_and_die("invalid hardware address");
  224. }
  225. }
  226. /* Check out any modifiers. */
  227. flags = ATF_PERM | ATF_COM;
  228. while (*args != NULL) {
  229. switch (index_in_strings(options, *args)) {
  230. case 0: /* "pub" */
  231. flags |= ATF_PUBL;
  232. args++;
  233. break;
  234. case 1: /* "priv" */
  235. flags &= ~ATF_PUBL;
  236. args++;
  237. break;
  238. case 2: /* "temp" */
  239. flags &= ~ATF_PERM;
  240. args++;
  241. break;
  242. case 3: /* "trail" */
  243. flags |= ATF_USETRAILERS;
  244. args++;
  245. break;
  246. case 4: /* "dontpub" */
  247. #ifdef HAVE_ATF_DONTPUB
  248. flags |= ATF_DONTPUB;
  249. #else
  250. bb_error_msg("feature ATF_DONTPUB is not supported");
  251. #endif
  252. args++;
  253. break;
  254. case 5: /* "auto" */
  255. #ifdef HAVE_ATF_MAGIC
  256. flags |= ATF_MAGIC;
  257. #else
  258. bb_error_msg("feature ATF_MAGIC is not supported");
  259. #endif
  260. args++;
  261. break;
  262. case 6: /* "dev" */
  263. if (*++args == NULL)
  264. bb_show_usage();
  265. device = *args;
  266. args++;
  267. break;
  268. case 7: /* "netmask" */
  269. if (*++args == NULL)
  270. bb_show_usage();
  271. if (strcmp(*args, "255.255.255.255") != 0) {
  272. host = *args;
  273. if (ap->input(host, &sa) < 0) {
  274. bb_herror_msg_and_die("%s", host);
  275. }
  276. memcpy(&req.arp_netmask, &sa, sizeof(struct sockaddr));
  277. flags |= ATF_NETMASK;
  278. }
  279. args++;
  280. break;
  281. default:
  282. bb_show_usage();
  283. break;
  284. }
  285. }
  286. /* Fill in the remainder of the request. */
  287. req.arp_flags = flags;
  288. strncpy(req.arp_dev, device, sizeof(req.arp_dev));
  289. /* Call the kernel. */
  290. if (option_mask32 & ARP_OPT_v)
  291. bb_error_msg("SIOCSARP()");
  292. xioctl(sockfd, SIOCSARP, &req);
  293. return 0;
  294. }
  295. /* Print the contents of an ARP request block. */
  296. static void
  297. arp_disp(const char *name, char *ip, int type, int arp_flags,
  298. char *hwa, char *mask, char *dev)
  299. {
  300. static const int arp_masks[] = {
  301. ATF_PERM, ATF_PUBL,
  302. #ifdef HAVE_ATF_MAGIC
  303. ATF_MAGIC,
  304. #endif
  305. #ifdef HAVE_ATF_DONTPUB
  306. ATF_DONTPUB,
  307. #endif
  308. ATF_USETRAILERS,
  309. };
  310. static const char arp_labels[] ALIGN1 = "PERM\0""PUP\0"
  311. #ifdef HAVE_ATF_MAGIC
  312. "AUTO\0"
  313. #endif
  314. #ifdef HAVE_ATF_DONTPUB
  315. "DONTPUB\0"
  316. #endif
  317. "TRAIL\0"
  318. ;
  319. const struct hwtype *xhw;
  320. xhw = get_hwntype(type);
  321. if (xhw == NULL)
  322. xhw = get_hwtype(DFLT_HW);
  323. printf("%s (%s) at ", name, ip);
  324. if (!(arp_flags & ATF_COM)) {
  325. if (arp_flags & ATF_PUBL)
  326. printf("* ");
  327. else
  328. printf("<incomplete> ");
  329. } else {
  330. printf("%s [%s] ", hwa, xhw->name);
  331. }
  332. if (arp_flags & ATF_NETMASK)
  333. printf("netmask %s ", mask);
  334. print_flags_separated(arp_masks, arp_labels, arp_flags, " ");
  335. printf(" on %s\n", dev);
  336. }
  337. /* Display the contents of the ARP cache in the kernel. */
  338. /* Called only from main, once */
  339. static int arp_show(char *name)
  340. {
  341. const char *host;
  342. const char *hostname;
  343. FILE *fp;
  344. struct sockaddr sa;
  345. int type, flags;
  346. int num;
  347. unsigned entries = 0, shown = 0;
  348. char ip[128];
  349. char hwa[128];
  350. char mask[128];
  351. char line[128];
  352. char dev[128];
  353. host = NULL;
  354. if (name != NULL) {
  355. /* Resolve the host name. */
  356. if (ap->input(name, &sa) < 0) {
  357. bb_herror_msg_and_die("%s", name);
  358. }
  359. host = xstrdup(ap->sprint(&sa, 1));
  360. }
  361. fp = xfopen_for_read("/proc/net/arp");
  362. /* Bypass header -- read one line */
  363. fgets(line, sizeof(line), fp);
  364. /* Read the ARP cache entries. */
  365. while (fgets(line, sizeof(line), fp)) {
  366. mask[0] = '-'; mask[1] = '\0';
  367. dev[0] = '-'; dev[1] = '\0';
  368. /* All these strings can't overflow
  369. * because fgets above reads limited amount of data */
  370. num = sscanf(line, "%s 0x%x 0x%x %s %s %s\n",
  371. ip, &type, &flags, hwa, mask, dev);
  372. if (num < 4)
  373. break;
  374. entries++;
  375. /* if the user specified hw-type differs, skip it */
  376. if (hw_set && (type != hw->type))
  377. continue;
  378. /* if the user specified address differs, skip it */
  379. if (host && strcmp(ip, host) != 0)
  380. continue;
  381. /* if the user specified device differs, skip it */
  382. if (device[0] && strcmp(dev, device) != 0)
  383. continue;
  384. shown++;
  385. /* This IS ugly but it works -be */
  386. hostname = "?";
  387. if (!(option_mask32 & ARP_OPT_n)) {
  388. if (ap->input(ip, &sa) < 0)
  389. hostname = ip;
  390. else
  391. hostname = ap->sprint(&sa, (option_mask32 & ARP_OPT_n) | 0x8000);
  392. if (strcmp(hostname, ip) == 0)
  393. hostname = "?";
  394. }
  395. arp_disp(hostname, ip, type, flags, hwa, mask, dev);
  396. }
  397. if (option_mask32 & ARP_OPT_v)
  398. printf("Entries: %d\tSkipped: %d\tFound: %d\n",
  399. entries, entries - shown, shown);
  400. if (!shown) {
  401. if (hw_set || host || device[0])
  402. printf("No match found in %d entries\n", entries);
  403. }
  404. if (ENABLE_FEATURE_CLEAN_UP) {
  405. free((char*)host);
  406. fclose(fp);
  407. }
  408. return 0;
  409. }
  410. int arp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  411. int arp_main(int argc UNUSED_PARAM, char **argv)
  412. {
  413. const char *hw_type = "ether";
  414. const char *protocol;
  415. unsigned opts;
  416. INIT_G();
  417. xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sockfd);
  418. ap = get_aftype(DFLT_AF);
  419. if (!ap)
  420. bb_error_msg_and_die("%s: %s not supported", DFLT_AF, "address family");
  421. opts = getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol,
  422. &hw_type, &hw_type, &device);
  423. argv += optind;
  424. if (opts & (ARP_OPT_A | ARP_OPT_p)) {
  425. ap = get_aftype(protocol);
  426. if (ap == NULL)
  427. bb_error_msg_and_die("%s: unknown %s", protocol, "address family");
  428. }
  429. if (opts & (ARP_OPT_A | ARP_OPT_p)) {
  430. hw = get_hwtype(hw_type);
  431. if (hw == NULL)
  432. bb_error_msg_and_die("%s: unknown %s", hw_type, "hardware type");
  433. hw_set = 1;
  434. }
  435. //if (opts & ARP_OPT_i)... -i
  436. if (ap->af != AF_INET) {
  437. bb_error_msg_and_die("%s: kernel only supports 'inet'", ap->name);
  438. }
  439. /* If no hw type specified get default */
  440. if (!hw) {
  441. hw = get_hwtype(DFLT_HW);
  442. if (!hw)
  443. bb_error_msg_and_die("%s: %s not supported", DFLT_HW, "hardware type");
  444. }
  445. if (hw->alen <= 0) {
  446. bb_error_msg_and_die("%s: %s without ARP support",
  447. hw->name, "hardware type");
  448. }
  449. /* Now see what we have to do here... */
  450. if (opts & (ARP_OPT_d | ARP_OPT_s)) {
  451. if (argv[0] == NULL)
  452. bb_error_msg_and_die("need host name");
  453. if (opts & ARP_OPT_s)
  454. return arp_set(argv);
  455. return arp_del(argv);
  456. }
  457. //if (opts & ARP_OPT_a) - default
  458. return arp_show(argv[0]);
  459. }