route.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * route
  4. *
  5. * Similar to the standard Unix route, but with only the necessary
  6. * parts for AF_INET and AF_INET6
  7. *
  8. * Bjorn Wesen, Axis Communications AB
  9. *
  10. * Author of the original route:
  11. * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  12. * (derived from FvK's 'route.c 1.70 01/04/94')
  13. *
  14. * Licensed under GPLv2 or later, see file LICENSE in this source tree.
  15. *
  16. *
  17. * displayroute() code added by Vladimir N. Oleynik <dzo@simtreas.ru>
  18. * adjustments by Larry Doolittle <LRDoolittle@lbl.gov>
  19. *
  20. * IPV6 support added by Bart Visscher <magick@linux-fan.com>
  21. */
  22. /* 2004/03/09 Manuel Novoa III <mjn3@codepoet.org>
  23. *
  24. * Rewritten to fix several bugs, add additional error checking, and
  25. * remove ridiculous amounts of bloat.
  26. */
  27. //config:config ROUTE
  28. //config: bool "route (9 kb)"
  29. //config: default y
  30. //config: help
  31. //config: Route displays or manipulates the kernel's IP routing tables.
  32. //applet:IF_ROUTE(APPLET(route, BB_DIR_SBIN, BB_SUID_DROP))
  33. //kbuild:lib-$(CONFIG_ROUTE) += route.o
  34. #include <net/route.h>
  35. #include <net/if.h>
  36. #include "libbb.h"
  37. #include "inet_common.h"
  38. #ifndef RTF_UP
  39. /* Keep this in sync with /usr/src/linux/include/linux/route.h */
  40. #define RTF_UP 0x0001 /* route usable */
  41. #define RTF_GATEWAY 0x0002 /* destination is a gateway */
  42. #define RTF_HOST 0x0004 /* host entry (net otherwise) */
  43. #define RTF_REINSTATE 0x0008 /* reinstate route after tmout */
  44. #define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */
  45. #define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */
  46. #define RTF_MTU 0x0040 /* specific MTU for this route */
  47. #ifndef RTF_MSS
  48. #define RTF_MSS RTF_MTU /* Compatibility :-( */
  49. #endif
  50. #define RTF_WINDOW 0x0080 /* per route window clamping */
  51. #define RTF_IRTT 0x0100 /* Initial round trip time */
  52. #define RTF_REJECT 0x0200 /* Reject route */
  53. #define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */
  54. #endif
  55. #if defined(SIOCADDRTOLD) || defined(RTF_IRTT) /* route */
  56. #define HAVE_NEW_ADDRT 1
  57. #endif
  58. #if HAVE_NEW_ADDRT
  59. #define mask_in_addr(x) (((struct sockaddr_in *)&((x).rt_genmask))->sin_addr.s_addr)
  60. #define full_mask(x) (x)
  61. #else
  62. #define mask_in_addr(x) ((x).rt_genmask)
  63. #define full_mask(x) (((struct sockaddr_in *)&(x))->sin_addr.s_addr)
  64. #endif
  65. /* The RTACTION entries must agree with tbl_verb[] below! */
  66. #define RTACTION_ADD 1
  67. #define RTACTION_DEL 2
  68. /* For the various tbl_*[] arrays, the 1st byte is return value. */
  69. #define NET_FLAG 1
  70. #define HOST_FLAG 2
  71. /* We remap '-' to '#' to avoid problems with getopt. */
  72. static const char tbl_hash_net_host[] ALIGN1 =
  73. "\001#net\0"
  74. "\002#host\0"
  75. ;
  76. #define KW_TAKES_ARG 020
  77. #define KW_SETS_FLAG 040
  78. #define KW_IPVx_METRIC 020
  79. #define KW_IPVx_NETMASK 021
  80. #define KW_IPVx_GATEWAY 022
  81. #define KW_IPVx_MSS 023
  82. #define KW_IPVx_WINDOW 024
  83. #define KW_IPVx_IRTT 025
  84. #define KW_IPVx_DEVICE 026
  85. #define KW_IPVx_FLAG_ONLY 040
  86. #define KW_IPVx_REJECT 040
  87. #define KW_IPVx_MOD 041
  88. #define KW_IPVx_DYN 042
  89. #define KW_IPVx_REINSTATE 043
  90. static const char tbl_ipvx[] ALIGN1 =
  91. /* 020 is the "takes an arg" bit */
  92. #if HAVE_NEW_ADDRT
  93. "\020metric\0"
  94. #endif
  95. "\021netmask\0"
  96. "\022gw\0"
  97. "\022gateway\0"
  98. "\023mss\0"
  99. "\024window\0"
  100. #ifdef RTF_IRTT
  101. "\025irtt\0"
  102. #endif
  103. "\026dev\0"
  104. "\026device\0"
  105. /* 040 is the "sets a flag" bit - MUST match flags_ipvx[] values below. */
  106. #ifdef RTF_REJECT
  107. "\040reject\0"
  108. #endif
  109. "\041mod\0"
  110. "\042dyn\0"
  111. "\043reinstate\0"
  112. ;
  113. static const uint16_t flags_ipvx[] ALIGN2 = { /* MUST match tbl_ipvx[] values above. */
  114. #ifdef RTF_REJECT
  115. RTF_REJECT,
  116. #endif
  117. RTF_MODIFIED,
  118. RTF_DYNAMIC,
  119. RTF_REINSTATE
  120. };
  121. static int kw_lookup(const char *kwtbl, char ***pargs)
  122. {
  123. if (**pargs) {
  124. do {
  125. if (strcmp(kwtbl + 1, **pargs) == 0) { /* Found a match. */
  126. *pargs += 1;
  127. if (kwtbl[0] & KW_TAKES_ARG) {
  128. if (!**pargs) { /* No more args! */
  129. bb_show_usage();
  130. }
  131. *pargs += 1; /* Calling routine will use args[-1]. */
  132. }
  133. return kwtbl[0];
  134. }
  135. kwtbl += strlen(kwtbl) + 1;
  136. } while (*kwtbl);
  137. }
  138. return 0;
  139. }
  140. /* Add or delete a route, depending on action. */
  141. static NOINLINE void INET_setroute(int action, char **args)
  142. {
  143. /* char buffer instead of bona-fide struct avoids aliasing warning */
  144. char rt_buf[sizeof(struct rtentry)];
  145. struct rtentry *const rt = (void *)rt_buf;
  146. const char *netmask = NULL;
  147. int skfd, isnet, xflag;
  148. /* Grab the -net or -host options. Remember they were transformed. */
  149. xflag = kw_lookup(tbl_hash_net_host, &args);
  150. /* If we did grab -net or -host, make sure we still have an arg left. */
  151. if (*args == NULL) {
  152. bb_show_usage();
  153. }
  154. /* Clean out the RTREQ structure. */
  155. memset(rt, 0, sizeof(*rt));
  156. {
  157. const char *target = *args++;
  158. char *prefix;
  159. /* recognize x.x.x.x/mask format. */
  160. prefix = strchr(target, '/');
  161. if (prefix) {
  162. int prefix_len;
  163. prefix_len = xatoul_range(prefix+1, 0, 32);
  164. mask_in_addr(*rt) = htonl( ~(0xffffffffUL >> prefix_len));
  165. *prefix = '\0';
  166. #if HAVE_NEW_ADDRT
  167. rt->rt_genmask.sa_family = AF_INET;
  168. #endif
  169. } else {
  170. /* Default netmask. */
  171. netmask = "default";
  172. }
  173. /* Prefer hostname lookup if -host flag (xflag==1) was given. */
  174. isnet = INET_resolve(target, (struct sockaddr_in *) &rt->rt_dst,
  175. (xflag & HOST_FLAG));
  176. if (isnet < 0) {
  177. bb_error_msg_and_die("resolving %s", target);
  178. }
  179. if (prefix) {
  180. /* do not destroy prefix for process args */
  181. *prefix = '/';
  182. }
  183. }
  184. if (xflag) { /* Reinit isnet if -net or -host was specified. */
  185. isnet = (xflag & NET_FLAG);
  186. }
  187. /* Fill in the other fields. */
  188. rt->rt_flags = ((isnet) ? RTF_UP : (RTF_UP | RTF_HOST));
  189. while (*args) {
  190. int k = kw_lookup(tbl_ipvx, &args);
  191. const char *args_m1 = args[-1];
  192. if (k & KW_IPVx_FLAG_ONLY) {
  193. rt->rt_flags |= flags_ipvx[k & 3];
  194. continue;
  195. }
  196. #if HAVE_NEW_ADDRT
  197. if (k == KW_IPVx_METRIC) {
  198. rt->rt_metric = xatoul(args_m1) + 1;
  199. continue;
  200. }
  201. #endif
  202. if (k == KW_IPVx_NETMASK) {
  203. struct sockaddr mask;
  204. if (mask_in_addr(*rt)) {
  205. bb_show_usage();
  206. }
  207. netmask = args_m1;
  208. isnet = INET_resolve(netmask, (struct sockaddr_in *) &mask, 0);
  209. if (isnet < 0) {
  210. bb_error_msg_and_die("resolving %s", netmask);
  211. }
  212. rt->rt_genmask = full_mask(mask);
  213. continue;
  214. }
  215. if (k == KW_IPVx_GATEWAY) {
  216. if (rt->rt_flags & RTF_GATEWAY) {
  217. bb_show_usage();
  218. }
  219. isnet = INET_resolve(args_m1,
  220. (struct sockaddr_in *) &rt->rt_gateway, 1);
  221. rt->rt_flags |= RTF_GATEWAY;
  222. if (isnet) {
  223. if (isnet < 0) {
  224. bb_error_msg_and_die("resolving %s", args_m1);
  225. }
  226. bb_error_msg_and_die("gateway %s is a NETWORK", args_m1);
  227. }
  228. continue;
  229. }
  230. if (k == KW_IPVx_MSS) { /* Check valid MSS bounds. */
  231. rt->rt_flags |= RTF_MSS;
  232. rt->rt_mss = xatoul_range(args_m1, 64, 32768);
  233. continue;
  234. }
  235. if (k == KW_IPVx_WINDOW) { /* Check valid window bounds. */
  236. rt->rt_flags |= RTF_WINDOW;
  237. rt->rt_window = xatoul_range(args_m1, 128, INT_MAX);
  238. continue;
  239. }
  240. #ifdef RTF_IRTT
  241. if (k == KW_IPVx_IRTT) {
  242. rt->rt_flags |= RTF_IRTT;
  243. rt->rt_irtt = xatoul(args_m1);
  244. rt->rt_irtt *= (bb_clk_tck() / 100); /* FIXME */
  245. #if 0 /* FIXME: do we need to check anything of this? */
  246. if (rt->rt_irtt < 1 || rt->rt_irtt > (120 * HZ)) {
  247. bb_error_msg_and_die("bad irtt");
  248. }
  249. #endif
  250. continue;
  251. }
  252. #endif
  253. /* Device is special in that it can be the last arg specified
  254. * and doesn't require the dev/device keyword in that case. */
  255. if (!rt->rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) {
  256. /* Don't use args_m1 here since args may have changed! */
  257. rt->rt_dev = args[-1];
  258. continue;
  259. }
  260. /* Nothing matched. */
  261. bb_show_usage();
  262. }
  263. #ifdef RTF_REJECT
  264. if ((rt->rt_flags & RTF_REJECT) && !rt->rt_dev) {
  265. rt->rt_dev = (char*)"lo";
  266. }
  267. #endif
  268. /* sanity checks.. */
  269. if (mask_in_addr(*rt)) {
  270. uint32_t mask = mask_in_addr(*rt);
  271. mask = ~ntohl(mask);
  272. if ((rt->rt_flags & RTF_HOST) && mask != 0xffffffff) {
  273. bb_error_msg_and_die("netmask %.8x and host route conflict",
  274. (unsigned int) mask);
  275. }
  276. if (mask & (mask + 1)) {
  277. bb_error_msg_and_die("bogus netmask %s", netmask);
  278. }
  279. mask = ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr;
  280. if (mask & ~(uint32_t)mask_in_addr(*rt)) {
  281. bb_simple_error_msg_and_die("netmask and route address conflict");
  282. }
  283. }
  284. /* Fill out netmask if still unset */
  285. if ((action == RTACTION_ADD) && (rt->rt_flags & RTF_HOST)) {
  286. mask_in_addr(*rt) = 0xffffffff;
  287. }
  288. /* Create a socket to the INET kernel. */
  289. skfd = xsocket(AF_INET, SOCK_DGRAM, 0);
  290. if (action == RTACTION_ADD)
  291. xioctl(skfd, SIOCADDRT, rt);
  292. else
  293. xioctl(skfd, SIOCDELRT, rt);
  294. if (ENABLE_FEATURE_CLEAN_UP) close(skfd);
  295. }
  296. #if ENABLE_FEATURE_IPV6
  297. static NOINLINE void INET6_setroute(int action, char **args)
  298. {
  299. struct sockaddr_in6 sa6;
  300. struct in6_rtmsg rt;
  301. int prefix_len, skfd;
  302. const char *devname;
  303. /* We know args isn't NULL from the check in route_main. */
  304. const char *target = *args++;
  305. if (strcmp(target, "default") == 0) {
  306. prefix_len = 0;
  307. memset(&sa6, 0, sizeof(sa6));
  308. } else {
  309. char *cp;
  310. cp = strchr(target, '/'); /* Yes... const to non is ok. */
  311. if (cp) {
  312. *cp = '\0';
  313. prefix_len = xatoul_range(cp + 1, 0, 128);
  314. } else {
  315. prefix_len = 128;
  316. }
  317. if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
  318. bb_error_msg_and_die("resolving %s", target);
  319. }
  320. }
  321. /* Clean out the RTREQ structure. */
  322. memset(&rt, 0, sizeof(rt));
  323. memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr, sizeof(struct in6_addr));
  324. /* Fill in the other fields. */
  325. rt.rtmsg_dst_len = prefix_len;
  326. rt.rtmsg_flags = ((prefix_len == 128) ? (RTF_UP|RTF_HOST) : RTF_UP);
  327. rt.rtmsg_metric = 1;
  328. devname = NULL;
  329. while (*args) {
  330. int k = kw_lookup(tbl_ipvx, &args);
  331. const char *args_m1 = args[-1];
  332. if ((k == KW_IPVx_MOD) || (k == KW_IPVx_DYN)) {
  333. rt.rtmsg_flags |= flags_ipvx[k & 3];
  334. continue;
  335. }
  336. if (k == KW_IPVx_METRIC) {
  337. rt.rtmsg_metric = xatoul(args_m1);
  338. continue;
  339. }
  340. if (k == KW_IPVx_GATEWAY) {
  341. if (rt.rtmsg_flags & RTF_GATEWAY) {
  342. bb_show_usage();
  343. }
  344. if (INET6_resolve(args_m1, (struct sockaddr_in6 *) &sa6) < 0) {
  345. bb_error_msg_and_die("resolving %s", args_m1);
  346. }
  347. memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr,
  348. sizeof(struct in6_addr));
  349. rt.rtmsg_flags |= RTF_GATEWAY;
  350. continue;
  351. }
  352. /* Device is special in that it can be the last arg specified
  353. * and doesn't require the dev/device keyword in that case. */
  354. if (!devname && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) {
  355. /* Don't use args_m1 here since args may have changed! */
  356. devname = args[-1];
  357. continue;
  358. }
  359. /* Nothing matched. */
  360. bb_show_usage();
  361. }
  362. /* Create a socket to the INET6 kernel. */
  363. skfd = xsocket(AF_INET6, SOCK_DGRAM, 0);
  364. rt.rtmsg_ifindex = 0;
  365. if (devname) {
  366. struct ifreq ifr;
  367. /*memset(&ifr, 0, sizeof(ifr)); - SIOCGIFINDEX does not need to clear all */
  368. strncpy_IFNAMSIZ(ifr.ifr_name, devname);
  369. xioctl(skfd, SIOCGIFINDEX, &ifr);
  370. rt.rtmsg_ifindex = ifr.ifr_ifindex;
  371. }
  372. /* Tell the kernel to accept this route. */
  373. if (action == RTACTION_ADD)
  374. xioctl(skfd, SIOCADDRT, &rt);
  375. else
  376. xioctl(skfd, SIOCDELRT, &rt);
  377. if (ENABLE_FEATURE_CLEAN_UP) close(skfd);
  378. }
  379. #endif
  380. static const
  381. IF_NOT_FEATURE_IPV6(uint16_t flagvals[] ALIGN2 = )
  382. IF_FEATURE_IPV6(uint32_t flagvals[] ALIGN4 = )
  383. { /* Must agree with flagchars[]. */
  384. RTF_UP,
  385. RTF_GATEWAY,
  386. RTF_HOST,
  387. RTF_REINSTATE,
  388. RTF_DYNAMIC,
  389. RTF_MODIFIED,
  390. #if ENABLE_FEATURE_IPV6
  391. RTF_DEFAULT,
  392. RTF_ADDRCONF,
  393. RTF_CACHE,
  394. RTF_REJECT,
  395. RTF_NONEXTHOP, /* this one doesn't fit into 16 bits */
  396. #endif
  397. };
  398. /* Must agree with flagvals[]. */
  399. static const char flagchars[] ALIGN1 =
  400. "UGHRDM"
  401. #if ENABLE_FEATURE_IPV6
  402. "DAC!n"
  403. #endif
  404. ;
  405. #define IPV4_MASK (RTF_UP|RTF_GATEWAY|RTF_HOST|RTF_REINSTATE|RTF_DYNAMIC|RTF_MODIFIED)
  406. #define IPV6_MASK (RTF_UP|RTF_GATEWAY|RTF_HOST|RTF_DEFAULT|RTF_ADDRCONF|RTF_CACHE|RTF_REJECT|RTF_NONEXTHOP)
  407. static void set_flags(char *flagstr, int flags)
  408. {
  409. int i;
  410. for (i = 0; (*flagstr = flagchars[i]) != 0; i++) {
  411. if (flags & flagvals[i]) {
  412. ++flagstr;
  413. }
  414. }
  415. }
  416. /* also used in netstat */
  417. void FAST_FUNC bb_displayroutes(int noresolve, int netstatfmt)
  418. {
  419. char devname[64], flags[16], *sdest, *sgw;
  420. unsigned long d, g, m;
  421. int r;
  422. int flgs, ref, use, metric, mtu, win, ir;
  423. struct sockaddr_in s_addr;
  424. struct in_addr mask;
  425. FILE *fp = xfopen_for_read("/proc/net/route");
  426. printf("Kernel IP routing table\n"
  427. "Destination Gateway Genmask Flags %s Iface\n",
  428. netstatfmt ? " MSS Window irtt" : "Metric Ref Use");
  429. /* Skip the first line. */
  430. r = fscanf(fp, "%*[^\n]\n");
  431. if (r < 0) {
  432. /* Empty line, read error, or EOF. Yes, if routing table
  433. * is completely empty, /proc/net/route has no header.
  434. */
  435. goto ERROR;
  436. }
  437. while (1) {
  438. r = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n",
  439. devname, &d, &g, &flgs, &ref, &use, &metric, &m,
  440. &mtu, &win, &ir);
  441. if (r != 11) {
  442. ERROR:
  443. if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
  444. break;
  445. }
  446. bb_simple_perror_msg_and_die(bb_msg_read_error);
  447. }
  448. if (!(flgs & RTF_UP)) { /* Skip interfaces that are down. */
  449. continue;
  450. }
  451. set_flags(flags, (flgs & IPV4_MASK));
  452. #ifdef RTF_REJECT
  453. if (flgs & RTF_REJECT) {
  454. flags[0] = '!';
  455. }
  456. #endif
  457. memset(&s_addr, 0, sizeof(struct sockaddr_in));
  458. s_addr.sin_family = AF_INET;
  459. s_addr.sin_addr.s_addr = d;
  460. sdest = INET_rresolve(&s_addr, (noresolve | 0x8000), m); /* 'default' instead of '*' */
  461. s_addr.sin_addr.s_addr = g;
  462. sgw = INET_rresolve(&s_addr, (noresolve | 0x4000), m); /* Host instead of net */
  463. mask.s_addr = m;
  464. /* "%15.15s" truncates hostnames, do we really want that? */
  465. printf("%-15.15s %-15.15s %-16s%-6s", sdest, sgw, inet_ntoa(mask), flags);
  466. free(sdest);
  467. free(sgw);
  468. if (netstatfmt) {
  469. printf("%5d %-5d %6d %s\n", mtu, win, ir, devname);
  470. } else {
  471. printf("%-6d %-2d %7d %s\n", metric, ref, use, devname);
  472. }
  473. }
  474. fclose(fp);
  475. }
  476. #if ENABLE_FEATURE_IPV6
  477. static void INET6_displayroutes(void)
  478. {
  479. char addr6[128], *naddr6;
  480. /* In addr6x, we store both 40-byte ':'-delimited ipv6 addresses.
  481. * We read the non-delimited strings into the tail of the buffer
  482. * using fscanf and then modify the buffer by shifting forward
  483. * while inserting ':'s and the nul terminator for the first string.
  484. * Hence the strings are at addr6x and addr6x+40. This generates
  485. * _much_ less code than the previous (upstream) approach. */
  486. char addr6x[80];
  487. char iface[16], flags[16];
  488. int iflags, metric, refcnt, use, prefix_len, slen;
  489. struct sockaddr_in6 snaddr6;
  490. FILE *fp = xfopen_for_read("/proc/net/ipv6_route");
  491. printf("Kernel IPv6 routing table\n%-44s%-40s"
  492. "Flags Metric Ref Use Iface\n",
  493. "Destination", "Next Hop");
  494. while (1) {
  495. int r;
  496. r = fscanf(fp, "%32s%x%*s%x%32s%x%x%x%x%s\n",
  497. addr6x+14, &prefix_len, &slen, addr6x+40+7,
  498. &metric, &refcnt, &use, &iflags, iface);
  499. if (r != 9) {
  500. if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */
  501. break;
  502. }
  503. ERROR:
  504. bb_simple_perror_msg_and_die(bb_msg_read_error);
  505. }
  506. /* Do the addr6x shift-and-insert changes to ':'-delimit addresses.
  507. * For now, always do this to validate the proc route format, even
  508. * if the interface is down. */
  509. {
  510. int i = 0;
  511. char *p = addr6x+14;
  512. do {
  513. if (!*p) {
  514. if (i == 40) { /* nul terminator for 1st address? */
  515. addr6x[39] = 0; /* Fixup... need 0 instead of ':'. */
  516. ++p; /* Skip and continue. */
  517. continue;
  518. }
  519. goto ERROR;
  520. }
  521. addr6x[i++] = *p++;
  522. if (!((i+1) % 5)) {
  523. addr6x[i++] = ':';
  524. }
  525. } while (i < 40+28+7);
  526. }
  527. set_flags(flags, (iflags & IPV6_MASK));
  528. r = 0;
  529. while (1) {
  530. memset(&snaddr6, 0, sizeof(snaddr6));
  531. inet_pton(AF_INET6, addr6x + r,
  532. (struct sockaddr *) &snaddr6.sin6_addr);
  533. snaddr6.sin6_family = AF_INET6;
  534. naddr6 = INET6_rresolve((struct sockaddr_in6 *) &snaddr6,
  535. 0x0fff /* Apparently, upstream never resolves. */
  536. );
  537. if (!r) { /* 1st pass */
  538. snprintf(addr6, sizeof(addr6), "%s/%d", naddr6, prefix_len);
  539. r += 40;
  540. free(naddr6);
  541. } else { /* 2nd pass */
  542. /* Print the info. */
  543. printf("%-43s %-39s %-5s %-6d %-2d %7d %-8s\n",
  544. addr6, naddr6, flags, metric, refcnt, use, iface);
  545. free(naddr6);
  546. break;
  547. }
  548. }
  549. }
  550. fclose(fp);
  551. }
  552. #endif
  553. //usage:#define route_trivial_usage
  554. ///////: "[-ne]"IF_FEATURE_IPV6(" [-A inet[6]]")" [{add|del|delete} [-net|-host] TARGET [netmask MASK] [gw GATEWAY] [metric N] [mss BYTES] [window BYTES] [irtt MSEC] [reject] [mod] [dyn] [reinstate] [[dev] IFACE]]"
  555. ///////too wordy
  556. //usage: "[-ne]"IF_FEATURE_IPV6(" [-A inet[6]]")" [{add|del} [-net|-host] TARGET [netmask MASK]\n"
  557. //usage: " [gw GATEWAY] [metric N] [mss BYTES] [window BYTES] [reject] [IFACE]]"
  558. //usage:#define route_full_usage "\n\n"
  559. //usage: "Show or edit kernel routing tables\n"
  560. //usage: "\n -n Don't resolve names"
  561. //usage: "\n -e Display other/more information"
  562. //usage: "\n -A inet" IF_FEATURE_IPV6("[6]") " Select address family"
  563. #define ROUTE_OPT_A 0x01
  564. #define ROUTE_OPT_n 0x02
  565. #define ROUTE_OPT_e 0x04
  566. #define ROUTE_OPT_INET6 0x08 /* Not an actual option. See below. */
  567. /* 1st byte is return value, matches RTACTION_* code */
  568. static const char tbl_verb[] ALIGN1 =
  569. "\001add\0"
  570. "\002del\0"
  571. "\002delete\0"
  572. ;
  573. int route_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
  574. int route_main(int argc UNUSED_PARAM, char **argv)
  575. {
  576. unsigned opt;
  577. int what;
  578. char *family;
  579. char **p;
  580. /* First, remap '-net' and '-host' to avoid getopt problems. */
  581. p = argv;
  582. while (*++p) {
  583. if (strcmp(*p, "-net") == 0 || strcmp(*p, "-host") == 0) {
  584. p[0][0] = '#';
  585. }
  586. }
  587. opt = getopt32(argv, "A:ne", &family);
  588. if ((opt & ROUTE_OPT_A) && strcmp(family, "inet") != 0) {
  589. #if ENABLE_FEATURE_IPV6
  590. if (strcmp(family, "inet6") == 0) {
  591. opt |= ROUTE_OPT_INET6; /* Set flag for ipv6. */
  592. } else
  593. #endif
  594. bb_show_usage();
  595. }
  596. argv += optind;
  597. /* No more args means display the routing table. */
  598. if (!*argv) {
  599. int noresolve = (opt & ROUTE_OPT_n) ? 0x0fff : 0;
  600. #if ENABLE_FEATURE_IPV6
  601. if (opt & ROUTE_OPT_INET6)
  602. INET6_displayroutes();
  603. else
  604. #endif
  605. bb_displayroutes(noresolve, opt & ROUTE_OPT_e);
  606. fflush_stdout_and_exit_SUCCESS();
  607. }
  608. /* Check verb. At the moment, must be add, del, or delete. */
  609. what = kw_lookup(tbl_verb, &argv);
  610. if (!what || !*argv) { /* Unknown verb or no more args. */
  611. bb_show_usage();
  612. }
  613. #if ENABLE_FEATURE_IPV6
  614. if (opt & ROUTE_OPT_INET6)
  615. INET6_setroute(what, argv);
  616. else
  617. #endif
  618. INET_setroute(what, argv);
  619. return EXIT_SUCCESS;
  620. }