iproute.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907
  1. /* vi: set sw=4 ts=4: */
  2. /*
  3. * iproute.c "ip route".
  4. *
  5. * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
  6. *
  7. * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
  8. *
  9. *
  10. * Changes:
  11. *
  12. * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses
  13. * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized
  14. */
  15. #include "ip_common.h" /* #include "libbb.h" is inside */
  16. #include "rt_names.h"
  17. #include "utils.h"
  18. #ifndef RTAX_RTTVAR
  19. #define RTAX_RTTVAR RTAX_HOPS
  20. #endif
  21. typedef struct filter_t {
  22. int tb;
  23. smallint flushed;
  24. char *flushb;
  25. int flushp;
  26. int flushe;
  27. struct rtnl_handle *rth;
  28. int protocol, protocolmask;
  29. int scope, scopemask;
  30. int type, typemask;
  31. int tos, tosmask;
  32. int iif, iifmask;
  33. int oif, oifmask;
  34. int realm, realmmask;
  35. inet_prefix rprefsrc;
  36. inet_prefix rvia;
  37. inet_prefix rdst;
  38. inet_prefix mdst;
  39. inet_prefix rsrc;
  40. inet_prefix msrc;
  41. } filter_t;
  42. #define filter (*(filter_t*)&bb_common_bufsiz1)
  43. static int flush_update(void)
  44. {
  45. if (rtnl_send(filter.rth, filter.flushb, filter.flushp) < 0) {
  46. bb_perror_msg("failed to send flush request");
  47. return -1;
  48. }
  49. filter.flushp = 0;
  50. return 0;
  51. }
  52. static unsigned get_hz(void)
  53. {
  54. static unsigned hz_internal;
  55. FILE *fp;
  56. if (hz_internal)
  57. return hz_internal;
  58. fp = fopen_for_read("/proc/net/psched");
  59. if (fp) {
  60. unsigned nom, denom;
  61. if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2)
  62. if (nom == 1000000)
  63. hz_internal = denom;
  64. fclose(fp);
  65. }
  66. if (!hz_internal)
  67. hz_internal = sysconf(_SC_CLK_TCK);
  68. return hz_internal;
  69. }
  70. static int print_route(const struct sockaddr_nl *who UNUSED_PARAM,
  71. struct nlmsghdr *n, void *arg UNUSED_PARAM)
  72. {
  73. struct rtmsg *r = NLMSG_DATA(n);
  74. int len = n->nlmsg_len;
  75. struct rtattr * tb[RTA_MAX+1];
  76. char abuf[256];
  77. inet_prefix dst;
  78. inet_prefix src;
  79. int host_len = -1;
  80. SPRINT_BUF(b1);
  81. if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) {
  82. fprintf(stderr, "Not a route: %08x %08x %08x\n",
  83. n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags);
  84. return 0;
  85. }
  86. if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE)
  87. return 0;
  88. len -= NLMSG_LENGTH(sizeof(*r));
  89. if (len < 0)
  90. bb_error_msg_and_die("wrong nlmsg len %d", len);
  91. if (r->rtm_family == AF_INET6)
  92. host_len = 128;
  93. else if (r->rtm_family == AF_INET)
  94. host_len = 32;
  95. if (r->rtm_family == AF_INET6) {
  96. if (filter.tb) {
  97. if (filter.tb < 0) {
  98. if (!(r->rtm_flags & RTM_F_CLONED)) {
  99. return 0;
  100. }
  101. } else {
  102. if (r->rtm_flags & RTM_F_CLONED) {
  103. return 0;
  104. }
  105. if (filter.tb == RT_TABLE_LOCAL) {
  106. if (r->rtm_type != RTN_LOCAL) {
  107. return 0;
  108. }
  109. } else if (filter.tb == RT_TABLE_MAIN) {
  110. if (r->rtm_type == RTN_LOCAL) {
  111. return 0;
  112. }
  113. } else {
  114. return 0;
  115. }
  116. }
  117. }
  118. } else {
  119. if (filter.tb > 0 && filter.tb != r->rtm_table) {
  120. return 0;
  121. }
  122. }
  123. if (filter.rdst.family &&
  124. (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) {
  125. return 0;
  126. }
  127. if (filter.mdst.family &&
  128. (r->rtm_family != filter.mdst.family ||
  129. (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) {
  130. return 0;
  131. }
  132. if (filter.rsrc.family &&
  133. (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) {
  134. return 0;
  135. }
  136. if (filter.msrc.family &&
  137. (r->rtm_family != filter.msrc.family ||
  138. (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) {
  139. return 0;
  140. }
  141. memset(tb, 0, sizeof(tb));
  142. parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
  143. if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen))
  144. return 0;
  145. if (filter.mdst.family && filter.mdst.bitlen >= 0 &&
  146. inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len))
  147. return 0;
  148. if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen))
  149. return 0;
  150. if (filter.msrc.family && filter.msrc.bitlen >= 0 &&
  151. inet_addr_match(&src, &filter.msrc, r->rtm_src_len))
  152. return 0;
  153. if (filter.flushb &&
  154. r->rtm_family == AF_INET6 &&
  155. r->rtm_dst_len == 0 &&
  156. r->rtm_type == RTN_UNREACHABLE &&
  157. tb[RTA_PRIORITY] &&
  158. *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1)
  159. return 0;
  160. if (filter.flushb) {
  161. struct nlmsghdr *fn;
  162. if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) {
  163. if (flush_update())
  164. bb_error_msg_and_die("flush");
  165. }
  166. fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp));
  167. memcpy(fn, n, n->nlmsg_len);
  168. fn->nlmsg_type = RTM_DELROUTE;
  169. fn->nlmsg_flags = NLM_F_REQUEST;
  170. fn->nlmsg_seq = ++filter.rth->seq;
  171. filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb;
  172. filter.flushed = 1;
  173. return 0;
  174. }
  175. if (n->nlmsg_type == RTM_DELROUTE) {
  176. printf("Deleted ");
  177. }
  178. if (r->rtm_type != RTN_UNICAST && !filter.type) {
  179. printf("%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1)));
  180. }
  181. if (tb[RTA_DST]) {
  182. if (r->rtm_dst_len != host_len) {
  183. printf("%s/%u ", rt_addr_n2a(r->rtm_family,
  184. RTA_PAYLOAD(tb[RTA_DST]),
  185. RTA_DATA(tb[RTA_DST]),
  186. abuf, sizeof(abuf)),
  187. r->rtm_dst_len
  188. );
  189. } else {
  190. printf("%s ", format_host(r->rtm_family,
  191. RTA_PAYLOAD(tb[RTA_DST]),
  192. RTA_DATA(tb[RTA_DST]),
  193. abuf, sizeof(abuf))
  194. );
  195. }
  196. } else if (r->rtm_dst_len) {
  197. printf("0/%d ", r->rtm_dst_len);
  198. } else {
  199. printf("default ");
  200. }
  201. if (tb[RTA_SRC]) {
  202. if (r->rtm_src_len != host_len) {
  203. printf("from %s/%u ", rt_addr_n2a(r->rtm_family,
  204. RTA_PAYLOAD(tb[RTA_SRC]),
  205. RTA_DATA(tb[RTA_SRC]),
  206. abuf, sizeof(abuf)),
  207. r->rtm_src_len
  208. );
  209. } else {
  210. printf("from %s ", format_host(r->rtm_family,
  211. RTA_PAYLOAD(tb[RTA_SRC]),
  212. RTA_DATA(tb[RTA_SRC]),
  213. abuf, sizeof(abuf))
  214. );
  215. }
  216. } else if (r->rtm_src_len) {
  217. printf("from 0/%u ", r->rtm_src_len);
  218. }
  219. if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) {
  220. printf("via %s ", format_host(r->rtm_family,
  221. RTA_PAYLOAD(tb[RTA_GATEWAY]),
  222. RTA_DATA(tb[RTA_GATEWAY]),
  223. abuf, sizeof(abuf)));
  224. }
  225. if (tb[RTA_OIF] && filter.oifmask != -1) {
  226. printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF])));
  227. }
  228. if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) {
  229. /* Do not use format_host(). It is our local addr
  230. and symbolic name will not be useful.
  231. */
  232. printf(" src %s ", rt_addr_n2a(r->rtm_family,
  233. RTA_PAYLOAD(tb[RTA_PREFSRC]),
  234. RTA_DATA(tb[RTA_PREFSRC]),
  235. abuf, sizeof(abuf)));
  236. }
  237. if (tb[RTA_PRIORITY]) {
  238. printf(" metric %d ", *(uint32_t*)RTA_DATA(tb[RTA_PRIORITY]));
  239. }
  240. if (r->rtm_family == AF_INET6) {
  241. struct rta_cacheinfo *ci = NULL;
  242. if (tb[RTA_CACHEINFO]) {
  243. ci = RTA_DATA(tb[RTA_CACHEINFO]);
  244. }
  245. if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) {
  246. if (r->rtm_flags & RTM_F_CLONED) {
  247. printf("%c cache ", _SL_);
  248. }
  249. if (ci->rta_expires) {
  250. printf(" expires %dsec", ci->rta_expires / get_hz());
  251. }
  252. if (ci->rta_error != 0) {
  253. printf(" error %d", ci->rta_error);
  254. }
  255. } else if (ci) {
  256. if (ci->rta_error != 0)
  257. printf(" error %d", ci->rta_error);
  258. }
  259. }
  260. if (tb[RTA_IIF] && filter.iifmask != -1) {
  261. printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF])));
  262. }
  263. bb_putchar('\n');
  264. return 0;
  265. }
  266. /* Return value becomes exitcode. It's okay to not return at all */
  267. static int iproute_modify(int cmd, unsigned flags, char **argv)
  268. {
  269. static const char keywords[] ALIGN1 =
  270. "src\0""via\0""mtu\0""lock\0""protocol\0"USE_FEATURE_IP_RULE("table\0")
  271. "dev\0""oif\0""to\0""metric\0";
  272. enum {
  273. ARG_src,
  274. ARG_via,
  275. ARG_mtu, PARM_lock,
  276. ARG_protocol,
  277. USE_FEATURE_IP_RULE(ARG_table,)
  278. ARG_dev,
  279. ARG_oif,
  280. ARG_to,
  281. ARG_metric,
  282. };
  283. enum {
  284. gw_ok = 1 << 0,
  285. dst_ok = 1 << 1,
  286. proto_ok = 1 << 2,
  287. type_ok = 1 << 3
  288. };
  289. struct rtnl_handle rth;
  290. struct {
  291. struct nlmsghdr n;
  292. struct rtmsg r;
  293. char buf[1024];
  294. } req;
  295. char mxbuf[256];
  296. struct rtattr * mxrta = (void*)mxbuf;
  297. unsigned mxlock = 0;
  298. char *d = NULL;
  299. smalluint ok = 0;
  300. int arg;
  301. memset(&req, 0, sizeof(req));
  302. req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  303. req.n.nlmsg_flags = NLM_F_REQUEST | flags;
  304. req.n.nlmsg_type = cmd;
  305. req.r.rtm_family = preferred_family;
  306. if (RT_TABLE_MAIN) /* if it is zero, memset already did it */
  307. req.r.rtm_table = RT_TABLE_MAIN;
  308. if (RT_SCOPE_NOWHERE)
  309. req.r.rtm_scope = RT_SCOPE_NOWHERE;
  310. if (cmd != RTM_DELROUTE) {
  311. req.r.rtm_protocol = RTPROT_BOOT;
  312. req.r.rtm_scope = RT_SCOPE_UNIVERSE;
  313. req.r.rtm_type = RTN_UNICAST;
  314. }
  315. mxrta->rta_type = RTA_METRICS;
  316. mxrta->rta_len = RTA_LENGTH(0);
  317. while (*argv) {
  318. arg = index_in_substrings(keywords, *argv);
  319. if (arg == ARG_src) {
  320. inet_prefix addr;
  321. NEXT_ARG();
  322. get_addr(&addr, *argv, req.r.rtm_family);
  323. if (req.r.rtm_family == AF_UNSPEC)
  324. req.r.rtm_family = addr.family;
  325. addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen);
  326. } else if (arg == ARG_via) {
  327. inet_prefix addr;
  328. ok |= gw_ok;
  329. NEXT_ARG();
  330. get_addr(&addr, *argv, req.r.rtm_family);
  331. if (req.r.rtm_family == AF_UNSPEC) {
  332. req.r.rtm_family = addr.family;
  333. }
  334. addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen);
  335. } else if (arg == ARG_mtu) {
  336. unsigned mtu;
  337. NEXT_ARG();
  338. if (index_in_strings(keywords, *argv) == PARM_lock) {
  339. mxlock |= (1 << RTAX_MTU);
  340. NEXT_ARG();
  341. }
  342. if (get_unsigned(&mtu, *argv, 0))
  343. invarg(*argv, "mtu");
  344. rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu);
  345. } else if (arg == ARG_protocol) {
  346. uint32_t prot;
  347. NEXT_ARG();
  348. if (rtnl_rtprot_a2n(&prot, *argv))
  349. invarg(*argv, "protocol");
  350. req.r.rtm_protocol = prot;
  351. ok |= proto_ok;
  352. #if ENABLE_FEATURE_IP_RULE
  353. } else if (arg == ARG_table) {
  354. uint32_t tid;
  355. NEXT_ARG();
  356. if (rtnl_rttable_a2n(&tid, *argv))
  357. invarg(*argv, "table");
  358. req.r.rtm_table = tid;
  359. #endif
  360. } else if (arg == ARG_dev || arg == ARG_oif) {
  361. NEXT_ARG();
  362. d = *argv;
  363. } else if (arg == ARG_metric) {
  364. uint32_t metric;
  365. NEXT_ARG();
  366. if (get_u32(&metric, *argv, 0))
  367. invarg(*argv, "metric");
  368. addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric);
  369. } else {
  370. int type;
  371. inet_prefix dst;
  372. if (arg == ARG_to) {
  373. NEXT_ARG();
  374. }
  375. if ((**argv < '0' || **argv > '9')
  376. && rtnl_rtntype_a2n(&type, *argv) == 0) {
  377. NEXT_ARG();
  378. req.r.rtm_type = type;
  379. ok |= type_ok;
  380. }
  381. if (ok & dst_ok) {
  382. duparg2("to", *argv);
  383. }
  384. get_prefix(&dst, *argv, req.r.rtm_family);
  385. if (req.r.rtm_family == AF_UNSPEC) {
  386. req.r.rtm_family = dst.family;
  387. }
  388. req.r.rtm_dst_len = dst.bitlen;
  389. ok |= dst_ok;
  390. if (dst.bytelen) {
  391. addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen);
  392. }
  393. }
  394. argv++;
  395. }
  396. xrtnl_open(&rth);
  397. if (d) {
  398. int idx;
  399. ll_init_map(&rth);
  400. if (d) {
  401. idx = xll_name_to_index(d);
  402. addattr32(&req.n, sizeof(req), RTA_OIF, idx);
  403. }
  404. }
  405. if (mxrta->rta_len > RTA_LENGTH(0)) {
  406. if (mxlock) {
  407. rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock);
  408. }
  409. addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
  410. }
  411. if (req.r.rtm_type == RTN_LOCAL || req.r.rtm_type == RTN_NAT)
  412. req.r.rtm_scope = RT_SCOPE_HOST;
  413. else if (req.r.rtm_type == RTN_BROADCAST ||
  414. req.r.rtm_type == RTN_MULTICAST ||
  415. req.r.rtm_type == RTN_ANYCAST)
  416. req.r.rtm_scope = RT_SCOPE_LINK;
  417. else if (req.r.rtm_type == RTN_UNICAST || req.r.rtm_type == RTN_UNSPEC) {
  418. if (cmd == RTM_DELROUTE)
  419. req.r.rtm_scope = RT_SCOPE_NOWHERE;
  420. else if (!(ok & gw_ok))
  421. req.r.rtm_scope = RT_SCOPE_LINK;
  422. }
  423. if (req.r.rtm_family == AF_UNSPEC) {
  424. req.r.rtm_family = AF_INET;
  425. }
  426. if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) {
  427. return 2;
  428. }
  429. return 0;
  430. }
  431. static int rtnl_rtcache_request(struct rtnl_handle *rth, int family)
  432. {
  433. struct {
  434. struct nlmsghdr nlh;
  435. struct rtmsg rtm;
  436. } req;
  437. struct sockaddr_nl nladdr;
  438. memset(&nladdr, 0, sizeof(nladdr));
  439. memset(&req, 0, sizeof(req));
  440. nladdr.nl_family = AF_NETLINK;
  441. req.nlh.nlmsg_len = sizeof(req);
  442. if (RTM_GETROUTE)
  443. req.nlh.nlmsg_type = RTM_GETROUTE;
  444. if (NLM_F_ROOT | NLM_F_REQUEST)
  445. req.nlh.nlmsg_flags = NLM_F_ROOT | NLM_F_REQUEST;
  446. /*req.nlh.nlmsg_pid = 0; - memset did it already */
  447. req.nlh.nlmsg_seq = rth->dump = ++rth->seq;
  448. req.rtm.rtm_family = family;
  449. if (RTM_F_CLONED)
  450. req.rtm.rtm_flags = RTM_F_CLONED;
  451. return xsendto(rth->fd, (void*)&req, sizeof(req), (struct sockaddr*)&nladdr, sizeof(nladdr));
  452. }
  453. static void iproute_flush_cache(void)
  454. {
  455. static const char fn[] ALIGN1 = "/proc/sys/net/ipv4/route/flush";
  456. int flush_fd = open_or_warn(fn, O_WRONLY);
  457. if (flush_fd < 0) {
  458. return;
  459. }
  460. if (write(flush_fd, "-1", 2) < 2) {
  461. bb_perror_msg("cannot flush routing cache");
  462. return;
  463. }
  464. close(flush_fd);
  465. }
  466. static void iproute_reset_filter(void)
  467. {
  468. memset(&filter, 0, sizeof(filter));
  469. filter.mdst.bitlen = -1;
  470. filter.msrc.bitlen = -1;
  471. }
  472. /* Return value becomes exitcode. It's okay to not return at all */
  473. static int iproute_list_or_flush(char **argv, int flush)
  474. {
  475. int do_ipv6 = preferred_family;
  476. struct rtnl_handle rth;
  477. char *id = NULL;
  478. char *od = NULL;
  479. static const char keywords[] ALIGN1 =
  480. /* "ip route list/flush" parameters: */
  481. "protocol\0" "dev\0" "oif\0" "iif\0"
  482. "via\0" "table\0" "cache\0"
  483. "from\0" "to\0"
  484. /* and possible further keywords */
  485. "all\0"
  486. "root\0"
  487. "match\0"
  488. "exact\0"
  489. "main\0"
  490. ;
  491. enum {
  492. KW_proto, KW_dev, KW_oif, KW_iif,
  493. KW_via, KW_table, KW_cache,
  494. KW_from, KW_to,
  495. /* */
  496. KW_all,
  497. KW_root,
  498. KW_match,
  499. KW_exact,
  500. KW_main,
  501. };
  502. int arg, parm;
  503. iproute_reset_filter();
  504. filter.tb = RT_TABLE_MAIN;
  505. if (flush && !*argv)
  506. bb_error_msg_and_die(bb_msg_requires_arg, "\"ip route flush\"");
  507. while (*argv) {
  508. arg = index_in_substrings(keywords, *argv);
  509. if (arg == KW_proto) {
  510. uint32_t prot = 0;
  511. NEXT_ARG();
  512. filter.protocolmask = -1;
  513. if (rtnl_rtprot_a2n(&prot, *argv)) {
  514. if (index_in_strings(keywords, *argv) != KW_all)
  515. invarg(*argv, "protocol");
  516. prot = 0;
  517. filter.protocolmask = 0;
  518. }
  519. filter.protocol = prot;
  520. } else if (arg == KW_dev || arg == KW_oif) {
  521. NEXT_ARG();
  522. od = *argv;
  523. } else if (arg == KW_iif) {
  524. NEXT_ARG();
  525. id = *argv;
  526. } else if (arg == KW_via) {
  527. NEXT_ARG();
  528. get_prefix(&filter.rvia, *argv, do_ipv6);
  529. } else if (arg == KW_table) { /* table all/cache/main */
  530. NEXT_ARG();
  531. parm = index_in_substrings(keywords, *argv);
  532. if (parm == KW_cache)
  533. filter.tb = -1;
  534. else if (parm == KW_all)
  535. filter.tb = 0;
  536. else if (parm != KW_main) {
  537. #if ENABLE_FEATURE_IP_RULE
  538. uint32_t tid;
  539. if (rtnl_rttable_a2n(&tid, *argv))
  540. invarg(*argv, "table");
  541. filter.tb = tid;
  542. #else
  543. invarg(*argv, "table");
  544. #endif
  545. }
  546. } else if (arg == KW_cache) {
  547. /* The command 'ip route flush cache' is used by OpenSWAN.
  548. * Assuming it's a synonym for 'ip route flush table cache' */
  549. filter.tb = -1;
  550. } else if (arg == KW_from) {
  551. NEXT_ARG();
  552. parm = index_in_substrings(keywords, *argv);
  553. if (parm == KW_root) {
  554. NEXT_ARG();
  555. get_prefix(&filter.rsrc, *argv, do_ipv6);
  556. } else if (parm == KW_match) {
  557. NEXT_ARG();
  558. get_prefix(&filter.msrc, *argv, do_ipv6);
  559. } else {
  560. if (parm == KW_exact)
  561. NEXT_ARG();
  562. get_prefix(&filter.msrc, *argv, do_ipv6);
  563. filter.rsrc = filter.msrc;
  564. }
  565. } else { /* "to" is the default parameter */
  566. if (arg == KW_to) {
  567. NEXT_ARG();
  568. arg = index_in_substrings(keywords, *argv);
  569. }
  570. /* parm = arg; - would be more plausible, but we reuse 'arg' here */
  571. if (arg == KW_root) {
  572. NEXT_ARG();
  573. get_prefix(&filter.rdst, *argv, do_ipv6);
  574. } else if (arg == KW_match) {
  575. NEXT_ARG();
  576. get_prefix(&filter.mdst, *argv, do_ipv6);
  577. } else { /* "to exact" is the default */
  578. if (arg == KW_exact)
  579. NEXT_ARG();
  580. get_prefix(&filter.mdst, *argv, do_ipv6);
  581. filter.rdst = filter.mdst;
  582. }
  583. }
  584. argv++;
  585. }
  586. if (do_ipv6 == AF_UNSPEC && filter.tb) {
  587. do_ipv6 = AF_INET;
  588. }
  589. xrtnl_open(&rth);
  590. ll_init_map(&rth);
  591. if (id || od) {
  592. int idx;
  593. if (id) {
  594. idx = xll_name_to_index(id);
  595. filter.iif = idx;
  596. filter.iifmask = -1;
  597. }
  598. if (od) {
  599. idx = xll_name_to_index(od);
  600. filter.oif = idx;
  601. filter.oifmask = -1;
  602. }
  603. }
  604. if (flush) {
  605. char flushb[4096-512];
  606. if (filter.tb == -1) { /* "flush table cache" */
  607. if (do_ipv6 != AF_INET6)
  608. iproute_flush_cache();
  609. if (do_ipv6 == AF_INET)
  610. return 0;
  611. }
  612. filter.flushb = flushb;
  613. filter.flushp = 0;
  614. filter.flushe = sizeof(flushb);
  615. filter.rth = &rth;
  616. for (;;) {
  617. xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
  618. filter.flushed = 0;
  619. xrtnl_dump_filter(&rth, print_route, NULL);
  620. if (filter.flushed == 0)
  621. return 0;
  622. if (flush_update())
  623. return 1;
  624. }
  625. }
  626. if (filter.tb != -1) {
  627. xrtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE);
  628. } else if (rtnl_rtcache_request(&rth, do_ipv6) < 0) {
  629. bb_perror_msg_and_die("cannot send dump request");
  630. }
  631. xrtnl_dump_filter(&rth, print_route, NULL);
  632. return 0;
  633. }
  634. /* Return value becomes exitcode. It's okay to not return at all */
  635. static int iproute_get(char **argv)
  636. {
  637. struct rtnl_handle rth;
  638. struct {
  639. struct nlmsghdr n;
  640. struct rtmsg r;
  641. char buf[1024];
  642. } req;
  643. char *idev = NULL;
  644. char *odev = NULL;
  645. bool connected = 0;
  646. bool from_ok = 0;
  647. static const char options[] ALIGN1 =
  648. "from\0""iif\0""oif\0""dev\0""notify\0""connected\0""to\0";
  649. memset(&req, 0, sizeof(req));
  650. iproute_reset_filter();
  651. req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg));
  652. if (NLM_F_REQUEST)
  653. req.n.nlmsg_flags = NLM_F_REQUEST;
  654. if (RTM_GETROUTE)
  655. req.n.nlmsg_type = RTM_GETROUTE;
  656. req.r.rtm_family = preferred_family;
  657. /*req.r.rtm_table = 0; - memset did this already */
  658. /*req.r.rtm_protocol = 0;*/
  659. /*req.r.rtm_scope = 0;*/
  660. /*req.r.rtm_type = 0;*/
  661. /*req.r.rtm_src_len = 0;*/
  662. /*req.r.rtm_dst_len = 0;*/
  663. /*req.r.rtm_tos = 0;*/
  664. while (*argv) {
  665. switch (index_in_strings(options, *argv)) {
  666. case 0: /* from */
  667. {
  668. inet_prefix addr;
  669. NEXT_ARG();
  670. from_ok = 1;
  671. get_prefix(&addr, *argv, req.r.rtm_family);
  672. if (req.r.rtm_family == AF_UNSPEC) {
  673. req.r.rtm_family = addr.family;
  674. }
  675. if (addr.bytelen) {
  676. addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen);
  677. }
  678. req.r.rtm_src_len = addr.bitlen;
  679. break;
  680. }
  681. case 1: /* iif */
  682. NEXT_ARG();
  683. idev = *argv;
  684. break;
  685. case 2: /* oif */
  686. case 3: /* dev */
  687. NEXT_ARG();
  688. odev = *argv;
  689. break;
  690. case 4: /* notify */
  691. req.r.rtm_flags |= RTM_F_NOTIFY;
  692. break;
  693. case 5: /* connected */
  694. connected = 1;
  695. break;
  696. case 6: /* to */
  697. NEXT_ARG();
  698. default:
  699. {
  700. inet_prefix addr;
  701. get_prefix(&addr, *argv, req.r.rtm_family);
  702. if (req.r.rtm_family == AF_UNSPEC) {
  703. req.r.rtm_family = addr.family;
  704. }
  705. if (addr.bytelen) {
  706. addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen);
  707. }
  708. req.r.rtm_dst_len = addr.bitlen;
  709. }
  710. argv++;
  711. }
  712. }
  713. if (req.r.rtm_dst_len == 0) {
  714. bb_error_msg_and_die("need at least destination address");
  715. }
  716. xrtnl_open(&rth);
  717. ll_init_map(&rth);
  718. if (idev || odev) {
  719. int idx;
  720. if (idev) {
  721. idx = xll_name_to_index(idev);
  722. addattr32(&req.n, sizeof(req), RTA_IIF, idx);
  723. }
  724. if (odev) {
  725. idx = xll_name_to_index(odev);
  726. addattr32(&req.n, sizeof(req), RTA_OIF, idx);
  727. }
  728. }
  729. if (req.r.rtm_family == AF_UNSPEC) {
  730. req.r.rtm_family = AF_INET;
  731. }
  732. if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
  733. return 2;
  734. }
  735. if (connected && !from_ok) {
  736. struct rtmsg *r = NLMSG_DATA(&req.n);
  737. int len = req.n.nlmsg_len;
  738. struct rtattr * tb[RTA_MAX+1];
  739. print_route(NULL, &req.n, NULL);
  740. if (req.n.nlmsg_type != RTM_NEWROUTE) {
  741. bb_error_msg_and_die("not a route?");
  742. }
  743. len -= NLMSG_LENGTH(sizeof(*r));
  744. if (len < 0) {
  745. bb_error_msg_and_die("wrong len %d", len);
  746. }
  747. memset(tb, 0, sizeof(tb));
  748. parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len);
  749. if (tb[RTA_PREFSRC]) {
  750. tb[RTA_PREFSRC]->rta_type = RTA_SRC;
  751. r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]);
  752. } else if (!tb[RTA_SRC]) {
  753. bb_error_msg_and_die("failed to connect the route");
  754. }
  755. if (!odev && tb[RTA_OIF]) {
  756. tb[RTA_OIF]->rta_type = 0;
  757. }
  758. if (tb[RTA_GATEWAY]) {
  759. tb[RTA_GATEWAY]->rta_type = 0;
  760. }
  761. if (!idev && tb[RTA_IIF]) {
  762. tb[RTA_IIF]->rta_type = 0;
  763. }
  764. req.n.nlmsg_flags = NLM_F_REQUEST;
  765. req.n.nlmsg_type = RTM_GETROUTE;
  766. if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) {
  767. return 2;
  768. }
  769. }
  770. print_route(NULL, &req.n, NULL);
  771. return 0;
  772. }
  773. /* Return value becomes exitcode. It's okay to not return at all */
  774. int do_iproute(char **argv)
  775. {
  776. static const char ip_route_commands[] ALIGN1 =
  777. /*0-3*/ "add\0""append\0""change\0""chg\0"
  778. /*4-7*/ "delete\0""get\0""list\0""show\0"
  779. /*8..*/ "prepend\0""replace\0""test\0""flush\0";
  780. int command_num;
  781. unsigned flags = 0;
  782. int cmd = RTM_NEWROUTE;
  783. if (!*argv)
  784. return iproute_list_or_flush(argv, 0);
  785. /* "Standard" 'ip r a' treats 'a' as 'add', not 'append' */
  786. /* It probably means that it is using "first match" rule */
  787. command_num = index_in_substrings(ip_route_commands, *argv);
  788. switch (command_num) {
  789. case 0: /* add */
  790. flags = NLM_F_CREATE|NLM_F_EXCL;
  791. break;
  792. case 1: /* append */
  793. flags = NLM_F_CREATE|NLM_F_APPEND;
  794. break;
  795. case 2: /* change */
  796. case 3: /* chg */
  797. flags = NLM_F_REPLACE;
  798. break;
  799. case 4: /* delete */
  800. cmd = RTM_DELROUTE;
  801. break;
  802. case 5: /* get */
  803. return iproute_get(argv+1);
  804. case 6: /* list */
  805. case 7: /* show */
  806. return iproute_list_or_flush(argv+1, 0);
  807. case 8: /* prepend */
  808. flags = NLM_F_CREATE;
  809. break;
  810. case 9: /* replace */
  811. flags = NLM_F_CREATE|NLM_F_REPLACE;
  812. break;
  813. case 10: /* test */
  814. flags = NLM_F_EXCL;
  815. break;
  816. case 11: /* flush */
  817. return iproute_list_or_flush(argv+1, 1);
  818. default:
  819. bb_error_msg_and_die("unknown command %s", *argv);
  820. }
  821. return iproute_modify(cmd, flags, argv+1);
  822. }