iproute.c revision f4f6d6407d43b81152e366b2011b606db1083802
1/* 2 * iproute.c "ip route". 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> 10 * 11 * 12 * Changes: 13 * 14 * Rani Assaf <rani@magic.metawire.com> 980929: resolve addresses 15 * Kunihiro Ishiguro <kunihiro@zebra.org> 001102: rtnh_ifindex was not initialized 16 */ 17 18#include <stdio.h> 19#include <stdlib.h> 20#include <unistd.h> 21#include <syslog.h> 22#include <fcntl.h> 23#include <string.h> 24#include <time.h> 25#include <sys/time.h> 26#include <sys/socket.h> 27#include <netinet/in.h> 28#include <netinet/ip.h> 29#include <arpa/inet.h> 30#include <linux/in_route.h> 31#include <linux/ip_mp_alg.h> 32 33#include "rt_names.h" 34#include "utils.h" 35#include "ip_common.h" 36 37#ifndef RTAX_RTTVAR 38#define RTAX_RTTVAR RTAX_HOPS 39#endif 40 41 42static const char *mx_names[RTAX_MAX+1] = { 43 [RTAX_MTU] = "mtu", 44 [RTAX_WINDOW] = "window", 45 [RTAX_RTT] = "rtt", 46 [RTAX_RTTVAR] = "rttvar", 47 [RTAX_SSTHRESH] = "ssthresh", 48 [RTAX_CWND] = "cwnd", 49 [RTAX_ADVMSS] = "advmss", 50 [RTAX_REORDERING]="reordering", 51 [RTAX_HOPLIMIT] = "hoplimit", 52 [RTAX_INITCWND] = "initcwnd", 53 [RTAX_FEATURES] = "features", 54}; 55static void usage(void) __attribute__((noreturn)); 56 57static void usage(void) 58{ 59 fprintf(stderr, "Usage: ip route { list | flush } SELECTOR\n"); 60 fprintf(stderr, " ip route get ADDRESS [ from ADDRESS iif STRING ]\n"); 61 fprintf(stderr, " [ oif STRING ] [ tos TOS ]\n"); 62 fprintf(stderr, " ip route { add | del | change | append | replace | monitor } ROUTE\n"); 63 fprintf(stderr, "SELECTOR := [ root PREFIX ] [ match PREFIX ] [ exact PREFIX ]\n"); 64 fprintf(stderr, " [ table TABLE_ID ] [ proto RTPROTO ]\n"); 65 fprintf(stderr, " [ type TYPE ] [ scope SCOPE ]\n"); 66 fprintf(stderr, "ROUTE := NODE_SPEC [ INFO_SPEC ]\n"); 67 fprintf(stderr, "NODE_SPEC := [ TYPE ] PREFIX [ tos TOS ]\n"); 68 fprintf(stderr, " [ table TABLE_ID ] [ proto RTPROTO ]\n"); 69 fprintf(stderr, " [ scope SCOPE ] [ metric METRIC ]\n"); 70 fprintf(stderr, " [ mpath MP_ALGO ]\n"); 71 fprintf(stderr, "INFO_SPEC := NH OPTIONS FLAGS [ nexthop NH ]...\n"); 72 fprintf(stderr, "NH := [ via ADDRESS ] [ dev STRING ] [ weight NUMBER ] NHFLAGS\n"); 73 fprintf(stderr, "OPTIONS := FLAGS [ mtu NUMBER ] [ advmss NUMBER ]\n"); 74 fprintf(stderr, " [ rtt NUMBER ] [ rttvar NUMBER ]\n"); 75 fprintf(stderr, " [ window NUMBER] [ cwnd NUMBER ] [ initcwnd NUMBER ]\n"); 76 fprintf(stderr, " [ ssthresh NUMBER ] [ realms REALM ]\n"); 77 fprintf(stderr, "TYPE := [ unicast | local | broadcast | multicast | throw |\n"); 78 fprintf(stderr, " unreachable | prohibit | blackhole | nat ]\n"); 79 fprintf(stderr, "TABLE_ID := [ local | main | default | all | NUMBER ]\n"); 80 fprintf(stderr, "SCOPE := [ host | link | global | NUMBER ]\n"); 81 fprintf(stderr, "FLAGS := [ equalize ]\n"); 82 fprintf(stderr, "MP_ALGO := { rr | drr | random | wrandom }\n"); 83 fprintf(stderr, "NHFLAGS := [ onlink | pervasive ]\n"); 84 fprintf(stderr, "RTPROTO := [ kernel | boot | static | NUMBER ]\n"); 85 exit(-1); 86} 87 88 89static struct 90{ 91 int tb; 92 int flushed; 93 char *flushb; 94 int flushp; 95 int flushe; 96 int protocol, protocolmask; 97 int scope, scopemask; 98 int type, typemask; 99 int tos, tosmask; 100 int iif, iifmask; 101 int oif, oifmask; 102 int realm, realmmask; 103 inet_prefix rprefsrc; 104 inet_prefix rvia; 105 inet_prefix rdst; 106 inet_prefix mdst; 107 inet_prefix rsrc; 108 inet_prefix msrc; 109} filter; 110 111static char *mp_alg_names[IP_MP_ALG_MAX+1] = { 112 [IP_MP_ALG_NONE] = "none", 113 [IP_MP_ALG_RR] = "rr", 114 [IP_MP_ALG_DRR] = "drr", 115 [IP_MP_ALG_RANDOM] = "random", 116 [IP_MP_ALG_WRANDOM] = "wrandom" 117}; 118 119static int flush_update(void) 120{ 121 if (rtnl_send(&rth, filter.flushb, filter.flushp) < 0) { 122 perror("Failed to send flush request\n"); 123 return -1; 124 } 125 filter.flushp = 0; 126 return 0; 127} 128 129int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 130{ 131 FILE *fp = (FILE*)arg; 132 struct rtmsg *r = NLMSG_DATA(n); 133 int len = n->nlmsg_len; 134 struct rtattr * tb[RTA_MAX+1]; 135 char abuf[256]; 136 inet_prefix dst; 137 inet_prefix src; 138 inet_prefix prefsrc; 139 inet_prefix via; 140 int host_len = -1; 141 SPRINT_BUF(b1); 142 143 144 if (n->nlmsg_type != RTM_NEWROUTE && n->nlmsg_type != RTM_DELROUTE) { 145 fprintf(stderr, "Not a route: %08x %08x %08x\n", 146 n->nlmsg_len, n->nlmsg_type, n->nlmsg_flags); 147 return 0; 148 } 149 if (filter.flushb && n->nlmsg_type != RTM_NEWROUTE) 150 return 0; 151 len -= NLMSG_LENGTH(sizeof(*r)); 152 if (len < 0) { 153 fprintf(stderr, "BUG: wrong nlmsg len %d\n", len); 154 return -1; 155 } 156 157 if (r->rtm_family == AF_INET6) 158 host_len = 128; 159 else if (r->rtm_family == AF_INET) 160 host_len = 32; 161 else if (r->rtm_family == AF_DECnet) 162 host_len = 16; 163 else if (r->rtm_family == AF_IPX) 164 host_len = 80; 165 166 if (r->rtm_family == AF_INET6) { 167 if (filter.tb) { 168 if (filter.tb < 0) { 169 if (!(r->rtm_flags&RTM_F_CLONED)) 170 return 0; 171 } else { 172 if (r->rtm_flags&RTM_F_CLONED) 173 return 0; 174 if (filter.tb == RT_TABLE_LOCAL) { 175 if (r->rtm_type != RTN_LOCAL) 176 return 0; 177 } else if (filter.tb == RT_TABLE_MAIN) { 178 if (r->rtm_type == RTN_LOCAL) 179 return 0; 180 } else { 181 return 0; 182 } 183 } 184 } 185 } else { 186 if (filter.tb > 0 && filter.tb != r->rtm_table) 187 return 0; 188 } 189 if ((filter.protocol^r->rtm_protocol)&filter.protocolmask) 190 return 0; 191 if ((filter.scope^r->rtm_scope)&filter.scopemask) 192 return 0; 193 if ((filter.type^r->rtm_type)&filter.typemask) 194 return 0; 195 if ((filter.tos^r->rtm_tos)&filter.tosmask) 196 return 0; 197 if (filter.rdst.family && 198 (r->rtm_family != filter.rdst.family || filter.rdst.bitlen > r->rtm_dst_len)) 199 return 0; 200 if (filter.mdst.family && 201 (r->rtm_family != filter.mdst.family || 202 (filter.mdst.bitlen >= 0 && filter.mdst.bitlen < r->rtm_dst_len))) 203 return 0; 204 if (filter.rsrc.family && 205 (r->rtm_family != filter.rsrc.family || filter.rsrc.bitlen > r->rtm_src_len)) 206 return 0; 207 if (filter.msrc.family && 208 (r->rtm_family != filter.msrc.family || 209 (filter.msrc.bitlen >= 0 && filter.msrc.bitlen < r->rtm_src_len))) 210 return 0; 211 if (filter.rvia.family && r->rtm_family != filter.rvia.family) 212 return 0; 213 if (filter.rprefsrc.family && r->rtm_family != filter.rprefsrc.family) 214 return 0; 215 216 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 217 218 memset(&dst, 0, sizeof(dst)); 219 dst.family = r->rtm_family; 220 if (tb[RTA_DST]) 221 memcpy(&dst.data, RTA_DATA(tb[RTA_DST]), (r->rtm_dst_len+7)/8); 222 if (filter.rsrc.family || filter.msrc.family) { 223 memset(&src, 0, sizeof(src)); 224 src.family = r->rtm_family; 225 if (tb[RTA_SRC]) 226 memcpy(&src.data, RTA_DATA(tb[RTA_SRC]), (r->rtm_src_len+7)/8); 227 } 228 if (filter.rvia.bitlen>0) { 229 memset(&via, 0, sizeof(via)); 230 via.family = r->rtm_family; 231 if (tb[RTA_GATEWAY]) 232 memcpy(&via.data, RTA_DATA(tb[RTA_GATEWAY]), host_len/8); 233 } 234 if (filter.rprefsrc.bitlen>0) { 235 memset(&prefsrc, 0, sizeof(prefsrc)); 236 prefsrc.family = r->rtm_family; 237 if (tb[RTA_PREFSRC]) 238 memcpy(&prefsrc.data, RTA_DATA(tb[RTA_PREFSRC]), host_len/8); 239 } 240 241 if (filter.rdst.family && inet_addr_match(&dst, &filter.rdst, filter.rdst.bitlen)) 242 return 0; 243 if (filter.mdst.family && filter.mdst.bitlen >= 0 && 244 inet_addr_match(&dst, &filter.mdst, r->rtm_dst_len)) 245 return 0; 246 247 if (filter.rsrc.family && inet_addr_match(&src, &filter.rsrc, filter.rsrc.bitlen)) 248 return 0; 249 if (filter.msrc.family && filter.msrc.bitlen >= 0 && 250 inet_addr_match(&src, &filter.msrc, r->rtm_src_len)) 251 return 0; 252 253 if (filter.rvia.family && inet_addr_match(&via, &filter.rvia, filter.rvia.bitlen)) 254 return 0; 255 if (filter.rprefsrc.family && inet_addr_match(&prefsrc, &filter.rprefsrc, filter.rprefsrc.bitlen)) 256 return 0; 257 if (filter.realmmask) { 258 __u32 realms = 0; 259 if (tb[RTA_FLOW]) 260 realms = *(__u32*)RTA_DATA(tb[RTA_FLOW]); 261 if ((realms^filter.realm)&filter.realmmask) 262 return 0; 263 } 264 if (filter.iifmask) { 265 int iif = 0; 266 if (tb[RTA_IIF]) 267 iif = *(int*)RTA_DATA(tb[RTA_IIF]); 268 if ((iif^filter.iif)&filter.iifmask) 269 return 0; 270 } 271 if (filter.oifmask) { 272 int oif = 0; 273 if (tb[RTA_OIF]) 274 oif = *(int*)RTA_DATA(tb[RTA_OIF]); 275 if ((oif^filter.oif)&filter.oifmask) 276 return 0; 277 } 278 if (filter.flushb && 279 r->rtm_family == AF_INET6 && 280 r->rtm_dst_len == 0 && 281 r->rtm_type == RTN_UNREACHABLE && 282 tb[RTA_PRIORITY] && 283 *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1) 284 return 0; 285 286 if (filter.flushb) { 287 struct nlmsghdr *fn; 288 if (NLMSG_ALIGN(filter.flushp) + n->nlmsg_len > filter.flushe) { 289 if (flush_update()) 290 return -1; 291 } 292 fn = (struct nlmsghdr*)(filter.flushb + NLMSG_ALIGN(filter.flushp)); 293 memcpy(fn, n, n->nlmsg_len); 294 fn->nlmsg_type = RTM_DELROUTE; 295 fn->nlmsg_flags = NLM_F_REQUEST; 296 fn->nlmsg_seq = ++rth.seq; 297 filter.flushp = (((char*)fn) + n->nlmsg_len) - filter.flushb; 298 filter.flushed++; 299 if (show_stats < 2) 300 return 0; 301 } 302 303 if (n->nlmsg_type == RTM_DELROUTE) 304 fprintf(fp, "Deleted "); 305 if (r->rtm_type != RTN_UNICAST && !filter.type) 306 fprintf(fp, "%s ", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); 307 308 if (tb[RTA_DST]) { 309 if (r->rtm_dst_len != host_len) { 310 fprintf(fp, "%s/%u ", rt_addr_n2a(r->rtm_family, 311 RTA_PAYLOAD(tb[RTA_DST]), 312 RTA_DATA(tb[RTA_DST]), 313 abuf, sizeof(abuf)), 314 r->rtm_dst_len 315 ); 316 } else { 317 fprintf(fp, "%s ", format_host(r->rtm_family, 318 RTA_PAYLOAD(tb[RTA_DST]), 319 RTA_DATA(tb[RTA_DST]), 320 abuf, sizeof(abuf)) 321 ); 322 } 323 } else if (r->rtm_dst_len) { 324 fprintf(fp, "0/%d ", r->rtm_dst_len); 325 } else { 326 fprintf(fp, "default "); 327 } 328 if (tb[RTA_SRC]) { 329 if (r->rtm_src_len != host_len) { 330 fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, 331 RTA_PAYLOAD(tb[RTA_SRC]), 332 RTA_DATA(tb[RTA_SRC]), 333 abuf, sizeof(abuf)), 334 r->rtm_src_len 335 ); 336 } else { 337 fprintf(fp, "from %s ", format_host(r->rtm_family, 338 RTA_PAYLOAD(tb[RTA_SRC]), 339 RTA_DATA(tb[RTA_SRC]), 340 abuf, sizeof(abuf)) 341 ); 342 } 343 } else if (r->rtm_src_len) { 344 fprintf(fp, "from 0/%u ", r->rtm_src_len); 345 } 346 if (r->rtm_tos && filter.tosmask != -1) { 347 SPRINT_BUF(b1); 348 fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); 349 } 350 351 if (tb[RTA_MP_ALGO]) { 352 __u32 mp_alg = *(__u32*) RTA_DATA(tb[RTA_MP_ALGO]); 353 if (mp_alg > IP_MP_ALG_NONE) { 354 fprintf(fp, "mpath %s ", 355 mp_alg < IP_MP_ALG_MAX ? mp_alg_names[mp_alg] : "unknown"); 356 } 357 } 358 359 if (tb[RTA_GATEWAY] && filter.rvia.bitlen != host_len) { 360 fprintf(fp, "via %s ", 361 format_host(r->rtm_family, 362 RTA_PAYLOAD(tb[RTA_GATEWAY]), 363 RTA_DATA(tb[RTA_GATEWAY]), 364 abuf, sizeof(abuf))); 365 } 366 if (tb[RTA_OIF] && filter.oifmask != -1) 367 fprintf(fp, "dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); 368 369 if (!(r->rtm_flags&RTM_F_CLONED)) { 370 if (r->rtm_table != RT_TABLE_MAIN && !filter.tb) 371 fprintf(fp, " table %s ", rtnl_rttable_n2a(r->rtm_table, b1, sizeof(b1))); 372 if (r->rtm_protocol != RTPROT_BOOT && filter.protocolmask != -1) 373 fprintf(fp, " proto %s ", rtnl_rtprot_n2a(r->rtm_protocol, b1, sizeof(b1))); 374 if (r->rtm_scope != RT_SCOPE_UNIVERSE && filter.scopemask != -1) 375 fprintf(fp, " scope %s ", rtnl_rtscope_n2a(r->rtm_scope, b1, sizeof(b1))); 376 } 377 if (tb[RTA_PREFSRC] && filter.rprefsrc.bitlen != host_len) { 378 /* Do not use format_host(). It is our local addr 379 and symbolic name will not be useful. 380 */ 381 fprintf(fp, " src %s ", 382 rt_addr_n2a(r->rtm_family, 383 RTA_PAYLOAD(tb[RTA_PREFSRC]), 384 RTA_DATA(tb[RTA_PREFSRC]), 385 abuf, sizeof(abuf))); 386 } 387 if (tb[RTA_PRIORITY]) 388 fprintf(fp, " metric %d ", *(__u32*)RTA_DATA(tb[RTA_PRIORITY])); 389 if (r->rtm_flags & RTNH_F_DEAD) 390 fprintf(fp, "dead "); 391 if (r->rtm_flags & RTNH_F_ONLINK) 392 fprintf(fp, "onlink "); 393 if (r->rtm_flags & RTNH_F_PERVASIVE) 394 fprintf(fp, "pervasive "); 395 if (r->rtm_flags & RTM_F_EQUALIZE) 396 fprintf(fp, "equalize "); 397 if (r->rtm_flags & RTM_F_NOTIFY) 398 fprintf(fp, "notify "); 399 400 if (tb[RTA_FLOW] && filter.realmmask != ~0U) { 401 __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]); 402 __u32 from = to>>16; 403 to &= 0xFFFF; 404 fprintf(fp, "realm%s ", from ? "s" : ""); 405 if (from) { 406 fprintf(fp, "%s/", 407 rtnl_rtrealm_n2a(from, b1, sizeof(b1))); 408 } 409 fprintf(fp, "%s ", 410 rtnl_rtrealm_n2a(to, b1, sizeof(b1))); 411 } 412 if ((r->rtm_flags&RTM_F_CLONED) && r->rtm_family == AF_INET) { 413 __u32 flags = r->rtm_flags&~0xFFFF; 414 int first = 1; 415 416 fprintf(fp, "%s cache ", _SL_); 417 418#define PRTFL(fl,flname) if (flags&RTCF_##fl) { \ 419 flags &= ~RTCF_##fl; \ 420 fprintf(fp, "%s" flname "%s", first ? "<" : "", flags ? "," : "> "); \ 421 first = 0; } 422 PRTFL(LOCAL, "local"); 423 PRTFL(REJECT, "reject"); 424 PRTFL(MULTICAST, "mc"); 425 PRTFL(BROADCAST, "brd"); 426 PRTFL(DNAT, "dst-nat"); 427 PRTFL(SNAT, "src-nat"); 428 PRTFL(MASQ, "masq"); 429 PRTFL(DIRECTDST, "dst-direct"); 430 PRTFL(DIRECTSRC, "src-direct"); 431 PRTFL(REDIRECTED, "redirected"); 432 PRTFL(DOREDIRECT, "redirect"); 433 PRTFL(FAST, "fastroute"); 434 PRTFL(NOTIFY, "notify"); 435 PRTFL(TPROXY, "proxy"); 436#ifdef RTCF_EQUALIZE 437 PRTFL(EQUALIZE, "equalize"); 438#endif 439 if (flags) 440 fprintf(fp, "%s%x> ", first ? "<" : "", flags); 441 if (tb[RTA_CACHEINFO]) { 442 struct rta_cacheinfo *ci = RTA_DATA(tb[RTA_CACHEINFO]); 443 static int hz; 444 if (!hz) 445 hz = get_user_hz(); 446 if (ci->rta_expires != 0) 447 fprintf(fp, " expires %dsec", ci->rta_expires/hz); 448 if (ci->rta_error != 0) 449 fprintf(fp, " error %d", ci->rta_error); 450 if (show_stats) { 451 if (ci->rta_clntref) 452 fprintf(fp, " users %d", ci->rta_clntref); 453 if (ci->rta_used != 0) 454 fprintf(fp, " used %d", ci->rta_used); 455 if (ci->rta_lastuse != 0) 456 fprintf(fp, " age %dsec", ci->rta_lastuse/hz); 457 } 458#ifdef RTNETLINK_HAVE_PEERINFO 459 if (ci->rta_id) 460 fprintf(fp, " ipid 0x%04x", ci->rta_id); 461 if (ci->rta_ts || ci->rta_tsage) 462 fprintf(fp, " ts 0x%x tsage %dsec", ci->rta_ts, ci->rta_tsage); 463#endif 464 } 465 } else if (r->rtm_family == AF_INET6) { 466 struct rta_cacheinfo *ci = NULL; 467 if (tb[RTA_CACHEINFO]) 468 ci = RTA_DATA(tb[RTA_CACHEINFO]); 469 if ((r->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { 470 static int hz; 471 if (!hz) 472 hz = get_user_hz(); 473 if (r->rtm_flags & RTM_F_CLONED) 474 fprintf(fp, "%s cache ", _SL_); 475 if (ci->rta_expires) 476 fprintf(fp, " expires %dsec", ci->rta_expires/hz); 477 if (ci->rta_error != 0) 478 fprintf(fp, " error %d", ci->rta_error); 479 if (show_stats) { 480 if (ci->rta_clntref) 481 fprintf(fp, " users %d", ci->rta_clntref); 482 if (ci->rta_used != 0) 483 fprintf(fp, " used %d", ci->rta_used); 484 if (ci->rta_lastuse != 0) 485 fprintf(fp, " age %dsec", ci->rta_lastuse/hz); 486 } 487 } else if (ci) { 488 if (ci->rta_error != 0) 489 fprintf(fp, " error %d", ci->rta_error); 490 } 491 } 492 if (tb[RTA_METRICS]) { 493 int i; 494 unsigned mxlock = 0; 495 struct rtattr *mxrta[RTAX_MAX+1]; 496 497 parse_rtattr(mxrta, RTAX_MAX, RTA_DATA(tb[RTA_METRICS]), 498 RTA_PAYLOAD(tb[RTA_METRICS])); 499 if (mxrta[RTAX_LOCK]) 500 mxlock = *(unsigned*)RTA_DATA(mxrta[RTAX_LOCK]); 501 502 for (i=2; i<= RTAX_MAX; i++) { 503 static int hz; 504 if (mxrta[i] == NULL) 505 continue; 506 if (!hz) 507 hz = get_hz(); 508 if (i-2 < sizeof(mx_names)/sizeof(char*)) 509 fprintf(fp, " %s", mx_names[i-2]); 510 else 511 fprintf(fp, " metric %d", i); 512 if (mxlock & (1<<i)) 513 fprintf(fp, " lock"); 514 515 if (i != RTAX_RTT && i != RTAX_RTTVAR) 516 fprintf(fp, " %u", *(unsigned*)RTA_DATA(mxrta[i])); 517 else { 518 unsigned val = *(unsigned*)RTA_DATA(mxrta[i]); 519 520 val *= 1000; 521 if (i == RTAX_RTT) 522 val /= 8; 523 else 524 val /= 4; 525 if (val >= hz) 526 fprintf(fp, " %ums", val/hz); 527 else 528 fprintf(fp, " %.2fms", (float)val/hz); 529 } 530 } 531 } 532 if (tb[RTA_IIF] && filter.iifmask != -1) { 533 fprintf(fp, " iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); 534 } 535 if (tb[RTA_MULTIPATH]) { 536 struct rtnexthop *nh = RTA_DATA(tb[RTA_MULTIPATH]); 537 int first = 0; 538 539 len = RTA_PAYLOAD(tb[RTA_MULTIPATH]); 540 541 for (;;) { 542 if (len < sizeof(*nh)) 543 break; 544 if (nh->rtnh_len > len) 545 break; 546 if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) { 547 if (first) 548 fprintf(fp, " Oifs:"); 549 else 550 fprintf(fp, " "); 551 } else 552 fprintf(fp, "%s\tnexthop", _SL_); 553 if (nh->rtnh_len > sizeof(*nh)) { 554 parse_rtattr(tb, RTA_MAX, RTNH_DATA(nh), nh->rtnh_len - sizeof(*nh)); 555 if (tb[RTA_GATEWAY]) { 556 fprintf(fp, " via %s ", 557 format_host(r->rtm_family, 558 RTA_PAYLOAD(tb[RTA_GATEWAY]), 559 RTA_DATA(tb[RTA_GATEWAY]), 560 abuf, sizeof(abuf))); 561 } 562 if (tb[RTA_FLOW]) { 563 __u32 to = *(__u32*)RTA_DATA(tb[RTA_FLOW]); 564 __u32 from = to>>16; 565 to &= 0xFFFF; 566 fprintf(fp, " realm%s ", from ? "s" : ""); 567 if (from) { 568 fprintf(fp, "%s/", 569 rtnl_rtrealm_n2a(from, b1, sizeof(b1))); 570 } 571 fprintf(fp, "%s", 572 rtnl_rtrealm_n2a(to, b1, sizeof(b1))); 573 } 574 } 575 if (r->rtm_flags&RTM_F_CLONED && r->rtm_type == RTN_MULTICAST) { 576 fprintf(fp, " %s", ll_index_to_name(nh->rtnh_ifindex)); 577 if (nh->rtnh_hops != 1) 578 fprintf(fp, "(ttl>%d)", nh->rtnh_hops); 579 } else { 580 fprintf(fp, " dev %s", ll_index_to_name(nh->rtnh_ifindex)); 581 fprintf(fp, " weight %d", nh->rtnh_hops+1); 582 } 583 if (nh->rtnh_flags & RTNH_F_DEAD) 584 fprintf(fp, " dead"); 585 if (nh->rtnh_flags & RTNH_F_ONLINK) 586 fprintf(fp, " onlink"); 587 if (nh->rtnh_flags & RTNH_F_PERVASIVE) 588 fprintf(fp, " pervasive"); 589 len -= NLMSG_ALIGN(nh->rtnh_len); 590 nh = RTNH_NEXT(nh); 591 } 592 } 593 fprintf(fp, "\n"); 594 fflush(fp); 595 return 0; 596} 597 598 599int parse_one_nh(struct rtattr *rta, struct rtnexthop *rtnh, int *argcp, char ***argvp) 600{ 601 int argc = *argcp; 602 char **argv = *argvp; 603 604 while (++argv, --argc > 0) { 605 if (strcmp(*argv, "via") == 0) { 606 NEXT_ARG(); 607 rta_addattr32(rta, 4096, RTA_GATEWAY, get_addr32(*argv)); 608 rtnh->rtnh_len += sizeof(struct rtattr) + 4; 609 } else if (strcmp(*argv, "dev") == 0) { 610 NEXT_ARG(); 611 if ((rtnh->rtnh_ifindex = ll_name_to_index(*argv)) == 0) { 612 fprintf(stderr, "Cannot find device \"%s\"\n", *argv); 613 exit(1); 614 } 615 } else if (strcmp(*argv, "weight") == 0) { 616 unsigned w; 617 NEXT_ARG(); 618 if (get_unsigned(&w, *argv, 0) || w == 0 || w > 256) 619 invarg("\"weight\" is invalid\n", *argv); 620 rtnh->rtnh_hops = w - 1; 621 } else if (strcmp(*argv, "onlink") == 0) { 622 rtnh->rtnh_flags |= RTNH_F_ONLINK; 623 } else if (matches(*argv, "realms") == 0) { 624 __u32 realm; 625 NEXT_ARG(); 626 if (get_rt_realms(&realm, *argv)) 627 invarg("\"realm\" value is invalid\n", *argv); 628 rta_addattr32(rta, 4096, RTA_FLOW, realm); 629 rtnh->rtnh_len += sizeof(struct rtattr) + 4; 630 } else 631 break; 632 } 633 *argcp = argc; 634 *argvp = argv; 635 return 0; 636} 637 638int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r, int argc, char **argv) 639{ 640 char buf[1024]; 641 struct rtattr *rta = (void*)buf; 642 struct rtnexthop *rtnh; 643 644 rta->rta_type = RTA_MULTIPATH; 645 rta->rta_len = RTA_LENGTH(0); 646 rtnh = RTA_DATA(rta); 647 648 while (argc > 0) { 649 if (strcmp(*argv, "nexthop") != 0) { 650 fprintf(stderr, "Error: \"nexthop\" or end of line is expected instead of \"%s\"\n", *argv); 651 exit(-1); 652 } 653 if (argc <= 1) { 654 fprintf(stderr, "Error: unexpected end of line after \"nexthop\"\n"); 655 exit(-1); 656 } 657 memset(rtnh, 0, sizeof(*rtnh)); 658 rtnh->rtnh_len = sizeof(*rtnh); 659 rta->rta_len += rtnh->rtnh_len; 660 parse_one_nh(rta, rtnh, &argc, &argv); 661 rtnh = RTNH_NEXT(rtnh); 662 } 663 664 if (rta->rta_len > RTA_LENGTH(0)) 665 addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta)); 666 return 0; 667} 668 669 670int iproute_modify(int cmd, unsigned flags, int argc, char **argv) 671{ 672 struct { 673 struct nlmsghdr n; 674 struct rtmsg r; 675 char buf[1024]; 676 } req; 677 char mxbuf[256]; 678 struct rtattr * mxrta = (void*)mxbuf; 679 unsigned mxlock = 0; 680 char *d = NULL; 681 int gw_ok = 0; 682 int dst_ok = 0; 683 int nhs_ok = 0; 684 int scope_ok = 0; 685 int table_ok = 0; 686 int proto_ok = 0; 687 int type_ok = 0; 688 689 memset(&req, 0, sizeof(req)); 690 691 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 692 req.n.nlmsg_flags = NLM_F_REQUEST|flags; 693 req.n.nlmsg_type = cmd; 694 req.r.rtm_family = preferred_family; 695 req.r.rtm_table = RT_TABLE_MAIN; 696 req.r.rtm_scope = RT_SCOPE_NOWHERE; 697 698 if (cmd != RTM_DELROUTE) { 699 req.r.rtm_protocol = RTPROT_BOOT; 700 req.r.rtm_scope = RT_SCOPE_UNIVERSE; 701 req.r.rtm_type = RTN_UNICAST; 702 } 703 704 mxrta->rta_type = RTA_METRICS; 705 mxrta->rta_len = RTA_LENGTH(0); 706 707 while (argc > 0) { 708 if (strcmp(*argv, "src") == 0) { 709 inet_prefix addr; 710 NEXT_ARG(); 711 get_addr(&addr, *argv, req.r.rtm_family); 712 if (req.r.rtm_family == AF_UNSPEC) 713 req.r.rtm_family = addr.family; 714 addattr_l(&req.n, sizeof(req), RTA_PREFSRC, &addr.data, addr.bytelen); 715 } else if (strcmp(*argv, "via") == 0) { 716 inet_prefix addr; 717 gw_ok = 1; 718 NEXT_ARG(); 719 get_addr(&addr, *argv, req.r.rtm_family); 720 if (req.r.rtm_family == AF_UNSPEC) 721 req.r.rtm_family = addr.family; 722 addattr_l(&req.n, sizeof(req), RTA_GATEWAY, &addr.data, addr.bytelen); 723 } else if (strcmp(*argv, "from") == 0) { 724 inet_prefix addr; 725 NEXT_ARG(); 726 get_prefix(&addr, *argv, req.r.rtm_family); 727 if (req.r.rtm_family == AF_UNSPEC) 728 req.r.rtm_family = addr.family; 729 if (addr.bytelen) 730 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen); 731 req.r.rtm_src_len = addr.bitlen; 732 } else if (strcmp(*argv, "tos") == 0 || 733 matches(*argv, "dsfield") == 0) { 734 __u32 tos; 735 NEXT_ARG(); 736 if (rtnl_dsfield_a2n(&tos, *argv)) 737 invarg("\"tos\" value is invalid\n", *argv); 738 req.r.rtm_tos = tos; 739 } else if (matches(*argv, "metric") == 0 || 740 matches(*argv, "priority") == 0 || 741 matches(*argv, "preference") == 0) { 742 __u32 metric; 743 NEXT_ARG(); 744 if (get_u32(&metric, *argv, 0)) 745 invarg("\"metric\" value is invalid\n", *argv); 746 addattr32(&req.n, sizeof(req), RTA_PRIORITY, metric); 747 } else if (strcmp(*argv, "scope") == 0) { 748 __u32 scope = 0; 749 NEXT_ARG(); 750 if (rtnl_rtscope_a2n(&scope, *argv)) 751 invarg("invalid \"scope\" value\n", *argv); 752 req.r.rtm_scope = scope; 753 scope_ok = 1; 754 } else if (strcmp(*argv, "mtu") == 0) { 755 unsigned mtu; 756 NEXT_ARG(); 757 if (strcmp(*argv, "lock") == 0) { 758 mxlock |= (1<<RTAX_MTU); 759 NEXT_ARG(); 760 } 761 if (get_unsigned(&mtu, *argv, 0)) 762 invarg("\"mtu\" value is invalid\n", *argv); 763 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_MTU, mtu); 764#ifdef RTAX_ADVMSS 765 } else if (strcmp(*argv, "advmss") == 0) { 766 unsigned mss; 767 NEXT_ARG(); 768 if (strcmp(*argv, "lock") == 0) { 769 mxlock |= (1<<RTAX_ADVMSS); 770 NEXT_ARG(); 771 } 772 if (get_unsigned(&mss, *argv, 0)) 773 invarg("\"mss\" value is invalid\n", *argv); 774 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_ADVMSS, mss); 775#endif 776#ifdef RTAX_REORDERING 777 } else if (matches(*argv, "reordering") == 0) { 778 unsigned reord; 779 NEXT_ARG(); 780 if (strcmp(*argv, "lock") == 0) { 781 mxlock |= (1<<RTAX_REORDERING); 782 NEXT_ARG(); 783 } 784 if (get_unsigned(&reord, *argv, 0)) 785 invarg("\"reordering\" value is invalid\n", *argv); 786 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_REORDERING, reord); 787#endif 788 } else if (strcmp(*argv, "rtt") == 0) { 789 unsigned rtt; 790 NEXT_ARG(); 791 if (strcmp(*argv, "lock") == 0) { 792 mxlock |= (1<<RTAX_RTT); 793 NEXT_ARG(); 794 } 795 if (get_unsigned(&rtt, *argv, 0)) 796 invarg("\"rtt\" value is invalid\n", *argv); 797 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTT, rtt); 798 } else if (matches(*argv, "window") == 0) { 799 unsigned win; 800 NEXT_ARG(); 801 if (strcmp(*argv, "lock") == 0) { 802 mxlock |= (1<<RTAX_WINDOW); 803 NEXT_ARG(); 804 } 805 if (get_unsigned(&win, *argv, 0)) 806 invarg("\"window\" value is invalid\n", *argv); 807 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_WINDOW, win); 808 } else if (matches(*argv, "cwnd") == 0) { 809 unsigned win; 810 NEXT_ARG(); 811 if (strcmp(*argv, "lock") == 0) { 812 mxlock |= (1<<RTAX_CWND); 813 NEXT_ARG(); 814 } 815 if (get_unsigned(&win, *argv, 0)) 816 invarg("\"cwnd\" value is invalid\n", *argv); 817 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_CWND, win); 818 } else if (matches(*argv, "initcwnd") == 0) { 819 unsigned win; 820 NEXT_ARG(); 821 if (strcmp(*argv, "lock") == 0) { 822 mxlock |= (1<<RTAX_INITCWND); 823 NEXT_ARG(); 824 } 825 if (get_unsigned(&win, *argv, 0)) 826 invarg("\"initcwnd\" value is invalid\n", *argv); 827 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_INITCWND, win); 828 } else if (matches(*argv, "rttvar") == 0) { 829 unsigned win; 830 NEXT_ARG(); 831 if (strcmp(*argv, "lock") == 0) { 832 mxlock |= (1<<RTAX_RTTVAR); 833 NEXT_ARG(); 834 } 835 if (get_unsigned(&win, *argv, 0)) 836 invarg("\"rttvar\" value is invalid\n", *argv); 837 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_RTTVAR, win); 838 } else if (matches(*argv, "ssthresh") == 0) { 839 unsigned win; 840 NEXT_ARG(); 841 if (strcmp(*argv, "lock") == 0) { 842 mxlock |= (1<<RTAX_SSTHRESH); 843 NEXT_ARG(); 844 } 845 if (get_unsigned(&win, *argv, 0)) 846 invarg("\"ssthresh\" value is invalid\n", *argv); 847 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_SSTHRESH, win); 848 } else if (matches(*argv, "realms") == 0) { 849 __u32 realm; 850 NEXT_ARG(); 851 if (get_rt_realms(&realm, *argv)) 852 invarg("\"realm\" value is invalid\n", *argv); 853 addattr32(&req.n, sizeof(req), RTA_FLOW, realm); 854 } else if (strcmp(*argv, "onlink") == 0) { 855 req.r.rtm_flags |= RTNH_F_ONLINK; 856 } else if (matches(*argv, "equalize") == 0 || 857 strcmp(*argv, "eql") == 0) { 858 req.r.rtm_flags |= RTM_F_EQUALIZE; 859 } else if (strcmp(*argv, "nexthop") == 0) { 860 nhs_ok = 1; 861 break; 862 } else if (matches(*argv, "protocol") == 0) { 863 __u32 prot; 864 NEXT_ARG(); 865 if (rtnl_rtprot_a2n(&prot, *argv)) 866 invarg("\"protocol\" value is invalid\n", *argv); 867 req.r.rtm_protocol = prot; 868 proto_ok =1; 869 } else if (matches(*argv, "table") == 0) { 870 __u32 tid; 871 NEXT_ARG(); 872 if (rtnl_rttable_a2n(&tid, *argv)) 873 invarg("\"table\" value is invalid\n", *argv); 874 req.r.rtm_table = tid; 875 table_ok = 1; 876 } else if (strcmp(*argv, "dev") == 0 || 877 strcmp(*argv, "oif") == 0) { 878 NEXT_ARG(); 879 d = *argv; 880 } else if (strcmp(*argv, "mpath") == 0 || 881 strcmp(*argv, "mp") == 0) { 882 int i; 883 __u32 mp_alg = IP_MP_ALG_NONE; 884 885 NEXT_ARG(); 886 for (i = 1; i < ARRAY_SIZE(mp_alg_names); i++) 887 if (strcmp(*argv, mp_alg_names[i]) == 0) 888 mp_alg = i; 889 if (mp_alg == IP_MP_ALG_NONE) 890 invarg("\"mpath\" value is invalid\n", *argv); 891 addattr_l(&req.n, sizeof(req), RTA_MP_ALGO, &mp_alg, sizeof(mp_alg)); 892 } else { 893 int type; 894 inet_prefix dst; 895 896 if (strcmp(*argv, "to") == 0) { 897 NEXT_ARG(); 898 } 899 if ((**argv < '0' || **argv > '9') && 900 rtnl_rtntype_a2n(&type, *argv) == 0) { 901 NEXT_ARG(); 902 req.r.rtm_type = type; 903 type_ok = 1; 904 } 905 906 if (matches(*argv, "help") == 0) 907 usage(); 908 if (dst_ok) 909 duparg2("to", *argv); 910 get_prefix(&dst, *argv, req.r.rtm_family); 911 if (req.r.rtm_family == AF_UNSPEC) 912 req.r.rtm_family = dst.family; 913 req.r.rtm_dst_len = dst.bitlen; 914 dst_ok = 1; 915 if (dst.bytelen) 916 addattr_l(&req.n, sizeof(req), RTA_DST, &dst.data, dst.bytelen); 917 } 918 argc--; argv++; 919 } 920 921 if (d || nhs_ok) { 922 int idx; 923 924 ll_init_map(&rth); 925 926 if (d) { 927 if ((idx = ll_name_to_index(d)) == 0) { 928 fprintf(stderr, "Cannot find device \"%s\"\n", d); 929 return -1; 930 } 931 addattr32(&req.n, sizeof(req), RTA_OIF, idx); 932 } 933 } 934 935 if (mxrta->rta_len > RTA_LENGTH(0)) { 936 if (mxlock) 937 rta_addattr32(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock); 938 addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta)); 939 } 940 941 if (nhs_ok) 942 parse_nexthops(&req.n, &req.r, argc, argv); 943 944 if (!table_ok) { 945 if (req.r.rtm_type == RTN_LOCAL || 946 req.r.rtm_type == RTN_BROADCAST || 947 req.r.rtm_type == RTN_NAT || 948 req.r.rtm_type == RTN_ANYCAST) 949 req.r.rtm_table = RT_TABLE_LOCAL; 950 } 951 if (!scope_ok) { 952 if (req.r.rtm_type == RTN_LOCAL || 953 req.r.rtm_type == RTN_NAT) 954 req.r.rtm_scope = RT_SCOPE_HOST; 955 else if (req.r.rtm_type == RTN_BROADCAST || 956 req.r.rtm_type == RTN_MULTICAST || 957 req.r.rtm_type == RTN_ANYCAST) 958 req.r.rtm_scope = RT_SCOPE_LINK; 959 else if (req.r.rtm_type == RTN_UNICAST || 960 req.r.rtm_type == RTN_UNSPEC) { 961 if (cmd == RTM_DELROUTE) 962 req.r.rtm_scope = RT_SCOPE_NOWHERE; 963 else if (!gw_ok && !nhs_ok) 964 req.r.rtm_scope = RT_SCOPE_LINK; 965 } 966 } 967 968 if (req.r.rtm_family == AF_UNSPEC) 969 req.r.rtm_family = AF_INET; 970 971 if (rtnl_talk(&rth, &req.n, 0, 0, NULL, NULL, NULL) < 0) 972 exit(2); 973 974 return 0; 975} 976 977static int rtnl_rtcache_request(struct rtnl_handle *rth, int family) 978{ 979 struct { 980 struct nlmsghdr nlh; 981 struct rtmsg rtm; 982 } req; 983 struct sockaddr_nl nladdr; 984 985 memset(&nladdr, 0, sizeof(nladdr)); 986 memset(&req, 0, sizeof(req)); 987 nladdr.nl_family = AF_NETLINK; 988 989 req.nlh.nlmsg_len = sizeof(req); 990 req.nlh.nlmsg_type = RTM_GETROUTE; 991 req.nlh.nlmsg_flags = NLM_F_ROOT|NLM_F_REQUEST; 992 req.nlh.nlmsg_pid = 0; 993 req.nlh.nlmsg_seq = rth->dump = ++rth->seq; 994 req.rtm.rtm_family = family; 995 req.rtm.rtm_flags |= RTM_F_CLONED; 996 997 return sendto(rth->fd, (void*)&req, sizeof(req), 0, (struct sockaddr*)&nladdr, sizeof(nladdr)); 998} 999 1000static int iproute_flush_cache(void) 1001{ 1002#define ROUTE_FLUSH_PATH "/proc/sys/net/ipv4/route/flush" 1003 1004 int len; 1005 int flush_fd = open (ROUTE_FLUSH_PATH, O_WRONLY); 1006 char *buffer = "-1"; 1007 1008 if (flush_fd < 0) { 1009 fprintf (stderr, "Cannot open \"%s\"\n", ROUTE_FLUSH_PATH); 1010 return -1; 1011 } 1012 1013 len = strlen (buffer); 1014 1015 if ((write (flush_fd, (void *)buffer, len)) < len) { 1016 fprintf (stderr, "Cannot flush routing cache\n"); 1017 return -1; 1018 } 1019 close(flush_fd); 1020 return 0; 1021} 1022 1023 1024static int iproute_list_or_flush(int argc, char **argv, int flush) 1025{ 1026 int do_ipv6 = preferred_family; 1027 char *id = NULL; 1028 char *od = NULL; 1029 1030 iproute_reset_filter(); 1031 filter.tb = RT_TABLE_MAIN; 1032 1033 if (flush && argc <= 0) { 1034 fprintf(stderr, "\"ip route flush\" requires arguments.\n"); 1035 return -1; 1036 } 1037 1038 while (argc > 0) { 1039 if (matches(*argv, "table") == 0) { 1040 __u32 tid; 1041 NEXT_ARG(); 1042 if (rtnl_rttable_a2n(&tid, *argv)) { 1043 if (strcmp(*argv, "all") == 0) { 1044 tid = 0; 1045 } else if (strcmp(*argv, "cache") == 0) { 1046 tid = -1; 1047 } else if (strcmp(*argv, "help") == 0) { 1048 usage(); 1049 } else { 1050 invarg("table id value is invalid\n", *argv); 1051 } 1052 } 1053 filter.tb = tid; 1054 } else if (matches(*argv, "cached") == 0 || 1055 matches(*argv, "cloned") == 0) { 1056 filter.tb = -1; 1057 } else if (strcmp(*argv, "tos") == 0 || 1058 matches(*argv, "dsfield") == 0) { 1059 __u32 tos; 1060 NEXT_ARG(); 1061 if (rtnl_dsfield_a2n(&tos, *argv)) 1062 invarg("TOS value is invalid\n", *argv); 1063 filter.tos = tos; 1064 filter.tosmask = -1; 1065 } else if (matches(*argv, "protocol") == 0) { 1066 __u32 prot = 0; 1067 NEXT_ARG(); 1068 filter.protocolmask = -1; 1069 if (rtnl_rtprot_a2n(&prot, *argv)) { 1070 if (strcmp(*argv, "all") != 0) 1071 invarg("invalid \"protocol\"\n", *argv); 1072 prot = 0; 1073 filter.protocolmask = 0; 1074 } 1075 filter.protocol = prot; 1076 } else if (matches(*argv, "scope") == 0) { 1077 __u32 scope = 0; 1078 NEXT_ARG(); 1079 filter.scopemask = -1; 1080 if (rtnl_rtscope_a2n(&scope, *argv)) { 1081 if (strcmp(*argv, "all") != 0) 1082 invarg("invalid \"scope\"\n", *argv); 1083 scope = RT_SCOPE_NOWHERE; 1084 filter.scopemask = 0; 1085 } 1086 filter.scope = scope; 1087 } else if (matches(*argv, "type") == 0) { 1088 int type; 1089 NEXT_ARG(); 1090 filter.typemask = -1; 1091 if (rtnl_rtntype_a2n(&type, *argv)) 1092 invarg("node type value is invalid\n", *argv); 1093 filter.type = type; 1094 } else if (strcmp(*argv, "dev") == 0 || 1095 strcmp(*argv, "oif") == 0) { 1096 NEXT_ARG(); 1097 od = *argv; 1098 } else if (strcmp(*argv, "iif") == 0) { 1099 NEXT_ARG(); 1100 id = *argv; 1101 } else if (strcmp(*argv, "via") == 0) { 1102 NEXT_ARG(); 1103 get_prefix(&filter.rvia, *argv, do_ipv6); 1104 } else if (strcmp(*argv, "src") == 0) { 1105 NEXT_ARG(); 1106 get_prefix(&filter.rprefsrc, *argv, do_ipv6); 1107 } else if (matches(*argv, "realms") == 0) { 1108 __u32 realm; 1109 NEXT_ARG(); 1110 if (get_rt_realms(&realm, *argv)) 1111 invarg("invalid realms\n", *argv); 1112 filter.realm = realm; 1113 filter.realmmask = ~0U; 1114 if ((filter.realm&0xFFFF) == 0 && 1115 (*argv)[strlen(*argv) - 1] == '/') 1116 filter.realmmask &= ~0xFFFF; 1117 if ((filter.realm&0xFFFF0000U) == 0 && 1118 (strchr(*argv, '/') == NULL || 1119 (*argv)[0] == '/')) 1120 filter.realmmask &= ~0xFFFF0000U; 1121 } else if (matches(*argv, "from") == 0) { 1122 NEXT_ARG(); 1123 if (matches(*argv, "root") == 0) { 1124 NEXT_ARG(); 1125 get_prefix(&filter.rsrc, *argv, do_ipv6); 1126 } else if (matches(*argv, "match") == 0) { 1127 NEXT_ARG(); 1128 get_prefix(&filter.msrc, *argv, do_ipv6); 1129 } else { 1130 if (matches(*argv, "exact") == 0) { 1131 NEXT_ARG(); 1132 } 1133 get_prefix(&filter.msrc, *argv, do_ipv6); 1134 filter.rsrc = filter.msrc; 1135 } 1136 } else { 1137 if (matches(*argv, "to") == 0) { 1138 NEXT_ARG(); 1139 } 1140 if (matches(*argv, "root") == 0) { 1141 NEXT_ARG(); 1142 get_prefix(&filter.rdst, *argv, do_ipv6); 1143 } else if (matches(*argv, "match") == 0) { 1144 NEXT_ARG(); 1145 get_prefix(&filter.mdst, *argv, do_ipv6); 1146 } else { 1147 if (matches(*argv, "exact") == 0) { 1148 NEXT_ARG(); 1149 } 1150 get_prefix(&filter.mdst, *argv, do_ipv6); 1151 filter.rdst = filter.mdst; 1152 } 1153 } 1154 argc--; argv++; 1155 } 1156 1157 if (do_ipv6 == AF_UNSPEC && filter.tb) 1158 do_ipv6 = AF_INET; 1159 1160 ll_init_map(&rth); 1161 1162 if (id || od) { 1163 int idx; 1164 1165 if (id) { 1166 if ((idx = ll_name_to_index(id)) == 0) { 1167 fprintf(stderr, "Cannot find device \"%s\"\n", id); 1168 return -1; 1169 } 1170 filter.iif = idx; 1171 filter.iifmask = -1; 1172 } 1173 if (od) { 1174 if ((idx = ll_name_to_index(od)) == 0) { 1175 fprintf(stderr, "Cannot find device \"%s\"\n", od); 1176 return -1; 1177 } 1178 filter.oif = idx; 1179 filter.oifmask = -1; 1180 } 1181 } 1182 1183 if (flush) { 1184 int round = 0; 1185 char flushb[4096-512]; 1186 time_t start = time(0); 1187 1188 if (filter.tb == -1) { 1189 if (do_ipv6 != AF_INET6) { 1190 iproute_flush_cache(); 1191 if (show_stats) 1192 printf("*** IPv4 routing cache is flushed.\n"); 1193 } 1194 if (do_ipv6 == AF_INET) 1195 return 0; 1196 } 1197 1198 filter.flushb = flushb; 1199 filter.flushp = 0; 1200 filter.flushe = sizeof(flushb); 1201 1202 for (;;) { 1203 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { 1204 perror("Cannot send dump request"); 1205 exit(1); 1206 } 1207 filter.flushed = 0; 1208 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { 1209 fprintf(stderr, "Flush terminated\n"); 1210 exit(1); 1211 } 1212 if (filter.flushed == 0) { 1213 if (round == 0) { 1214 if (filter.tb != -1 || do_ipv6 == AF_INET6) 1215 fprintf(stderr, "Nothing to flush.\n"); 1216 } else if (show_stats) 1217 printf("*** Flush is complete after %d round%s ***\n", round, round>1?"s":""); 1218 fflush(stdout); 1219 return 0; 1220 } 1221 round++; 1222 if (flush_update() < 0) 1223 exit(1); 1224 1225 if (time(0) - start > 30) { 1226 printf("\n*** Flush not completed after %ld seconds, %d entries remain ***\n", 1227 time(0) - start, filter.flushed); 1228 exit(1); 1229 } 1230 1231 if (show_stats) { 1232 printf("\n*** Round %d, deleting %d entries ***\n", round, filter.flushed); 1233 fflush(stdout); 1234 } 1235 } 1236 } 1237 1238 if (filter.tb != -1) { 1239 if (rtnl_wilddump_request(&rth, do_ipv6, RTM_GETROUTE) < 0) { 1240 perror("Cannot send dump request"); 1241 exit(1); 1242 } 1243 } else { 1244 if (rtnl_rtcache_request(&rth, do_ipv6) < 0) { 1245 perror("Cannot send dump request"); 1246 exit(1); 1247 } 1248 } 1249 1250 if (rtnl_dump_filter(&rth, print_route, stdout, NULL, NULL) < 0) { 1251 fprintf(stderr, "Dump terminated\n"); 1252 exit(1); 1253 } 1254 1255 exit(0); 1256} 1257 1258 1259int iproute_get(int argc, char **argv) 1260{ 1261 struct { 1262 struct nlmsghdr n; 1263 struct rtmsg r; 1264 char buf[1024]; 1265 } req; 1266 char *idev = NULL; 1267 char *odev = NULL; 1268 int connected = 0; 1269 int from_ok = 0; 1270 1271 memset(&req, 0, sizeof(req)); 1272 1273 iproute_reset_filter(); 1274 1275 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 1276 req.n.nlmsg_flags = NLM_F_REQUEST; 1277 req.n.nlmsg_type = RTM_GETROUTE; 1278 req.r.rtm_family = preferred_family; 1279 req.r.rtm_table = 0; 1280 req.r.rtm_protocol = 0; 1281 req.r.rtm_scope = 0; 1282 req.r.rtm_type = 0; 1283 req.r.rtm_src_len = 0; 1284 req.r.rtm_dst_len = 0; 1285 req.r.rtm_tos = 0; 1286 1287 while (argc > 0) { 1288 if (strcmp(*argv, "tos") == 0 || 1289 matches(*argv, "dsfield") == 0) { 1290 __u32 tos; 1291 NEXT_ARG(); 1292 if (rtnl_dsfield_a2n(&tos, *argv)) 1293 invarg("TOS value is invalid\n", *argv); 1294 req.r.rtm_tos = tos; 1295 } else if (matches(*argv, "from") == 0) { 1296 inet_prefix addr; 1297 NEXT_ARG(); 1298 if (matches(*argv, "help") == 0) 1299 usage(); 1300 from_ok = 1; 1301 get_prefix(&addr, *argv, req.r.rtm_family); 1302 if (req.r.rtm_family == AF_UNSPEC) 1303 req.r.rtm_family = addr.family; 1304 if (addr.bytelen) 1305 addattr_l(&req.n, sizeof(req), RTA_SRC, &addr.data, addr.bytelen); 1306 req.r.rtm_src_len = addr.bitlen; 1307 } else if (matches(*argv, "iif") == 0) { 1308 NEXT_ARG(); 1309 idev = *argv; 1310 } else if (matches(*argv, "oif") == 0 || 1311 strcmp(*argv, "dev") == 0) { 1312 NEXT_ARG(); 1313 odev = *argv; 1314 } else if (matches(*argv, "notify") == 0) { 1315 req.r.rtm_flags |= RTM_F_NOTIFY; 1316 } else if (matches(*argv, "connected") == 0) { 1317 connected = 1; 1318 } else { 1319 inet_prefix addr; 1320 if (strcmp(*argv, "to") == 0) { 1321 NEXT_ARG(); 1322 } 1323 if (matches(*argv, "help") == 0) 1324 usage(); 1325 get_prefix(&addr, *argv, req.r.rtm_family); 1326 if (req.r.rtm_family == AF_UNSPEC) 1327 req.r.rtm_family = addr.family; 1328 if (addr.bytelen) 1329 addattr_l(&req.n, sizeof(req), RTA_DST, &addr.data, addr.bytelen); 1330 req.r.rtm_dst_len = addr.bitlen; 1331 } 1332 argc--; argv++; 1333 } 1334 1335 if (req.r.rtm_dst_len == 0) { 1336 fprintf(stderr, "need at least destination address\n"); 1337 exit(1); 1338 } 1339 1340 ll_init_map(&rth); 1341 1342 if (idev || odev) { 1343 int idx; 1344 1345 if (idev) { 1346 if ((idx = ll_name_to_index(idev)) == 0) { 1347 fprintf(stderr, "Cannot find device \"%s\"\n", idev); 1348 return -1; 1349 } 1350 addattr32(&req.n, sizeof(req), RTA_IIF, idx); 1351 } 1352 if (odev) { 1353 if ((idx = ll_name_to_index(odev)) == 0) { 1354 fprintf(stderr, "Cannot find device \"%s\"\n", odev); 1355 return -1; 1356 } 1357 addattr32(&req.n, sizeof(req), RTA_OIF, idx); 1358 } 1359 } 1360 1361 if (req.r.rtm_family == AF_UNSPEC) 1362 req.r.rtm_family = AF_INET; 1363 1364 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) 1365 exit(2); 1366 1367 if (connected && !from_ok) { 1368 struct rtmsg *r = NLMSG_DATA(&req.n); 1369 int len = req.n.nlmsg_len; 1370 struct rtattr * tb[RTA_MAX+1]; 1371 1372 if (print_route(NULL, &req.n, (void*)stdout) < 0) { 1373 fprintf(stderr, "An error :-)\n"); 1374 exit(1); 1375 } 1376 1377 if (req.n.nlmsg_type != RTM_NEWROUTE) { 1378 fprintf(stderr, "Not a route?\n"); 1379 return -1; 1380 } 1381 len -= NLMSG_LENGTH(sizeof(*r)); 1382 if (len < 0) { 1383 fprintf(stderr, "Wrong len %d\n", len); 1384 return -1; 1385 } 1386 1387 parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); 1388 1389 if (tb[RTA_PREFSRC]) { 1390 tb[RTA_PREFSRC]->rta_type = RTA_SRC; 1391 r->rtm_src_len = 8*RTA_PAYLOAD(tb[RTA_PREFSRC]); 1392 } else if (!tb[RTA_SRC]) { 1393 fprintf(stderr, "Failed to connect the route\n"); 1394 return -1; 1395 } 1396 if (!odev && tb[RTA_OIF]) 1397 tb[RTA_OIF]->rta_type = 0; 1398 if (tb[RTA_GATEWAY]) 1399 tb[RTA_GATEWAY]->rta_type = 0; 1400 if (!idev && tb[RTA_IIF]) 1401 tb[RTA_IIF]->rta_type = 0; 1402 req.n.nlmsg_flags = NLM_F_REQUEST; 1403 req.n.nlmsg_type = RTM_GETROUTE; 1404 1405 if (rtnl_talk(&rth, &req.n, 0, 0, &req.n, NULL, NULL) < 0) 1406 exit(2); 1407 } 1408 1409 if (print_route(NULL, &req.n, (void*)stdout) < 0) { 1410 fprintf(stderr, "An error :-)\n"); 1411 exit(1); 1412 } 1413 1414 exit(0); 1415} 1416 1417void iproute_reset_filter() 1418{ 1419 memset(&filter, 0, sizeof(filter)); 1420 filter.mdst.bitlen = -1; 1421 filter.msrc.bitlen = -1; 1422} 1423 1424int do_iproute(int argc, char **argv) 1425{ 1426 if (argc < 1) 1427 return iproute_list_or_flush(0, NULL, 0); 1428 1429 if (matches(*argv, "add") == 0) 1430 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_EXCL, 1431 argc-1, argv+1); 1432 if (matches(*argv, "change") == 0 || strcmp(*argv, "chg") == 0) 1433 return iproute_modify(RTM_NEWROUTE, NLM_F_REPLACE, 1434 argc-1, argv+1); 1435 if (matches(*argv, "replace") == 0) 1436 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_REPLACE, 1437 argc-1, argv+1); 1438 if (matches(*argv, "prepend") == 0) 1439 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE, 1440 argc-1, argv+1); 1441 if (matches(*argv, "append") == 0) 1442 return iproute_modify(RTM_NEWROUTE, NLM_F_CREATE|NLM_F_APPEND, 1443 argc-1, argv+1); 1444 if (matches(*argv, "test") == 0) 1445 return iproute_modify(RTM_NEWROUTE, NLM_F_EXCL, 1446 argc-1, argv+1); 1447 if (matches(*argv, "delete") == 0) 1448 return iproute_modify(RTM_DELROUTE, 0, 1449 argc-1, argv+1); 1450 if (matches(*argv, "list") == 0 || matches(*argv, "show") == 0 1451 || matches(*argv, "lst") == 0) 1452 return iproute_list_or_flush(argc-1, argv+1, 0); 1453 if (matches(*argv, "get") == 0) 1454 return iproute_get(argc-1, argv+1); 1455 if (matches(*argv, "flush") == 0) 1456 return iproute_list_or_flush(argc-1, argv+1, 1); 1457 if (matches(*argv, "help") == 0) 1458 usage(); 1459 fprintf(stderr, "Command \"%s\" is unknown, try \"ip route help\".\n", *argv); 1460 exit(-1); 1461} 1462 1463