3
0

iproute.c 21 KB

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