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