iproute.c 22 KB

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