iproute.c 21 KB

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