1 /* ip.c - Show / manipulate routing, devices, policy routing and tunnels. 2 * 3 * Copyright 2014 Sameer Prakash Pradhan <sameer.p.pradhan@gmail.com> 4 * Copyright 2014 Ranjan Kumar <ranjankumar.bth@gmail.com> 5 * Copyright 2014 Rajni Kant <rajnikant12345@gmail.com> 6 * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com> 7 * 8 * No Standard. 9 * 10 USE_IP(NEWTOY(ip, NULL, TOYFLAG_SBIN)) 11 USE_IP(OLDTOY(ipaddr, ip, TOYFLAG_SBIN)) 12 USE_IP(OLDTOY(iplink, ip, TOYFLAG_SBIN)) 13 USE_IP(OLDTOY(iproute, ip, TOYFLAG_SBIN)) 14 USE_IP(OLDTOY(iprule, ip, TOYFLAG_SBIN)) 15 USE_IP(OLDTOY(iptunnel, ip, TOYFLAG_SBIN)) 16 17 config IP 18 bool "ip" 19 default n 20 help 21 usage: ip [ OPTIONS ] OBJECT { COMMAND } 22 23 Show / manipulate routing, devices, policy routing and tunnels. 24 25 where OBJECT := {address | link | route | rule | tunnel} 26 OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] } 27 */ 28 #define FOR_ip 29 #include "toys.h" 30 #include <linux/netlink.h> 31 #include <linux/rtnetlink.h> 32 #include <linux/if_ether.h> 33 #include <linux/if_addr.h> 34 #include <net/if_arp.h> 35 #include <ifaddrs.h> 36 #include <fnmatch.h> 37 #include <linux/if_tunnel.h> 38 39 #ifndef IP_DF 40 #define IP_DF 0x4000 /* don't fragment flag. */ 41 #endif 42 43 GLOBALS( 44 char stats, singleline, flush, *filter_dev, gbuf[8192]; 45 int sockfd, connected, from_ok, route_cmd; 46 int8_t addressfamily, is_addr; 47 ) 48 49 struct arglist { 50 char *name; 51 int idx; 52 }; 53 54 static struct 55 { 56 int ifindex, scope, scopemask, up, to; 57 char *label, *addr; 58 } addrinfo; 59 60 struct linkdata { 61 struct linkdata *next, *prev; 62 int flags, iface_idx, mtu, txqueuelen, parent,iface_type; 63 char qdiscpline[IFNAMSIZ+1], state[IFNAMSIZ+1], type[IFNAMSIZ+1], 64 iface[IFNAMSIZ+1], laddr[64], bcast[64]; 65 struct rtnl_link_stats rt_stat; 66 }*linfo; 67 68 typedef int (*cmdobj)(char **argv); 69 70 #define MESG_LEN 8192 71 72 // For "/etc/iproute2/RPDB_tables" 73 enum { 74 RPDB_rtdsfield = 1, 75 RPDB_rtprotos = 2, 76 RPDB_rtrealms = 3, 77 RPDB_rtscopes = 4, 78 RPDB_rttables = 5 79 }; 80 81 #define RPDB_ENTRIES 256 82 static int8_t rttable_init; 83 static int8_t rtprotos_init; 84 static int8_t rtdsfield_init; 85 static int8_t rtscope_init; 86 static int8_t rtrealms_init; 87 88 static struct arglist *rt_dsfield[RPDB_ENTRIES]; 89 static struct arglist *rt_protos[RPDB_ENTRIES]; 90 static struct arglist *rt_tables[RPDB_ENTRIES]; 91 static struct arglist *rt_realms[RPDB_ENTRIES]; 92 static struct arglist *rt_scope[RPDB_ENTRIES]; 93 94 static struct arglist rtmtypes[] = { {"none", RTN_UNSPEC}, 95 {"unicast", RTN_UNICAST}, {"local", RTN_LOCAL}, 96 {"broadcast", RTN_BROADCAST}, {"anycast", RTN_ANYCAST}, 97 {"multicast", RTN_MULTICAST}, {"blackhole", RTN_BLACKHOLE}, 98 {"unreachable", RTN_UNREACHABLE}, {"prohibit", RTN_PROHIBIT}, 99 {"throw", RTN_THROW}, {"nat", RTN_NAT}, 100 {"xresolve", RTN_XRESOLVE}, {NULL, -1} 101 }; 102 103 static int filter_nlmesg(int (*fun)(struct nlmsghdr *mhdr, char **), char **); 104 static int ipaddr_print(struct linkdata *, int flg); 105 106 // extended route attribute metrics. 107 static const char *mx_names[RTAX_MAX + 1] = { 108 [RTAX_MTU] = "mtu", 109 [RTAX_WINDOW] = "window", 110 [RTAX_RTT] = "rtt", 111 [RTAX_RTTVAR] = "rttvar", 112 [RTAX_SSTHRESH] = "ssthresh", 113 [RTAX_CWND] = "cwnd", 114 [RTAX_ADVMSS] = "advmss", 115 [RTAX_REORDERING] = "reordering", 116 [RTAX_HOPLIMIT] = "hoplimit", 117 [RTAX_INITCWND] = "initcwnd", 118 [RTAX_FEATURES] = "features", 119 [RTAX_RTO_MIN] = "rto_min", 120 [RTAX_INITRWND] = "initrwnd", 121 [RTAX_QUICKACK] = "quickack", 122 [RTAX_CC_ALGO] = "congctl"}; 123 124 // =========================================================================== 125 // Common Code for IP Options (like: addr, link, route etc.) 126 // =========================================================================== 127 static int substring_to_idx(char *str, struct arglist *list) 128 { 129 struct arglist *alist; 130 int len; 131 132 if (!str) return -1; 133 len = strlen(str); 134 135 for (alist = list; alist->name; alist++) 136 if (!memcmp(str, alist->name, len)) return alist->idx; 137 return -1; 138 } 139 140 static int string_to_idx(char *str, struct arglist *list) 141 { 142 struct arglist *alist; 143 144 if (!str) return -1; 145 for (alist = list; alist->name; alist++) 146 if (!strcmp(str, alist->name)) return alist->idx; 147 return -1; 148 } 149 150 static char *idx_to_string(int idx, struct arglist *list) 151 { 152 struct arglist *alist; 153 154 if (idx < 0) return NULL; 155 for (alist = list; alist->name; alist++) 156 if (idx == alist->idx) return alist->name; 157 return NULL; 158 } 159 160 static void send_nlmesg(int type, int flags, int family, 161 void *buf, int blen) 162 { 163 struct { 164 struct nlmsghdr nlh; 165 struct rtgenmsg g; 166 } req; 167 168 if (!buf) { 169 memset(&req, 0, sizeof(req)); 170 req.nlh.nlmsg_len = sizeof(req); 171 req.nlh.nlmsg_type = type; 172 req.nlh.nlmsg_flags = flags; 173 req.g.rtgen_family = family; 174 buf = &req; 175 blen = sizeof(req); 176 } 177 if (send(TT.sockfd , (void*)buf, blen, 0) < 0) 178 perror_exit("Unable to send data on socket."); 179 } 180 181 // Parse /etc/iproute2/RPDB_tables and prepare list. 182 static void parseRPDB(char *fname, struct arglist **list, int32_t size) 183 { 184 FILE *fp = fopen(fname, "r"); 185 char *line = 0; 186 size_t l = 0; 187 ssize_t len; 188 189 if (!fp) return; 190 while ((len = getline(&line, &l, fp)) > 0) { 191 char *ptr = line; 192 int32_t idx; 193 194 while (*ptr == ' ' || *ptr == '\t') ptr++; 195 if (*ptr == 0 || *ptr == '#' || *ptr == '\n') continue; 196 if ((sscanf(ptr, "0x%x %s\n", &idx, toybuf) != 2) && 197 (sscanf(ptr, "0x%x %s #", &idx, toybuf) != 2) && 198 (sscanf(ptr, "%d %s\n", &idx, toybuf) != 2) && 199 (sscanf(ptr, "%d %s #", &idx, toybuf) != 2)) { 200 error_msg("corrupt %s", fname); 201 break; 202 } 203 if (idx >= 0 && idx < size) { 204 int index = idx & (size-1); 205 if (list[index]) free(list[index]->name); 206 else list[index] = xzalloc(sizeof(struct arglist)); 207 list[index]->idx = idx; 208 list[index]->name = xstrdup(toybuf); 209 } 210 } 211 free(line); 212 fclose(fp); 213 } 214 215 static void free_alist(struct arglist **list) 216 { 217 int i; 218 for (i = 0;i<RPDB_ENTRIES;i++) { 219 if (list[i]) { 220 free(list[i]->name); 221 free(list[i]); 222 } 223 } 224 } 225 226 static void init_arglist(struct arglist **list,int value, char* name) 227 { 228 if (!list[value]) list[value] = xzalloc(sizeof(struct arglist)); 229 list[value]->idx = value; 230 list[value]->name = xstrdup(name); 231 } 232 233 static struct arglist **getlist(u_int8_t whichDB) 234 { 235 struct arglist **alist; 236 237 switch (whichDB) { 238 case RPDB_rtdsfield: 239 alist = rt_dsfield; 240 if (!rtdsfield_init) { 241 rtdsfield_init = 1; 242 parseRPDB("/etc/iproute2/rt_dsfield", alist, ARRAY_LEN(rt_dsfield)); 243 } 244 break; 245 case RPDB_rtprotos: 246 alist = rt_protos; 247 if (!rttable_init) { 248 rtprotos_init = 1; 249 init_arglist(rt_protos,0,"none"); 250 init_arglist(rt_protos,1,"redirect"); 251 init_arglist(rt_protos,2,"kernel"); 252 init_arglist(rt_protos,3,"boot"); 253 init_arglist(rt_protos,4,"static"); 254 init_arglist(rt_protos,8,"gated"); 255 init_arglist(rt_protos,9,"ra"); 256 init_arglist(rt_protos,10,"mrt"); 257 init_arglist(rt_protos,11,"zebra"); 258 init_arglist(rt_protos,12,"bird"); 259 parseRPDB("/etc/iproute2/rt_protos", alist, ARRAY_LEN(rt_protos)); 260 } 261 break; 262 case RPDB_rtrealms: 263 alist = rt_realms; 264 if (!rtrealms_init) { 265 rtrealms_init = 1; 266 init_arglist(rt_realms,0,"unspec"); 267 parseRPDB("/etc/iproute2/rt_realms", alist, ARRAY_LEN(rt_realms)); 268 } 269 break; 270 case RPDB_rtscopes: 271 alist = rt_scope; 272 if (!rtscope_init) { 273 rtscope_init = 1; 274 init_arglist(rt_scope,0,"global"); 275 init_arglist(rt_scope,200,"site"); 276 init_arglist(rt_scope,253,"link"); 277 init_arglist(rt_scope,254,"host"); 278 init_arglist(rt_scope,255,"nowhere"); 279 parseRPDB("/etc/iproute2/rt_scopes", alist, ARRAY_LEN(rt_scope)); 280 } 281 break; 282 case RPDB_rttables: 283 alist = rt_tables; 284 if (!rttable_init) { 285 rttable_init = 1; 286 init_arglist(rt_tables,RT_TABLE_DEFAULT,"default"); 287 init_arglist(rt_tables,RT_TABLE_MAIN,"main"); 288 init_arglist(rt_tables,RT_TABLE_LOCAL,"local"); 289 parseRPDB("/etc/iproute2/rt_tables", alist, ARRAY_LEN(rt_tables)); 290 } 291 break; 292 default: 293 error_exit("wrong database"); 294 break; // Unreachable code. 295 } 296 return alist; 297 } 298 299 /* 300 * Parse RPBD tables (if not parsed already). 301 * return RPDB table name as per idx. 302 */ 303 static char *namefromRPDB(int idx, u_int8_t whichDB) 304 { 305 struct arglist **alist; 306 307 if (idx < 0 || idx >= RPDB_ENTRIES) { 308 snprintf(toybuf, RPDB_ENTRIES, "%u", idx); 309 return toybuf; 310 } 311 312 alist = getlist(whichDB); 313 314 if (alist[idx] && alist[idx]->name) return alist[idx]->name; 315 316 if (whichDB == RPDB_rtdsfield) snprintf(toybuf, RPDB_ENTRIES, "0x%02x", idx); 317 else snprintf(toybuf, RPDB_ENTRIES, "%u", idx); 318 319 return toybuf; 320 } 321 322 static int idxfromRPDB(char *name, u_int8_t whichDB) 323 { 324 struct arglist **alist; 325 long i = 0; 326 char *ptr = NULL; 327 328 for (alist = getlist(whichDB); i < RPDB_ENTRIES; i++) { 329 if (!alist[i] || !alist[i]->name) continue; 330 if (!strcmp(alist[i]->name, name)) return i; 331 } 332 i = strtol(name, &ptr, 0); 333 if (errno || (ptr && *ptr) || i < 0 || i > 255) 334 return -1; 335 return i; 336 } 337 338 static char *rtmtype_idx2str(u_int8_t idx) 339 { 340 char *name = idx_to_string(idx, rtmtypes); 341 342 if (!name) snprintf(toybuf, RPDB_ENTRIES, "%u", idx); 343 else snprintf(toybuf, sizeof(toybuf), "%s", name); 344 return toybuf; 345 } 346 347 static int rtmtype_str2idx(char *name) 348 { 349 int idx = string_to_idx(name, rtmtypes); 350 351 if (idx < 0) return atolx_range(name, 0, 255); 352 return idx; 353 } 354 355 /* 356 * Used to get the prefix value in binary form. 357 * For IPv4: non-standard parsing used; as 10.10 will be treated as 10.10.0.0 358 * unlike inet_aton which is 10.0.0.10 359 */ 360 static int get_prefix(uint32_t *addr, uint8_t *af, char *name, int family) 361 { 362 if (family == AF_PACKET) error_exit("'%s' may be inet prefix", name); 363 if (!memcmp(name, "default", strlen(name)) 364 || !memcmp(name, "all", strlen(name)) 365 || !memcmp(name, "any", strlen(name))) { 366 *af = family; 367 return 0; 368 } 369 if (strchr(name, ':')) { 370 *af = AF_INET6; 371 if (family != AF_UNSPEC && family != AF_INET6) return 1; 372 if (inet_pton(AF_INET6, name, (void *)addr) != 1) 373 return 1; 374 } else { // for IPv4. 375 char *ptr = name; 376 uint8_t count = 0; 377 378 *af = AF_INET; 379 if (family != AF_UNSPEC && family != AF_INET) return 1; 380 while (*ptr) { 381 int val, len = 0; 382 383 if (*ptr == '.') ptr++; 384 sscanf(ptr, "%d%n", &val, &len); 385 if (!len || len > 3 || val < 0 || val > 255 || count > 3) return 1; 386 ptr += len; 387 ((uint8_t*)addr)[count++] = val; 388 } 389 } 390 return 0; 391 } 392 393 /* 394 * Used to calculate netmask, which can be in the form of 395 * either 255.255.255.0 or 24 or default or any or all strings. 396 */ 397 static int get_nmask_prefix(uint32_t *netmask, uint8_t af, 398 char *name, uint8_t family) 399 { 400 char *ptr; 401 uint32_t naddr[4] = {0,}; 402 uint64_t plen; 403 uint8_t naf = AF_UNSPEC; 404 405 *netmask = (af == AF_INET6) ? 128 : 32; // set default netmask 406 plen = strtoul(name, &ptr, 0); 407 408 if (!ptr || ptr == name || *ptr || !plen || plen > *netmask) { 409 if (get_prefix(naddr, &naf, name, family)) return -1; 410 if (naf == AF_INET) { 411 uint32_t mask = htonl(*naddr), host = ~mask; 412 if (host & (host + 1)) return -1; 413 for (plen = 0; mask; mask <<= 1) ++plen; 414 if (plen > 32) return -1; 415 } 416 } 417 *netmask = plen; 418 return 0; 419 } 420 421 /* 422 * Parse prefix, which will be in form of 423 * either default or default/default or default/24 or default/255.255.255.0 424 * or 10.20.30.40 or 10.20.30.40/default or 10.20.30.40/24 425 * or 10.20.30.40/255.255.255.0 426 */ 427 static void parse_prefix(uint32_t *addr, uint32_t *netmask, uint8_t *len, 428 char *name, int family) 429 { 430 uint8_t af = AF_UNSPEC; 431 char *slash = strchr(name, '/'); 432 433 if (slash) *slash = 0; 434 if (get_prefix(addr, &af, name, family)) error_exit("Invalid prefix"); 435 436 if (slash) { // grab netmask. 437 if (get_nmask_prefix(netmask, af, slash+1, family)) 438 error_exit("Invalid prefix"); 439 *slash ='/'; 440 } 441 else if (af == AF_INET && *addr) *netmask = 32; 442 else if (af == AF_INET6 && (*addr || *(addr+3))) *netmask = 128; 443 444 if (!*addr && !slash && !af) *len = 0; 445 else *len = (af == AF_INET6) ? 16 : 4; 446 } 447 448 /* 449 * Add a route attribute to a buffer; this is primarily used for extended 450 * attributes which get collected in a separate buffer from the normal route 451 * attributes and later get added to the main rtm message. 452 */ 453 static void add_varlen_rtattr_to_buffer(struct rtattr *rta, int maxlen, 454 int type, void *data, int alen) { 455 struct rtattr *subrta; 456 int len = RTA_LENGTH(alen); 457 if (RTA_ALIGN(rta->rta_len) + RTA_ALIGN(len) > maxlen) { 458 error_exit("RTA exceeds max length %d", maxlen); 459 } 460 subrta = (struct rtattr*)(((char*)rta) + RTA_ALIGN(rta->rta_len)); 461 subrta->rta_type = type; 462 subrta->rta_len = len; 463 if (alen) { 464 memcpy(RTA_DATA(subrta), data, alen); 465 } 466 rta->rta_len = NLMSG_ALIGN(rta->rta_len) + RTA_ALIGN(len); 467 } 468 469 static void add_uint32_rtattr_to_buffer(struct rtattr *rta, int maxlen, 470 int type, uint32_t attr) { 471 add_varlen_rtattr_to_buffer(rta, maxlen, type, (char*)&attr, sizeof(attr)); 472 } 473 474 /* 475 * Add a route attribute to a RTM message. 476 */ 477 static void add_string_to_rtattr(struct nlmsghdr *n, int maxlen, 478 int type, void *data, int alen) 479 { 480 int len = RTA_LENGTH(alen); 481 struct rtattr *rta; 482 483 if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) return; 484 rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); 485 rta->rta_type = type; 486 rta->rta_len = len; 487 memcpy(RTA_DATA(rta), data, alen); 488 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + len; 489 } 490 491 492 493 // =========================================================================== 494 // Code for ip link. 495 // =========================================================================== 496 #ifndef NLMSG_TAIL 497 #define NLMSG_TAIL(nmsg) \ 498 ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) 499 #endif 500 501 static uint32_t get_ifaceindex(char *name, int ext) 502 { 503 struct if_nameindex *if_ni, *i; 504 int index = -1; 505 506 if_ni = if_nameindex(); 507 if (!if_ni) perror_exit("if_nameindex"); 508 509 for (i = if_ni; i->if_index && i->if_name; i++) 510 if (!strcmp(name, i->if_name)) { 511 index = i->if_index; 512 break; 513 } 514 if_freenameindex(if_ni); 515 if (index == -1 && ext) perror_exit("can't find device '%s'", name); 516 return index; 517 } 518 519 static void fill_hwaddr(char *arg, int len, unsigned char *address) 520 { 521 int count = 0, val, length; 522 523 while (count < len) { 524 val = length = 0; 525 if (!arg) error_exit("bad hw-addr '%s'", ""); 526 if (*arg == ':') arg++, count++; 527 sscanf(arg, "%2x%n", &val, &length); 528 if (!length || length > 2) 529 error_exit("bad hw-addr '%s'", arg); 530 arg += length; 531 count += length; 532 *address++ = val; 533 } 534 } 535 536 // Multimach = 1, single match = 0 537 static char *get_flag_string(struct arglist *aflags, int flags, int ismulti) 538 { 539 struct arglist *p = aflags; 540 char *out = NULL, *tmp = NULL; 541 542 for (; p->name; p++) { 543 int test = (ismulti ? p->idx & flags : 0) || p->idx == flags; 544 if (test) { // flags can be zero 545 tmp = out ? xmprintf("%s,%s", out, p->name) : xmprintf("%s", p->name); 546 if (out) free(out); 547 out = tmp; 548 } 549 } 550 return out; 551 } 552 553 static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) 554 { 555 struct arglist vlan_optlist[] = {{"id", 0}, {"protocol", 1}, 556 {"reorder_hdr", 2}, {"gvrp", 3}, {NULL,-1}}; 557 struct arglist vlan_protolist[] = {{"802.1q", 0}, {"802.1ad", 1}, {NULL,-1}}; 558 struct arglist on_off[] = { {"on", 0}, {"off", 1}, {NULL,-1}}; 559 int idx; 560 struct ifla_vlan_flags flags; 561 562 memset(&flags, 0, sizeof(flags)); 563 for (; *argv; argv++) { 564 int param, proto; 565 566 if ((idx = substring_to_idx(*argv++, vlan_optlist)) == -1) help_exit(0); 567 switch (idx) { 568 case 0: // ARG_id 569 if (!*argv) help_exit(0); 570 param = atolx(*argv); 571 add_string_to_rtattr(n, size, IFLA_VLAN_ID, ¶m, sizeof(param)); 572 break; 573 case 1: // ARG_protocol 574 if (!*argv) error_exit("Invalid vlan id."); 575 if ((idx = substring_to_idx(*argv, vlan_protolist)) == -1) help_exit(0); 576 if (!idx) proto = ETH_P_8021Q; // PROTO_8021Q - 0 577 else if (idx == 1) proto = 0x88A8; // ETH Protocol - 8021AD 578 // IFLA VLAN PROTOCOL - 5 579 add_string_to_rtattr(n, size, 5, &proto, sizeof(proto)); 580 break; 581 case 2: // ARG_reorder_hdr 582 case 3: // ARG_gvrp 583 if ((param = substring_to_idx(*argv, on_off)) == -1) help_exit(0); 584 585 flags.mask |= (idx -1); // VLAN FLAG REORDER Header 586 flags.flags &= ~(idx -1); // VLAN FLAG REORDER Header 587 if (!param) flags.flags |= (idx -1); // VLAN FLAG REORDER Header 588 break; 589 } 590 } 591 if (flags.mask) 592 add_string_to_rtattr(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags)); 593 } 594 595 static int linkupdate(char **argv) 596 { 597 struct { 598 struct nlmsghdr mhdr; 599 struct ifinfomsg info; 600 char buf[1024]; 601 } request; 602 char *name, *dev, *type, *link, *addr; 603 struct rtattr *attr = NULL; 604 int len = 0, add = (*argv[-1] == 'a') ? 1 : 0; 605 606 name = dev = type = link = addr = NULL; 607 for (; *argv; argv++) { 608 struct arglist objectlist[] = { {"type", 0}, {"name", 1}, {"link", 2}, 609 {"address", 3}, {NULL,-1}}; 610 uint8_t idx = substring_to_idx(*argv, objectlist); 611 612 if (!idx) { 613 type = *++argv; 614 break; 615 } 616 else if (idx == 1) dev = name = *++argv; 617 else if (idx == 2) link = *++argv; 618 else if (idx == 3) addr = *++argv; 619 else if (!dev) name = dev = *argv; 620 } 621 622 if (!name && !add) 623 error_exit("Not enough information: \"dev\" argument is required.\n"); 624 else if (!type && add) 625 error_exit("Not enough information: \"type\" argument is required.\n"); 626 627 memset(&request, 0, sizeof(request)); 628 request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 629 request.mhdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; 630 if (add) { 631 request.mhdr.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; 632 request.mhdr.nlmsg_type = RTM_NEWLINK; 633 } else { 634 request.mhdr.nlmsg_type = RTM_DELLINK; 635 request.info.ifi_index = get_ifaceindex(name, 1); 636 } 637 request.info.ifi_family = AF_UNSPEC; 638 attr = NLMSG_TAIL(&request.mhdr); 639 if (type) { 640 add_string_to_rtattr(&request.mhdr, sizeof(request), 641 IFLA_LINKINFO, NULL, 0); 642 add_string_to_rtattr(&request.mhdr, sizeof(request), 643 IFLA_INFO_KIND, type, strlen(type)); 644 if (!strcmp(type, "vlan")) { 645 struct rtattr *data = NLMSG_TAIL(&request.mhdr); 646 add_string_to_rtattr(&request.mhdr, sizeof(request), 647 IFLA_INFO_DATA, NULL, 0); 648 vlan_parse_opt(++argv, &request.mhdr, sizeof(request)); 649 data->rta_len = (void *)NLMSG_TAIL(&request.mhdr) - (void *)data; 650 } 651 attr->rta_len = (void *)NLMSG_TAIL(&request.mhdr) - (void *)attr; 652 } 653 654 if (link) { 655 uint32_t idx = get_ifaceindex(link, 1); 656 add_string_to_rtattr(&request.mhdr, sizeof(request), 657 IFLA_LINK, &idx, sizeof(uint32_t)); 658 } 659 if (addr) { 660 char abuf[IF_NAMESIZE] = {0,}; 661 662 fill_hwaddr(addr, IF_NAMESIZE, (unsigned char *)abuf); 663 add_string_to_rtattr(&request.mhdr, sizeof(request), 664 IFLA_ADDRESS, abuf, strlen(abuf)); 665 } 666 if (!name) { 667 snprintf(toybuf, IFNAMSIZ, "%s%d", type, 0); 668 for (len = 1; ; len++) { 669 if (!get_ifaceindex(toybuf, 0)) break; 670 snprintf(toybuf, IFNAMSIZ, "%s%d", type, len); 671 } 672 name = toybuf; 673 } 674 len = strlen(name) + 1; 675 if (len < 2 || len > IFNAMSIZ) error_exit("Invalid device name."); 676 add_string_to_rtattr(&request.mhdr, sizeof(request), IFLA_IFNAME, name, len); 677 678 send_nlmesg(0, 0, 0, (void *)&request, request.mhdr.nlmsg_len); 679 return (filter_nlmesg(NULL,NULL)); 680 } 681 682 static int link_set(char **argv) 683 { 684 struct arglist cmd_objectlist[] = {{"up", 0}, {"down", 1}, {"arp", 2}, 685 {"multicast", 3}, {"dynamic", 4}, {"name", 5}, {"txqueuelen", 6}, 686 {"mtu", 7},{"address", 8}, {"broadcast", 9}, {NULL,-1}}; 687 int case_flags[] = {IFF_NOARP,IFF_MULTICAST,IFF_DYNAMIC}; 688 struct ifreq req; 689 int idx, flags = 0, masks = 0xffff, fd; 690 691 memset(&req, 0, sizeof(req)); 692 if (!*argv) error_exit("\"dev\" missing"); 693 xstrncpy(req.ifr_name, *argv, IF_NAMESIZE); 694 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 695 xioctl(fd, SIOCGIFINDEX, &req); 696 for (++argv; *argv;) { 697 if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1) help_exit(0); 698 switch(idx) { 699 case 0: 700 flags |= IFF_UP; break; 701 case 1: 702 masks &= ~IFF_UP; break; 703 case 2: 704 case 3: 705 case 4: 706 if (!*argv) help_exit(0); 707 else if (!strcmp(*argv, "on")) { 708 if (idx == 2) { 709 masks &= ~case_flags[idx-2]; 710 flags &= ~case_flags[idx-2]; 711 } else flags |= case_flags[idx-2]; 712 } else if (!strcmp(*argv,"off")) { 713 if (idx == 2) { 714 masks |= case_flags[idx-2]; 715 flags |= case_flags[idx-2]; 716 } else masks &= ~case_flags[idx-2]; 717 } else help_exit(0); 718 ++argv; 719 break; 720 case 5: 721 xstrncpy(req.ifr_ifru.ifru_newname, *argv, IF_NAMESIZE); 722 xioctl(fd, SIOCSIFNAME, &req); 723 xstrncpy(req.ifr_name, *argv++, IF_NAMESIZE); 724 xioctl(fd, SIOCGIFINDEX, &req); 725 break; 726 case 6: 727 req.ifr_ifru.ifru_ivalue = atolx(*argv++); 728 xioctl(fd, SIOCSIFTXQLEN, &req); 729 break; 730 case 7: 731 req.ifr_ifru.ifru_mtu = atolx(*argv++); 732 xioctl(fd, SIOCSIFMTU, &req); 733 break; 734 case 8: 735 xioctl(fd, SIOCGIFHWADDR, &req); 736 fill_hwaddr(*argv++, IF_NAMESIZE, 737 (unsigned char *)(req.ifr_hwaddr.sa_data)); 738 xioctl(fd, SIOCSIFHWADDR, &req); 739 break; 740 case 9: 741 xioctl(fd, SIOCGIFHWADDR, &req); 742 fill_hwaddr(*argv++, IF_NAMESIZE, 743 (unsigned char *)(req.ifr_hwaddr.sa_data)); 744 xioctl(fd, SIOCSIFHWBROADCAST, &req); 745 break; 746 } 747 } 748 xioctl(fd, SIOCGIFFLAGS, &req); 749 req.ifr_ifru.ifru_flags |= flags; 750 req.ifr_ifru.ifru_flags &= masks; 751 xioctl(fd, SIOCSIFFLAGS, &req); 752 xclose(fd); 753 return 0; 754 } 755 756 static void print_stats(struct rtnl_link_stats *rtstat) 757 { 758 char *line_feed = (!TT.singleline ? "\n " : " "); 759 760 if (TT.stats > 0) { 761 xprintf(" RX: bytes packets errors " 762 "dropped overrun mcast%s%-10u %-8u %-7u %-8u %-8u %-8u\n", 763 line_feed, rtstat->rx_bytes, rtstat->rx_packets, rtstat->rx_errors, 764 rtstat->rx_dropped, rtstat->rx_over_errors, rtstat->multicast); 765 if (TT.stats > 1) { 766 xprintf(" RX: errors length crc " 767 "frame fifo missed%s%-10u %-8u %-7u %-8u %-8u %-8u\n", 768 line_feed, rtstat->rx_errors, rtstat->rx_length_errors, 769 rtstat->rx_crc_errors, rtstat->rx_frame_errors, 770 rtstat->rx_fifo_errors, rtstat->rx_missed_errors); 771 } 772 xprintf(" TX: bytes packets errors " 773 "dropped carrier collsns%s%-10u %-8u %-7u %-8u %-8u %-8u\n", 774 line_feed, rtstat->tx_bytes, rtstat->tx_packets, rtstat->tx_errors, 775 rtstat->tx_dropped, rtstat->tx_carrier_errors, rtstat->collisions); 776 if (TT.stats > 1) { 777 xprintf(" TX: errors aborted fifo window " 778 "heartbeat%s%-10u %-8u %-7u %-8u %-8u\n", 779 line_feed, rtstat->tx_errors, rtstat->tx_aborted_errors, 780 rtstat->tx_fifo_errors, rtstat->tx_window_errors, 781 rtstat->tx_heartbeat_errors); 782 } 783 } 784 } 785 786 static int print_link_output(struct linkdata *link) 787 { 788 char *line_feed = " ", *flags,*peer = "brd"; 789 struct arglist iface_flags[] = {{"",0},{"UP", IFF_UP}, 790 {"BROADCAST", IFF_BROADCAST}, {"DEBUG", IFF_DEBUG}, 791 {"LOOPBACK", IFF_LOOPBACK}, {"POINTOPOINT", IFF_POINTOPOINT}, 792 {"NOTRAILERS", IFF_NOTRAILERS}, {"RUNNING", IFF_RUNNING}, 793 {"NOARP", IFF_NOARP}, {"PROMISC",IFF_PROMISC}, 794 {"ALLMULTI", IFF_ALLMULTI}, {"MASTER", IFF_MASTER}, {"SLAVE", IFF_SLAVE}, 795 {"MULTICAST", IFF_MULTICAST}, {"PORTSEL", IFF_PORTSEL}, 796 {"AUTOMEDIA", IFF_AUTOMEDIA}, {"DYNAMIC", IFF_DYNAMIC}, {NULL,-1}}; 797 798 if (link->parent != -1) { 799 int fd = 0; 800 struct ifreq req; 801 802 memset(&req, 0, sizeof(req)); 803 if_indextoname( link->parent,req.ifr_ifrn.ifrn_name); 804 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 805 if (ioctl(fd, SIOCGIFTXQLEN, &req)) perror(""); 806 else link->txqueuelen = req.ifr_ifru.ifru_ivalue; 807 xclose(fd); 808 } 809 810 if (TT.is_addr && addrinfo.label && fnmatch(addrinfo.label, link->iface, 0)) 811 return 0; 812 813 814 if (!(flags = get_flag_string(iface_flags, link->flags, 1))) 815 error_exit("Invalid data."); 816 if (!TT.singleline) line_feed="\n "; 817 if (link->parent != -1) { 818 char iface[IF_NAMESIZE]; 819 820 if (!if_indextoname(link->parent, iface)) perror_exit(NULL); 821 sprintf(toybuf,"%s@%s", link->iface, iface); 822 } 823 if (link->flags & IFF_POINTOPOINT) peer = "peer"; 824 if (TT.is_addr && TT.singleline && TT.addressfamily) 825 xprintf("%d: %s", link->iface_idx, 826 ((link->parent == -1) ? link->iface : toybuf)); 827 else xprintf("%d: %s: <%s> mtu %d qdisc %s state %s qlen %d", 828 link->iface_idx, ((link->parent == -1) ? link->iface : toybuf), flags, 829 link->mtu, link->qdiscpline, link->state, link->txqueuelen); 830 831 if (!TT.addressfamily || TT.addressfamily == AF_PACKET) 832 xprintf("%slink/%s %s %s %s", 833 line_feed, link->type, link->laddr, peer ,link->bcast); 834 835 xputc('\n'); 836 837 //user can specify stats flag two times 838 //one for stats and other for erros e.g. -s and -s -s 839 print_stats(&link->rt_stat); 840 free(flags); 841 842 return 0; 843 } 844 845 static void fill_address(void *p, char *ip) 846 { 847 unsigned char *ptr = (unsigned char*)p; 848 snprintf(ip, 64, " %02x:%02x:%02x:%02x:%02x:%02x", 849 ptr[0], ptr[1], ptr[2], ptr[3], ptr[4], ptr[5]); 850 } 851 852 static int get_link_info(struct nlmsghdr* h,struct linkdata* link,char **argv) 853 { 854 struct ifinfomsg *iface = NLMSG_DATA(h); 855 struct rtattr *attr = IFLA_RTA(iface); 856 int len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*iface)); 857 struct arglist hwtypes[]={{"generic",0},{"ether",ARPHRD_ETHER}, 858 {"loopback", ARPHRD_LOOPBACK},{"sit",ARPHRD_SIT}, 859 #ifdef ARPHRD_INFINIBAND 860 {"infiniband",ARPHRD_INFINIBAND}, 861 #endif 862 #ifdef ARPHRD_IEEE802_TR 863 {"ieee802",ARPHRD_IEEE802}, {"tr",ARPHRD_IEEE802_TR}, 864 #else 865 {"tr",ARPHRD_IEEE802}, 866 #endif 867 #ifdef ARPHRD_IEEE80211 868 {"ieee802.11",ARPHRD_IEEE80211}, 869 #endif 870 #ifdef ARPHRD_IEEE1394 871 {"ieee1394",ARPHRD_IEEE1394}, 872 #endif 873 {"irda",ARPHRD_IRDA},{"slip",ARPHRD_SLIP},{"cslip",ARPHRD_CSLIP}, 874 {"slip6",ARPHRD_SLIP6}, {"cslip6",ARPHRD_CSLIP6}, {"ppp",ARPHRD_PPP}, 875 {"ipip",ARPHRD_TUNNEL}, {"tunnel6",ARPHRD_TUNNEL6}, 876 {"gre",ARPHRD_IPGRE}, 877 #ifdef ARPHRD_VOID 878 {"void",ARPHRD_VOID}, 879 #endif 880 {NULL,-1}}; 881 char *lname = get_flag_string(hwtypes, iface->ifi_type, 0); 882 883 link->next = link->prev = 0; 884 link->iface_type = iface->ifi_type; 885 if (!lname) error_exit("Invalid link."); 886 xstrncpy(link->type, lname, IFNAMSIZ); 887 free(lname); 888 link->iface_idx = iface->ifi_index; 889 link->flags = iface->ifi_flags; 890 if (*argv && !strcasecmp("up",*argv) && !(link->flags & IFF_UP)) return 1; 891 link->parent = -1; 892 for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) { 893 switch(attr->rta_type) { 894 case IFLA_IFNAME: 895 snprintf(link->iface, IFNAMSIZ, "%s",(char *) RTA_DATA(attr)); 896 break; 897 case IFLA_ADDRESS: 898 if ( iface->ifi_type== ARPHRD_TUNNEL || 899 iface->ifi_type == ARPHRD_SIT || 900 iface->ifi_type == ARPHRD_IPGRE) 901 inet_ntop(AF_INET, RTA_DATA(attr), link->laddr, 64); 902 else fill_address(RTA_DATA(attr), link->laddr); 903 break; 904 case IFLA_BROADCAST: 905 if (iface->ifi_type== ARPHRD_TUNNEL || 906 iface->ifi_type == ARPHRD_SIT || 907 iface->ifi_type == ARPHRD_IPGRE) 908 inet_ntop(AF_INET, RTA_DATA(attr), link->bcast, 64); 909 else fill_address(RTA_DATA(attr), link->bcast); 910 break; 911 case IFLA_MTU: 912 link->mtu = *((int*)(RTA_DATA(attr))); 913 break; 914 case IFLA_QDISC: 915 snprintf(link->qdiscpline, IFNAMSIZ, "%s", (char *) RTA_DATA(attr)); 916 break; 917 case IFLA_STATS : 918 link->rt_stat = *((struct rtnl_link_stats*) RTA_DATA(attr)); 919 break; 920 case IFLA_LINK: 921 link->parent = *((int*)(RTA_DATA(attr))); 922 break; 923 case IFLA_TXQLEN: 924 link->txqueuelen = *((int*)(RTA_DATA(attr))); 925 break; 926 case IFLA_OPERSTATE: 927 { 928 struct arglist flags[]={{"UNKNOWN", 0}, {"NOTPRESENT", 1}, 929 {"DOWN", 2}, {"LOWERLAYERDOWN", 3}, {"TESTING", 4}, 930 {"DORMANT", 5}, {"UP", 6}, {NULL, -1}}; 931 if (!(lname = get_flag_string(flags, *((int*)(RTA_DATA(attr))), 0))) 932 error_exit("Invalid state."); 933 xstrncpy(link->state, lname,IFNAMSIZ); 934 free(lname); 935 } 936 break; 937 default: break; 938 } 939 } 940 return 0; 941 } 942 943 static int display_link_info(struct nlmsghdr *mhdr, char **argv) 944 { 945 struct linkdata link; 946 947 if (!get_link_info(mhdr, &link, argv)) { 948 if (TT.is_addr) { 949 struct linkdata *lnk = xzalloc(sizeof(struct linkdata)); 950 memcpy(lnk, &link, sizeof(struct linkdata)); 951 dlist_add_nomalloc((struct double_list **)&linfo, 952 (struct double_list *)lnk); 953 } 954 else print_link_output(&link); 955 } 956 return 0; 957 } 958 959 static int link_show(char **argv) 960 { 961 struct { 962 struct nlmsghdr mhdr; 963 struct ifinfomsg info; 964 } request; 965 uint32_t index = 0; 966 967 if (*argv && strcasecmp("up",*argv)) index = get_ifaceindex(*argv, 1); 968 memset(&request, 0, sizeof(request)); 969 request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg)); 970 request.mhdr.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; 971 if (!index) request.mhdr.nlmsg_flags |= NLM_F_ROOT|NLM_F_MATCH; 972 else request.info.ifi_change = 0xffffffff; // used in single operation 973 request.mhdr.nlmsg_type = RTM_GETLINK; 974 request.info.ifi_index = index; 975 request.info.ifi_family = AF_UNSPEC; 976 send_nlmesg(0, 0, 0, (void*)&request, sizeof(request)); 977 return (filter_nlmesg(display_link_info, argv)); 978 } 979 980 static int iplink(char **argv) 981 { 982 int idx; 983 cmdobj ipcmd, cmdobjlist[] = {linkupdate, link_set, link_show}; 984 struct arglist cmd_objectlist[] = {{"add", 0}, {"delete", 0}, 985 {"set", 1}, {"show", 2}, {"list", 2}, {"lst", 2}, {NULL,-1}}; 986 987 if (!*argv) idx = 2; 988 else if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1) 989 help_exit(0); 990 ipcmd = cmdobjlist[idx]; 991 return ipcmd(argv); 992 } 993 994 // =========================================================================== 995 // Code for ip addr. 996 // =========================================================================== 997 998 static int print_addrinfo(struct nlmsghdr *h, int flag_l) 999 { 1000 struct rtattr *rta, *rta_tb[IFA_MAX+1] = {0,}; 1001 char *family = toybuf, *scope = toybuf+256, *label = toybuf+512, 1002 *brd = toybuf+768, *peer = toybuf+1024, *any = toybuf+1280, 1003 lbuf[INET6_ADDRSTRLEN] = {0,}, lbuf_ifa[INET6_ADDRSTRLEN] = {0,}; 1004 struct ifaddrmsg *ifa = NLMSG_DATA(h); 1005 int len; 1006 1007 if ((len = h->nlmsg_len - NLMSG_LENGTH(sizeof(*ifa))) < 0) { 1008 error_msg("wrong nlmsg len %d", len); 1009 return 0; 1010 } 1011 1012 for (rta = IFA_RTA(ifa); RTA_OK(rta, len); rta=RTA_NEXT(rta, len)) 1013 if (rta->rta_type <= IFA_MAX) rta_tb[rta->rta_type] = rta; 1014 1015 if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; 1016 if (!rta_tb[IFA_ADDRESS]) rta_tb[IFA_ADDRESS] = rta_tb[IFA_LOCAL]; 1017 if ((addrinfo.scope ^ ifa->ifa_scope)&addrinfo.scopemask) return 0; 1018 if (addrinfo.ifindex && addrinfo.ifindex != ifa->ifa_index) return 0; 1019 1020 if (flag_l && addrinfo.label && ifa->ifa_family == AF_INET6) return 0; 1021 if ((rta_tb[IFA_LABEL])) { 1022 xstrncpy(label, RTA_DATA(rta_tb[IFA_LABEL]), 256); 1023 label[255] = '\0'; 1024 if (addrinfo.label && fnmatch(addrinfo.label, label, 0)) 1025 return 0; 1026 } 1027 1028 if (TT.flush) { 1029 if (ifa->ifa_index == addrinfo.ifindex) { 1030 h->nlmsg_type = RTM_DELADDR; 1031 h->nlmsg_flags = NLM_F_REQUEST; 1032 send_nlmesg(RTM_DELADDR, 0, 0, h, h->nlmsg_len); 1033 return 0; 1034 } 1035 } 1036 1037 if (h->nlmsg_type == RTM_DELADDR) printf("Deleted "); 1038 1039 if (TT.singleline) { 1040 if (!if_indextoname(ifa->ifa_index, lbuf)) perror_exit(NULL); 1041 printf("%u: %s",ifa->ifa_index, lbuf); 1042 } 1043 1044 sprintf(scope, " scope %s ", namefromRPDB(ifa->ifa_scope, RPDB_rtscopes)); 1045 1046 if (ifa->ifa_family == AF_INET) strcpy(family, " inet "); 1047 else if (ifa->ifa_family == AF_INET6) strcpy(family, " inet6 "); 1048 else sprintf(family, " family %d", ifa->ifa_family); 1049 1050 if (rta_tb[IFA_LOCAL]) { 1051 if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_LOCAL]), 1052 lbuf, sizeof(lbuf))) perror_exit("inet"); 1053 1054 sprintf(family+strlen(family), lbuf, strlen(lbuf)); 1055 if (!rta_tb[IFA_ADDRESS] || !memcmp(RTA_DATA(rta_tb[IFA_ADDRESS]), 1056 RTA_DATA(rta_tb[IFA_LOCAL]), 4)) 1057 sprintf(family+strlen(family), "/%d ", ifa->ifa_prefixlen); 1058 else { 1059 if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_ADDRESS]), 1060 lbuf_ifa, sizeof(lbuf_ifa))) perror_exit("inet"); 1061 sprintf(peer, " peer %s/%d ", lbuf_ifa, ifa->ifa_prefixlen); 1062 } 1063 } 1064 1065 if (addrinfo.to && strcmp(addrinfo.addr, lbuf)) 1066 return 0; 1067 1068 if (rta_tb[IFA_BROADCAST]) { 1069 if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_BROADCAST]), 1070 lbuf, sizeof(lbuf))) perror_exit("inet"); 1071 sprintf(brd, " brd %s", lbuf); 1072 }else brd = ""; 1073 1074 if (rta_tb[IFA_ANYCAST]) { 1075 if (!inet_ntop(ifa->ifa_family, RTA_DATA(rta_tb[IFA_ANYCAST]), 1076 lbuf, sizeof(lbuf))) perror_exit("inet"); 1077 sprintf(any, " any %s", lbuf); 1078 } 1079 1080 if (ifa->ifa_family == AF_INET) 1081 printf("%s%s%s%s%s %c", family, brd, peer, scope, label, 1082 (TT.singleline? '\0' : '\n')); 1083 else printf("%s%s %c", family, scope, (TT.singleline? '\0' : '\n')); 1084 if (TT.singleline && (ifa->ifa_family == AF_INET)) xputc('\n'); 1085 1086 if (rta_tb[IFA_CACHEINFO]) { 1087 struct ifa_cacheinfo *ci = RTA_DATA(rta_tb[IFA_CACHEINFO]); 1088 1089 printf("%c valid_lft ", (TT.singleline? '\\' : '\0')); 1090 if (ci->ifa_valid == 0xFFFFFFFFU) printf("forever"); 1091 else printf("%usec", ci->ifa_valid); 1092 printf(" preferred_lft "); 1093 if (ci->ifa_prefered == 0xFFFFFFFFU) printf("forever"); 1094 else printf("%dsec", ci->ifa_prefered); 1095 xputc('\n'); 1096 } 1097 return 0; 1098 } 1099 1100 static int ipaddrupdate(char **argv) 1101 { 1102 int length, cmd = !memcmp("add", argv[-1], strlen(argv[-1])) 1103 ? RTM_NEWADDR: RTM_DELADDR; 1104 int idx = 0,length_brd = 0, length_peer = 0,length_any = 0,length_local = 0, 1105 scoped = 0; 1106 char *dev = NULL,*label = NULL, reply[8192]; 1107 1108 struct nlmsghdr *addr_ptr = NULL; 1109 struct nlmsgerr *err = NULL; 1110 struct arglist cmd_objectlist[] = {{"dev",0}, {"peer", 1}, 1111 {"remote", 2}, {"broadcast", 3}, {"brd", 4}, {"label", 5}, 1112 {"anycast", 6},{"scope", 7}, {"local", 8}, {NULL, -1}}; 1113 struct { 1114 struct nlmsghdr nlm; 1115 struct ifaddrmsg ifadd; 1116 char buf[256]; 1117 } req; 1118 typedef struct { 1119 int family, bytelen, bitlen; 1120 __u32 data[8]; 1121 } option_data; 1122 option_data local; 1123 1124 memset(&req, 0, sizeof(req)); 1125 req.nlm.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifaddrmsg)); 1126 req.nlm.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK; 1127 req.nlm.nlmsg_type = cmd; 1128 req.ifadd.ifa_family = TT.addressfamily; 1129 1130 while (*argv) { 1131 idx = substring_to_idx(*argv, cmd_objectlist); 1132 if (idx >= 0) 1133 if (!*++argv) 1134 error_exit("Incomplete Command line"); 1135 switch(idx) { 1136 case 0: 1137 dev = *argv; 1138 break; 1139 case 1: 1140 case 2: 1141 { 1142 uint32_t addr[4] = {0,}, netmask = 0; 1143 uint8_t len = 0; 1144 parse_prefix(addr, &netmask, &len, *argv, 1145 req.ifadd.ifa_family); 1146 if (len) 1147 req.ifadd.ifa_family = ((len == 4) ? AF_INET : AF_INET6); 1148 length_peer = len; 1149 add_string_to_rtattr(&req.nlm, sizeof(req), 1150 IFA_ADDRESS, addr, len); 1151 req.ifadd.ifa_prefixlen = netmask; 1152 } 1153 break; 1154 case 3: 1155 case 4: 1156 if (*argv[0] == '+') { 1157 length_brd = -1; 1158 } else if (*argv[0] == '-') { 1159 length_brd = -2; 1160 } else { 1161 uint32_t addr[4] = {0,}; 1162 uint8_t af = AF_UNSPEC; 1163 1164 if (get_prefix(addr, &af, *argv, req.ifadd.ifa_family)) 1165 error_exit("Invalid prefix"); 1166 1167 length_brd = ((af == AF_INET6) ? 16 : 4); 1168 if (req.ifadd.ifa_family == AF_UNSPEC) 1169 req.ifadd.ifa_family = af; 1170 add_string_to_rtattr(&req.nlm, sizeof(req), 1171 IFA_BROADCAST, &addr, length_brd); 1172 } 1173 break; 1174 case 5: 1175 label = *argv; 1176 add_string_to_rtattr(&req.nlm, sizeof(req), 1177 IFA_LABEL, label, strlen(label) + 1); 1178 break; 1179 case 6: 1180 { 1181 uint32_t addr[4] = {0,}; 1182 uint8_t af = AF_UNSPEC; 1183 1184 if (get_prefix(addr, &af, *argv, req.ifadd.ifa_family)) 1185 error_exit("Invalid prefix"); 1186 length_any = ((af == AF_INET6) ? 16 : 4); 1187 if (req.ifadd.ifa_family == AF_UNSPEC) 1188 req.ifadd.ifa_family = af; 1189 add_string_to_rtattr(&req.nlm, sizeof(req), 1190 IFA_ANYCAST, &addr, length_any); 1191 } 1192 break; 1193 case 7: 1194 { 1195 int scope = idxfromRPDB(*argv, RPDB_rtscopes); 1196 if (scope < 0) error_exit("wrong scope '%s'", *argv); 1197 req.ifadd.ifa_scope = scope; 1198 scoped = 1; 1199 } 1200 break; 1201 default: 1202 { 1203 //local is by default 1204 uint32_t addr[8] = {0,}, netmask = 0; 1205 uint8_t len = 0; 1206 1207 parse_prefix(addr, &netmask, &len, *argv, 1208 req.ifadd.ifa_family); 1209 if (len) 1210 req.ifadd.ifa_family = ((len == 4) ? AF_INET : AF_INET6); 1211 length_local = len; 1212 local.bitlen = netmask; 1213 local.bytelen = len; 1214 memcpy(local.data, addr, sizeof(local.data)); 1215 local.family = req.ifadd.ifa_family; 1216 add_string_to_rtattr(&req.nlm, sizeof(req), 1217 IFA_LOCAL, &local.data, local.bytelen); 1218 } 1219 break; 1220 } 1221 argv++; 1222 } 1223 if (!dev) error_exit("need \"dev \" argument"); 1224 if (label && strncmp(dev, label, strlen(dev)) != 0) 1225 error_exit("\"dev\" (%s) must match \"label\" (%s)", dev, label); 1226 1227 if (length_peer == 0 && length_local && cmd != RTM_DELADDR){ 1228 add_string_to_rtattr(&req.nlm, sizeof(req), 1229 IFA_ADDRESS, &local.data, local.bytelen); 1230 } 1231 1232 if (length_brd < 0 && cmd != RTM_DELADDR){ 1233 int i; 1234 1235 if (req.ifadd.ifa_family != AF_INET) 1236 error_exit("broadcast can be set only for IPv4 addresses"); 1237 1238 if (local.bitlen <= 30) { 1239 for (i = 31; i >= local.bitlen; i--) { 1240 if (length_brd == -1) 1241 local.data[0] |= htonl(1<<(31-i)); 1242 else 1243 local.data[0] &= ~htonl(1<<(31-i)); 1244 } 1245 add_string_to_rtattr(&req.nlm, sizeof(req), 1246 IFA_BROADCAST, &local.data, local.bytelen); 1247 length_brd = local.bytelen; 1248 } 1249 } 1250 if (req.ifadd.ifa_prefixlen == 0) 1251 req.ifadd.ifa_prefixlen = local.bitlen; 1252 if (!scoped && (cmd != RTM_DELADDR) && (local.family == AF_INET) 1253 && (local.bytelen >= 1 && *(uint8_t*)&local.data == 127)) 1254 req.ifadd.ifa_scope = RT_SCOPE_HOST; 1255 req.ifadd.ifa_index = get_ifaceindex(dev, 1); 1256 1257 send_nlmesg(RTM_NEWADDR, 0, AF_UNSPEC, (void *)&req, req.nlm.nlmsg_len); 1258 length = recv(TT.sockfd, reply, sizeof(reply), 0); 1259 addr_ptr = (struct nlmsghdr *) reply; 1260 for (; NLMSG_OK(addr_ptr, length); addr_ptr = NLMSG_NEXT(addr_ptr, length)) { 1261 if (addr_ptr->nlmsg_type == NLMSG_DONE) 1262 return 1; 1263 if (addr_ptr->nlmsg_type == NLMSG_ERROR) 1264 err = (struct nlmsgerr*) NLMSG_DATA(addr_ptr); 1265 if (err && err->error) { 1266 errno = -err->error; 1267 perror_exit("RTNETLINK answers:"); 1268 } 1269 } 1270 return 0; 1271 } 1272 1273 static int ipaddr_listflush(char **argv) 1274 { 1275 int idx; uint32_t netmask = 0, found = 0; 1276 char *tmp = NULL, *name = NULL; 1277 struct double_list *dlist; 1278 struct arglist cmd_objectlist[] = {{"to", 0}, {"scope", 1}, {"up", 2}, 1279 {"label", 3}, {"dev", 4}, {NULL, -1}}; 1280 1281 TT.flush = *argv[-1] == 'f' ? 1 : 0; 1282 memset(&addrinfo, 0, sizeof(addrinfo)); 1283 1284 if (TT.flush) { 1285 if (!*argv) 1286 error_exit("Incomplete command for \"flush\""); 1287 if (TT.addressfamily == AF_PACKET) 1288 error_exit("Can't flush link Addressess"); 1289 } 1290 addrinfo.scope = -1; 1291 while (*argv) { 1292 switch (idx = substring_to_idx(*argv, cmd_objectlist)) { 1293 case 0: 1294 {// ADDR_TO 1295 if (!*++argv) error_exit("Incomplete Command line"); 1296 else if (!strcmp(*argv, "0")) return 0; 1297 uint32_t addr[4] = {0,}; 1298 uint8_t len = 0; 1299 1300 addrinfo.to = 1; 1301 parse_prefix(addr, &netmask, &len, *argv, TT.addressfamily); 1302 if (len) 1303 TT.addressfamily = ((len == 4) ? AF_INET : AF_INET6); 1304 addrinfo.addr = strtok(*argv, "/"); 1305 } 1306 break; 1307 case 1: // ADDR_SCOPE 1308 { 1309 int scope = 0; 1310 if (!*++argv) error_exit("Incomplete Command line"); 1311 name = *argv; 1312 1313 addrinfo.scopemask = -1; 1314 if (isdigit(**argv)) { 1315 int idx = atolx(*argv); 1316 1317 name = xstrdup(namefromRPDB(idx, RPDB_rtscopes)); 1318 } 1319 if ((scope = idxfromRPDB(name, RPDB_rtscopes)) < 0) { 1320 if (strcmp(name, "all")) 1321 error_exit("wrong scope '%s'", name); 1322 scope = RT_SCOPE_NOWHERE; 1323 addrinfo.scopemask = 0; 1324 } 1325 1326 if (isdigit(**argv)) 1327 free(name); 1328 addrinfo.scope = scope; 1329 } 1330 break; 1331 case 2: // ADDR_UP 1332 addrinfo.up = 1; 1333 break; 1334 case 3: // ADDR_LABEL 1335 if (!*++argv) error_exit("Incomplete Command line"); 1336 addrinfo.label = *argv; 1337 break; 1338 case 4: // ADDR_DEV 1339 if (!*++argv) error_exit("Incomplete Command line"); 1340 1341 default: 1342 if (TT.filter_dev) 1343 error_exit("Either \"dev\" is duplicate or %s is garbage", 1344 *argv); 1345 TT.filter_dev = *argv; 1346 break; 1347 } 1348 argv++; 1349 } 1350 1351 link_show(&tmp); 1352 while ( linfo && (dlist = dlist_pop(&linfo))){ 1353 struct linkdata *tmp = (struct linkdata*) dlist; 1354 char *temp = &tmp->iface[0]; 1355 1356 if (TT.filter_dev && strcmp(TT.filter_dev, temp)) 1357 continue; 1358 found = 1; 1359 if (TT.flush && addrinfo.label) ipaddr_print( tmp, 0); 1360 if (addrinfo.up && !(tmp->flags & IFF_UP)){ 1361 ipaddr_print(tmp, 0); 1362 continue; 1363 } 1364 if (addrinfo.label){ 1365 if ( fnmatch(addrinfo.label, temp, 0)) { 1366 ipaddr_print(tmp, 1); 1367 continue; 1368 } 1369 } 1370 if (!TT.addressfamily && ! TT.flush ) print_link_output(tmp); 1371 1372 ipaddr_print(tmp, 0); 1373 free(tmp); 1374 } 1375 if (TT.filter_dev && !found) 1376 error_exit("Device \"%s\" doesn't exist. \n", TT.filter_dev); 1377 return 0; 1378 } 1379 1380 static int ipaddr_print( struct linkdata *link, int flag_l) 1381 { 1382 struct nlmsghdr *addr_ptr; 1383 int ip_match = 0; 1384 1385 addrinfo.ifindex = link->iface_idx; 1386 send_nlmesg(RTM_GETADDR, NLM_F_ROOT|NLM_F_MATCH|NLM_F_REQUEST, 1387 AF_UNSPEC, NULL, 0); 1388 if (TT.addressfamily == AF_PACKET) print_link_output(link); 1389 1390 if (addrinfo.label){ 1391 char *col = strchr(addrinfo.label, ':'); 1392 if (!col && (fnmatch(addrinfo.label, &link->iface[0], 0))) 1393 return 0; 1394 } 1395 1396 while (1){ 1397 int len = recv(TT.sockfd, TT.gbuf, sizeof(TT.gbuf), 0); 1398 addr_ptr = (struct nlmsghdr *)TT.gbuf; 1399 struct ifaddrmsg *addressInfo = NLMSG_DATA(addr_ptr); 1400 char lbuf[INET6_ADDRSTRLEN]; 1401 struct rtattr *rta, *rta_tb[IFA_MAX+1] = {0,}; 1402 1403 int len1 = addr_ptr->nlmsg_len - NLMSG_LENGTH(sizeof(*addressInfo)); 1404 if (len1 > 0) { 1405 for (; NLMSG_OK(addr_ptr, len); addr_ptr = NLMSG_NEXT(addr_ptr, len)) { 1406 addressInfo = NLMSG_DATA(addr_ptr); 1407 if (TT.addressfamily && TT.addressfamily != addressInfo->ifa_family) 1408 continue; 1409 if (addrinfo.ifindex && addrinfo.ifindex != addressInfo->ifa_index) 1410 continue; 1411 1412 if (addrinfo.to) { 1413 memset(rta_tb, 0, sizeof(rta_tb)); 1414 int rt_len = IFA_PAYLOAD(addr_ptr); 1415 for (rta = IFA_RTA(addressInfo); RTA_OK(rta, rt_len); rta=RTA_NEXT(rta, rt_len)) { 1416 if (rta->rta_type <= IFA_MAX) rta_tb[rta->rta_type] = rta; 1417 } 1418 if (!rta_tb[IFA_LOCAL]) rta_tb[IFA_LOCAL] = rta_tb[IFA_ADDRESS]; 1419 if (rta_tb[IFA_LOCAL]) { 1420 if (!inet_ntop(TT.addressfamily, RTA_DATA(rta_tb[IFA_LOCAL]), 1421 lbuf, sizeof(lbuf))) perror_exit("inet"); 1422 if (strcmp(addrinfo.addr, lbuf)) 1423 continue; 1424 ip_match=1; 1425 } 1426 if (!ip_match) 1427 continue; 1428 } 1429 1430 if (!TT.flush){ 1431 if (addrinfo.scope != -1 && TT.addressfamily && TT.addressfamily == 1432 addressInfo->ifa_family && 1433 (addrinfo.ifindex == addressInfo->ifa_index)) { 1434 if ((addrinfo.scope ^ addressInfo->ifa_scope) & addrinfo.scopemask) 1435 continue; 1436 else if (addrinfo.up && (link->flags & IFF_UP)) 1437 print_link_output(link); 1438 else if (!addrinfo.up) print_link_output(link); 1439 } 1440 if (TT.addressfamily && 1441 (addrinfo.ifindex == addressInfo->ifa_index) && 1442 (addrinfo.scope == -1)){ 1443 if (addrinfo.up && (link->flags & IFF_UP)) 1444 print_link_output(link); 1445 else if (!addrinfo.up) print_link_output(link); 1446 } 1447 } 1448 1449 for (; NLMSG_OK(addr_ptr, len); addr_ptr = NLMSG_NEXT(addr_ptr, len)) { 1450 if ((addr_ptr->nlmsg_type == RTM_NEWADDR)) 1451 print_addrinfo(addr_ptr, flag_l); 1452 if ((addr_ptr->nlmsg_type == NLMSG_DONE) || 1453 (addr_ptr->nlmsg_type == NLMSG_ERROR) || 1454 (TT.flush && addrinfo.to)) 1455 goto ret_stop; 1456 } 1457 if ((addr_ptr->nlmsg_type == NLMSG_DONE) || 1458 (addr_ptr->nlmsg_type == NLMSG_ERROR)) 1459 break; 1460 } 1461 } 1462 else 1463 return 0; 1464 } 1465 1466 ret_stop: 1467 return 0; 1468 } 1469 1470 static int ipaddr(char **argv) 1471 { 1472 int idx; 1473 cmdobj ipcmd, cmdobjlist[] = {ipaddrupdate, ipaddr_listflush}; 1474 struct arglist cmd_objectlist[] = { {"add", 0}, {"delete", 0}, 1475 {"list", 1},{"show", 1},{"lst", 1}, {"flush", 1}, {NULL,-1}}; 1476 1477 TT.is_addr++; 1478 if (!*argv) idx = 1; 1479 else if ((idx = substring_to_idx(*argv++, cmd_objectlist)) == -1) 1480 help_exit(0); 1481 1482 ipcmd = cmdobjlist[idx]; 1483 return ipcmd(argv); 1484 } 1485 1486 // =========================================================================== 1487 // code for ip route 1488 // =========================================================================== 1489 struct I_data { 1490 unsigned char family; 1491 uint32_t addr[8] , netmask ; 1492 uint8_t len ; 1493 }; 1494 1495 struct { 1496 int tb,idev,odev,proto; 1497 struct I_data rvia, rdst, mdst, rsrc, msrc; 1498 } gfilter; 1499 1500 static void show_iproute_help(void) 1501 { 1502 char *errmsg = "\n\n" \ 1503 "iproute { list | flush } SELECTOR\n" \ 1504 "iproute get ADDRESS [from ADDRESS iif STRING]\n" \ 1505 " [oif STRING]\n" \ 1506 "iproute { add | del | change | append | replace | test } ROUTE\n" \ 1507 " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" \ 1508 " ROUTE := [TYPE] PREFIX [proto RTPROTO] [metric METRIC]"; 1509 1510 error_exit(errmsg); 1511 } 1512 1513 static void print_rta_metrics(char* out, const struct rtattr *mxattr) 1514 { 1515 int32_t tvar = RTA_PAYLOAD(mxattr); 1516 struct rtattr *rta, *mxrta[RTAX_MAX+1] = {0,}; 1517 unsigned int mxlock = 0; 1518 int i; 1519 1520 for (rta = RTA_DATA(mxattr); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar)) 1521 if (rta->rta_type <= RTA_MAX) mxrta[rta->rta_type] = rta; 1522 1523 if (mxrta[RTAX_LOCK]) 1524 mxlock = *(u_int32_t *)RTA_DATA(mxrta[RTAX_LOCK]); 1525 1526 for (i = 2; i <= RTAX_MAX; i++) { 1527 uint32_t val = 0; 1528 1529 if (mxrta[i] == NULL && !(mxlock & (1 << i))) 1530 continue; 1531 1532 if (mxrta[i] != NULL && i != RTAX_CC_ALGO) 1533 val = *(u_int32_t *)RTA_DATA(mxrta[i]); 1534 1535 if (i == RTAX_HOPLIMIT && (int)val == -1) 1536 continue; 1537 1538 if (i < sizeof(mx_names)/sizeof(char *) && mx_names[i]) 1539 sprintf(out, "%s%s ", out, mx_names[i]); 1540 else 1541 sprintf(out, "%smetric %d ", out, i); 1542 1543 if (mxlock & (1<<i)) 1544 sprintf(out, "%slock ", out); 1545 1546 switch (i) { 1547 case RTAX_RTT: 1548 case RTAX_RTTVAR: 1549 case RTAX_RTO_MIN: 1550 if (i == RTAX_RTT) 1551 val /= 8; 1552 else if (i == RTAX_RTTVAR) 1553 val /= 4; 1554 1555 if (val >= 1000) 1556 sprintf(out, "%s%gs ", out, val / 1e3); 1557 else 1558 sprintf(out, "%s%ums ", out, val); 1559 break; 1560 1561 case RTAX_CC_ALGO: 1562 sprintf(out, "%scongestion %s ", out, (const char*)RTA_DATA(mxrta[i])); 1563 break; 1564 1565 default: 1566 sprintf(out, "%s%u ", out, val); 1567 break; 1568 } 1569 } 1570 } 1571 1572 static int display_route_info(struct nlmsghdr *mhdr, char **argv) 1573 { 1574 char *inetval = NULL, out[1024] = {0}; 1575 struct rtmsg *msg = NLMSG_DATA(mhdr); 1576 struct rtattr *rta, *attr[RTA_MAX+1] = {0,}; 1577 int32_t tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); 1578 int hlen = ((msg->rtm_family == AF_INET) ? 32 1579 : ((msg->rtm_family == AF_INET6) ? 128 : -1)); 1580 1581 if (mhdr->nlmsg_type != RTM_NEWROUTE) return 0; 1582 if (msglen < 0) return 1; 1583 1584 if (msg->rtm_family == AF_INET6) { 1585 if (gfilter.tb) { 1586 if (gfilter.tb < 0) { 1587 if (!(msg->rtm_flags & RTM_F_CLONED)) return 0; 1588 } else { 1589 if (msg->rtm_flags & RTM_F_CLONED) return 0; 1590 if (gfilter.tb == RT_TABLE_LOCAL && msg->rtm_type != RTN_LOCAL) 1591 return 0; 1592 else if (gfilter.tb == RT_TABLE_MAIN && msg->rtm_type == RTN_LOCAL) 1593 return 0; 1594 } 1595 } 1596 } 1597 else if (gfilter.tb > 0 && gfilter.tb != msg->rtm_table) return 0; 1598 1599 if (gfilter.proto && (msg->rtm_protocol != gfilter.proto)) return 0; 1600 1601 1602 if (gfilter.rdst.family && (msg->rtm_family != gfilter.rdst.family || 1603 gfilter.rdst.netmask > msg->rtm_dst_len)) return 0; 1604 if (gfilter.mdst.family && (msg->rtm_family != gfilter.mdst.family 1605 || (gfilter.mdst.netmask < msg->rtm_dst_len))) return 0; 1606 if (gfilter.rsrc.family && (msg->rtm_family != gfilter.rsrc.family 1607 || gfilter.rsrc.netmask > msg->rtm_src_len)) return 0; 1608 if (gfilter.msrc.family && (msg->rtm_family != gfilter.msrc.family 1609 || (gfilter.msrc.netmask < msg->rtm_src_len))) return 0; 1610 tvar = msglen; 1611 1612 for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar)) 1613 if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta; 1614 1615 if (msg->rtm_type != RTN_UNICAST) 1616 sprintf(out,"%s%s ", out,rtmtype_idx2str(msg->rtm_type)); 1617 if (attr[RTA_DST]) { 1618 inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_DST]), 1619 toybuf, sizeof(toybuf)); 1620 if (gfilter.rdst.family && 1621 memcmp(RTA_DATA(attr[RTA_DST]), &gfilter.rdst.addr, gfilter.rdst.len)) 1622 return 0; 1623 if (gfilter.mdst.family && 1624 memcmp(RTA_DATA(attr[RTA_DST]), &gfilter.mdst.addr, gfilter.mdst.len)) 1625 return 0; 1626 sprintf(out,"%s%s",out,inetval); 1627 } 1628 if (msg->rtm_dst_len) sprintf(out,"%s/%d ", out,msg->rtm_dst_len); 1629 else sprintf(out,"%s%s",out,"default "); 1630 1631 if (attr[RTA_SRC]) { 1632 inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_SRC]), 1633 toybuf, sizeof(toybuf)); 1634 if (gfilter.rsrc.family && 1635 memcmp(RTA_DATA(attr[RTA_SRC]), &gfilter.rsrc.addr, gfilter.rsrc.len)) 1636 return 0; 1637 if (gfilter.msrc.family && 1638 memcmp(RTA_DATA(attr[RTA_SRC]), &gfilter.msrc.addr, gfilter.msrc.len)) 1639 return 0; 1640 sprintf(out, "%s from %s", out, inetval); 1641 } 1642 if (msg->rtm_src_len) sprintf(out, "%s/%d ", out, msg->rtm_src_len); 1643 1644 if (attr[RTA_GATEWAY]) { 1645 inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_GATEWAY]), 1646 toybuf, sizeof(toybuf)); 1647 sprintf(out, "%s via %s ", out, inetval); 1648 } 1649 if (gfilter.rvia.family) { 1650 char tmp[256]; 1651 1652 if (!attr[RTA_GATEWAY]) return 0; 1653 if (strcmp((char *)inet_ntop(msg->rtm_family, gfilter.rvia.addr, 1654 tmp, sizeof(tmp)), inetval)) return 0; 1655 } 1656 1657 if (gfilter.odev != 0) if (!attr[RTA_OIF]) return 0; 1658 if (attr[RTA_OIF]) { 1659 if (gfilter.odev !=0 && gfilter.odev != *(int*)RTA_DATA(attr[RTA_OIF])) 1660 return 0; 1661 sprintf(out, "%s dev %s ", out, 1662 if_indextoname(*(int*)RTA_DATA(attr[RTA_OIF]), toybuf)); 1663 } 1664 1665 if (attr[RTA_PREFSRC] && hlen) { 1666 inetval = (char *)inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_PREFSRC]), 1667 toybuf, sizeof(toybuf)); 1668 sprintf(out, "%s src %s ", out, inetval); 1669 } 1670 if (attr[RTA_PRIORITY]) 1671 sprintf(out, "%s metric %d ", out, *(uint32_t*)RTA_DATA(attr[RTA_PRIORITY])); 1672 if (msg->rtm_family == AF_INET6) { 1673 struct rta_cacheinfo *ci = NULL; 1674 if (attr[RTA_CACHEINFO]) ci = RTA_DATA(attr[RTA_CACHEINFO]); 1675 if ((msg->rtm_flags & RTM_F_CLONED) || (ci && ci->rta_expires)) { 1676 if (msg->rtm_flags & RTM_F_CLONED) sprintf(out, "%s%s cache ", 1677 out, (!TT.singleline ? "\n" : " ")); 1678 if (ci && ci->rta_expires) { 1679 int hz = 0; 1680 FILE *fp = xfopen("/proc/net/psched","r"); 1681 1682 if (fp) { 1683 unsigned int nom, denom; 1684 1685 if (fscanf(fp, "%*08x%*08x%08x%08x", &nom, &denom) == 2) 1686 if (nom == 1000000) 1687 hz = denom; 1688 fclose(fp); 1689 } 1690 if (!hz) hz = sysconf(_SC_CLK_TCK); 1691 sprintf(out, "%s expires %dsec", out, ci->rta_expires /hz); 1692 } 1693 if (ci && ci->rta_error) sprintf(out, "%s error %d", out, ci->rta_error); 1694 } 1695 else if (ci && ci->rta_error) 1696 sprintf(out, "%s error %d", out, ci->rta_error); 1697 } 1698 if (attr[RTA_IIF] && !gfilter.idev) 1699 sprintf(out, "%s iif %s", out, 1700 if_indextoname(*(int*)RTA_DATA(attr[RTA_IIF]), toybuf)); 1701 1702 if (attr[RTA_METRICS]) 1703 print_rta_metrics(out, attr[RTA_METRICS]); 1704 1705 if (TT.flush || (TT.connected && !TT.from_ok)) 1706 memcpy(toybuf, (void*)mhdr,mhdr->nlmsg_len); 1707 1708 if (TT.flush) { 1709 int sockfd = 0; 1710 struct nlmsghdr* mhdr = (struct nlmsghdr*)toybuf; 1711 struct rtmsg *msg = NLMSG_DATA(mhdr); 1712 int tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); 1713 struct rtattr *rta, *attr[RTA_MAX+1] = {0,}; 1714 1715 tvar = msglen; 1716 for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar)) 1717 if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta; 1718 1719 if (msg->rtm_family == AF_INET6 1720 && !msg->rtm_dst_len 1721 && msg->rtm_type == RTN_UNREACHABLE 1722 && attr[RTA_PRIORITY] 1723 && *(int*)RTA_DATA(attr[RTA_PRIORITY]) == -1) 1724 return 0; 1725 1726 mhdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 1727 mhdr->nlmsg_type = RTM_DELROUTE; 1728 mhdr->nlmsg_pid = 0; 1729 sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 1730 if (send(sockfd , (void*)mhdr, mhdr->nlmsg_len, 0) < 0) 1731 perror_exit("Unable to send data on socket."); 1732 1733 while (1) { 1734 struct nlmsghdr *mhdr; 1735 int msglen = recv(sockfd, toybuf, sizeof(toybuf), 0); 1736 1737 if ((msglen < 0) && (errno == EINTR || errno == EAGAIN)) continue; 1738 else if (msglen < 0) { 1739 error_msg("netlink receive error %s", strerror(errno)); 1740 xclose(sockfd); 1741 return 1; 1742 } else if (!msglen) { 1743 error_msg("EOF on netlink"); 1744 xclose(sockfd); 1745 return 1; 1746 } 1747 1748 for (mhdr = (struct nlmsghdr*)toybuf; NLMSG_OK(mhdr, msglen); 1749 mhdr = NLMSG_NEXT(mhdr, msglen)) { 1750 switch (mhdr->nlmsg_type) { 1751 case NLMSG_DONE: 1752 xclose(sockfd); 1753 return 0; 1754 case NLMSG_ERROR: 1755 { 1756 struct nlmsgerr *merr = (struct nlmsgerr*)NLMSG_DATA(mhdr); 1757 1758 if (merr->error == 0) { xclose(sockfd); return 0; } 1759 if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 1760 error_msg("ERROR truncated"); 1761 else { 1762 errno = -merr->error; 1763 perror_msg("RTNETLINK answers"); 1764 } 1765 xclose(sockfd); 1766 return 1; 1767 } 1768 default: 1769 break; 1770 } 1771 } // End of for loop. 1772 } // End of while loop. 1773 1774 xclose(sockfd); 1775 } else printf("%s\n",out); 1776 return 0; 1777 } 1778 1779 static int route_get(char **argv) 1780 { 1781 int idx, flag; 1782 struct arglist cmd_objectlist[] = {{"from", 0}, {"iif", 1}, {"oif", 2}, 1783 {"dev", 3}, {"notify", 4}, {"connected", 5}, {"to", 6}, {NULL, -1}}; 1784 char *idev = NULL, *odev = NULL; 1785 struct { 1786 struct nlmsghdr mhdr; 1787 struct rtmsg msg; 1788 char buf[1024]; 1789 } request; 1790 1791 memset(&request, 0, sizeof(request)); 1792 request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 1793 request.mhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 1794 request.mhdr.nlmsg_type = RTM_GETROUTE; 1795 request.msg.rtm_family = AF_UNSPEC; 1796 1797 for (; *argv; argv++) { 1798 switch(idx = substring_to_idx(*argv, cmd_objectlist)) { 1799 case 0: TT.from_ok = 1; // dst address 1800 case 6: argv++; //fallthrough 1801 default: 1802 { 1803 uint32_t addr[8] = {0,}, netmask = 0; 1804 uint8_t len = 0; 1805 1806 if (!*argv) error_exit("'%s': Missing Prefix", argv[-1]); 1807 parse_prefix(addr, &netmask, &len, *argv, request.msg.rtm_family); 1808 if (len) request.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6); 1809 netmask = (request.msg.rtm_family == AF_INET6) ? 128 : 32; 1810 if (!idx) request.msg.rtm_src_len = netmask; 1811 else request.msg.rtm_dst_len = netmask; 1812 add_string_to_rtattr(&request.mhdr, sizeof(request), 1813 (!idx ? RTA_SRC : RTA_DST), addr, len); 1814 break; 1815 } 1816 case 1: 1817 case 2: 1818 case 3: 1819 if (!*++argv) show_iproute_help(); 1820 if (idx == 1) idev = *argv, flag = RTA_IIF; 1821 else odev = *argv, flag = RTA_OIF; 1822 idx = get_ifaceindex(*argv, 1); 1823 add_string_to_rtattr(&request.mhdr, sizeof(request), 1824 flag, (char*)&idx, sizeof(idx)); 1825 break; 1826 case 4: 1827 request.msg.rtm_flags |= RTM_F_NOTIFY; 1828 break; 1829 case 5: 1830 TT.connected = 1; 1831 break; 1832 } 1833 } 1834 if (!request.msg.rtm_dst_len) 1835 error_exit("need at least destination address"); 1836 1837 send_nlmesg(0, 0, 0, &request, sizeof(request)); 1838 filter_nlmesg(display_route_info, NULL); 1839 1840 if (TT.connected && !TT.from_ok) { 1841 struct nlmsghdr *mhdr = (struct nlmsghdr*)toybuf; 1842 struct rtmsg *msg = NLMSG_DATA(mhdr); 1843 int tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); 1844 struct rtattr *rta, *attr[RTA_MAX+1] = {0,}; 1845 1846 if (mhdr->nlmsg_type != RTM_NEWROUTE) error_exit("not a route?"); 1847 if (msglen < 0) error_exit("wrong len %d", msglen); 1848 1849 tvar = msglen; 1850 for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar)) 1851 if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta; 1852 1853 if (attr[RTA_PREFSRC]) { 1854 attr[RTA_PREFSRC]->rta_type = RTA_SRC; 1855 msg->rtm_src_len = 8*RTA_PAYLOAD(attr[RTA_PREFSRC]); 1856 } else if (!attr[RTA_SRC]) error_exit("can't connect the route"); 1857 1858 if (!odev && attr[RTA_OIF]) attr[RTA_OIF]->rta_type = 0; 1859 if (attr[RTA_GATEWAY]) attr[RTA_GATEWAY]->rta_type = 0; 1860 if (!idev && attr[RTA_IIF]) attr[RTA_IIF]->rta_type = 0; 1861 mhdr->nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK; 1862 mhdr->nlmsg_type = RTM_GETROUTE; 1863 mhdr->nlmsg_pid = 0; 1864 xclose(TT.sockfd); 1865 TT.sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 1866 send_nlmesg(0, 0, 0, mhdr, mhdr->nlmsg_len); 1867 filter_nlmesg(display_route_info, NULL); 1868 } 1869 return 0; 1870 } 1871 1872 static int route_show_flush(char **argv) 1873 { 1874 struct arglist cmd_objectlist[] = {{"protocol", 0}, {"dev", 1}, {"oif", 2}, 1875 {"iif", 3}, {"via", 4}, {"table", 5}, {"cache", 6}, {"from", 7}, 1876 {"to", 8}, {"all", 9}, {"root", 10}, {"match", 11}, {"exact", 12}, 1877 {"main", 13}, {NULL,-1}}; 1878 int family = TT.addressfamily, idx; 1879 struct { 1880 struct nlmsghdr mhdr; 1881 struct rtmsg msg; 1882 } request; 1883 1884 if (*argv[-1] == 'f') TT.flush = 1; 1885 if (TT.flush && !*argv) show_iproute_help(); 1886 1887 gfilter.tb = RT_TABLE_MAIN; 1888 for (; *argv; argv++) { 1889 switch (idx = substring_to_idx(*argv, cmd_objectlist)) { 1890 case 0: 1891 if (!*++argv) show_iproute_help(); 1892 if ((idx = idxfromRPDB(*argv,RPDB_rtprotos)) < 0) 1893 error_exit("Invalid argument protocol."); 1894 gfilter.proto = idx; 1895 break; 1896 case 1: 1897 case 2: 1898 case 3: 1899 { 1900 if (!*++argv) show_iproute_help(); 1901 int dev = get_ifaceindex(*argv, 1); 1902 1903 if (idx == 3) gfilter.idev = dev; 1904 else gfilter.odev = dev; 1905 } 1906 break; 1907 case 4: 1908 if (!*++argv) show_iproute_help(); 1909 parse_prefix(gfilter.rvia.addr, &gfilter.rvia.netmask, 1910 &gfilter.rvia.len, *argv, gfilter.rvia.family); 1911 if (gfilter.rvia.len) 1912 gfilter.rvia.family = ((gfilter.rvia.len == 4) ? 1913 AF_INET : AF_INET6); 1914 break; 1915 case 5: 1916 if (!*++argv) show_iproute_help(); 1917 idx = substring_to_idx(*argv, cmd_objectlist); 1918 if (idx == 6) gfilter.tb = -1; 1919 else if (idx == 9) gfilter.tb = 0; 1920 else if (idx != 13) { 1921 if ((gfilter.tb = idxfromRPDB(*argv, RPDB_rttables)) < 0) 1922 error_exit("table %s is invalid.", *argv); 1923 } 1924 break; 1925 case 6: 1926 gfilter.tb = -1; 1927 break; 1928 case 7: 1929 if (!*++argv) show_iproute_help(); 1930 idx = substring_to_idx(*argv, cmd_objectlist); 1931 if (idx < 0) if (!*++argv) show_iproute_help(); 1932 if (idx == 10) 1933 if (!*++argv) show_iproute_help(); 1934 parse_prefix(gfilter.rsrc.addr, &gfilter.rsrc.netmask, 1935 &gfilter.rsrc.len, *argv, gfilter.rsrc.family); 1936 if (gfilter.rsrc.len) 1937 gfilter.rsrc.family = ((gfilter.rsrc.len == 4) ? 1938 AF_INET : AF_INET6); 1939 else { 1940 if ((idx == 12 ||idx == 11) && !*++argv) show_iproute_help(); 1941 parse_prefix(gfilter.msrc.addr, &gfilter.msrc.netmask, 1942 &gfilter.msrc.len, *argv, gfilter.msrc.family); 1943 if (gfilter.msrc.len) 1944 gfilter.msrc.family = ((gfilter.msrc.len == 4) ? 1945 AF_INET : AF_INET6); 1946 if (idx != 11) gfilter.rsrc = gfilter.msrc; 1947 } 1948 break; 1949 case 8: 1950 idx = substring_to_idx(*argv, cmd_objectlist); 1951 if (idx != -1 && !*++argv) show_iproute_help(); 1952 default: // fallthrough 1953 if (idx == 10) { 1954 if (!*++argv) show_iproute_help(); 1955 parse_prefix(gfilter.rdst.addr, &gfilter.rdst.netmask, 1956 &gfilter.rdst.len, *argv, gfilter.rdst.family); 1957 if (gfilter.rdst.len) 1958 gfilter.rdst.family = ((gfilter.rdst.len == 4) ? 1959 AF_INET : AF_INET6); 1960 } 1961 else { 1962 if ((idx == 12 ||idx == 11) && !*++argv) show_iproute_help(); 1963 parse_prefix(gfilter.mdst.addr, &gfilter.mdst.netmask, 1964 &gfilter.mdst.len, *argv, gfilter.mdst.family); 1965 if (gfilter.mdst.len) 1966 gfilter.mdst.family = ((gfilter.mdst.len == 4) ? 1967 AF_INET : AF_INET6); 1968 if (idx != 11) gfilter.rdst = gfilter.mdst; 1969 } 1970 break; 1971 } 1972 } 1973 if (family == AF_UNSPEC && gfilter.tb) family = AF_INET; 1974 1975 if (TT.flush) { 1976 if (gfilter.tb < 0) { // flush table cache 1977 if (family != AF_INET6) { 1978 FILE *fp = xfopen("/proc/sys/net/ipv4/route/flush", "w"); 1979 1980 if (fwrite("-1",1,2,fp) < 2) error_exit("can't flush routing cache"); 1981 fclose(fp); 1982 } 1983 if (family == AF_INET) return 0; 1984 } 1985 } 1986 1987 memset(&request, 0, sizeof (request)); 1988 request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof (struct rtmsg)); 1989 request.mhdr.nlmsg_flags = NLM_F_REQUEST; 1990 request.mhdr.nlmsg_flags |= NLM_F_ROOT | NLM_F_MATCH; 1991 request.mhdr.nlmsg_type = RTM_GETROUTE; 1992 request.msg.rtm_family = family; 1993 if (gfilter.tb < 0) request.msg.rtm_flags = RTM_F_CLONED; 1994 send_nlmesg(0, 0, 0, (void*)&request, sizeof (request)); 1995 return (filter_nlmesg(display_route_info, NULL)); 1996 } 1997 1998 static int route_update(char **argv, unsigned int route_flags) 1999 { 2000 char mxbuf[256], *d = NULL; 2001 struct rtattr *mxrta = (void*)mxbuf; 2002 unsigned mxlock = 0, ok = 0; 2003 int idx; 2004 uint32_t addr[8] = {0,}, netmask = 0; 2005 uint8_t len = 0; 2006 2007 struct arglist cmd_objectlist[] = {{"src", 0}, {"via", 1}, {"mtu", 2}, 2008 {"lock", 3}, {"protocol", 4}, {"table", 5}, {"dev", 6}, {"oif", 7}, 2009 {"to", 8}, {"metric", 9}, {NULL,-1} 2010 }; 2011 enum { 2012 gtwy_ok = 1, 2013 dst_ok = 2, 2014 proto_ok = 4, 2015 type_ok = 8 2016 }; 2017 struct { 2018 struct nlmsghdr hdr; 2019 struct rtmsg msg; 2020 char buf[1024]; 2021 } req; 2022 2023 memset(&req, 0, sizeof(req)); 2024 req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 2025 req.hdr.nlmsg_flags = NLM_F_ACK| NLM_F_REQUEST | route_flags; 2026 req.hdr.nlmsg_type = TT.route_cmd; 2027 req.msg.rtm_family = AF_UNSPEC; 2028 req.msg.rtm_table = RT_TABLE_MAIN; 2029 req.msg.rtm_scope = RT_SCOPE_NOWHERE; 2030 2031 if (TT.route_cmd != RTM_DELROUTE) { 2032 req.msg.rtm_protocol = RTPROT_BOOT; 2033 req.msg.rtm_scope = RT_SCOPE_UNIVERSE; 2034 req.msg.rtm_type = RTN_UNICAST; 2035 } 2036 2037 mxrta->rta_type = RTA_METRICS; 2038 mxrta->rta_len = RTA_LENGTH(0); 2039 2040 for (; *argv; argv++) { 2041 idx = substring_to_idx(*argv, cmd_objectlist); 2042 if (!idx) { 2043 if (!*++argv) show_iproute_help(); 2044 parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family); 2045 if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6); 2046 add_string_to_rtattr(&req.hdr, sizeof(req), RTA_PREFSRC, addr, len); 2047 } else if (idx == 1) { 2048 ok |= gtwy_ok; 2049 if (!*++argv) show_iproute_help(); 2050 parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family); 2051 if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6); 2052 add_string_to_rtattr(&req.hdr, sizeof(req),RTA_GATEWAY, addr, len); 2053 } else if (idx == 2) { 2054 if (!*++argv) show_iproute_help(); 2055 if (substring_to_idx(*argv, cmd_objectlist ) == 3) { 2056 mxlock |= (1 << RTAX_MTU); 2057 if (!*++argv) show_iproute_help(); 2058 } 2059 idx = atolx(*argv); 2060 add_uint32_rtattr_to_buffer(mxrta, sizeof(mxbuf), RTAX_MTU, idx); 2061 } else if (idx == 4) { 2062 if (!*++argv) show_iproute_help(); 2063 if ((idx = idxfromRPDB(*argv,RPDB_rtprotos)) < 0) 2064 error_exit("Invalid argument protocol %s.",*argv); 2065 req.msg.rtm_protocol = idx; 2066 ok |= proto_ok; 2067 } else if (idx == 5) { 2068 if (!*++argv) show_iproute_help(); 2069 req.msg.rtm_table = idxfromRPDB(*argv, RPDB_rttables); 2070 } else if (idx == 6 || idx == 7) { 2071 if (!*++argv) show_iproute_help(); 2072 d = *argv; 2073 } else if (idx == 9) { 2074 unsigned long metric; 2075 unsigned int res; 2076 char* ptr; 2077 if (!*++argv) show_iproute_help(); 2078 metric = strtoul(*argv, &ptr, 0); 2079 if (!(!*ptr && metric <= 0xFFFFFFFFUL)) 2080 error_exit("Invalid argument metric %s.",*argv); 2081 else 2082 res = metric; 2083 add_string_to_rtattr(&req.hdr, sizeof(req), 2084 RTA_PRIORITY, (char*)&res, sizeof(res)); 2085 } else { 2086 if (idx == 8) 2087 if (!*++argv) show_iproute_help(); 2088 idx = substring_to_idx(*argv,rtmtypes); 2089 if (idx != -1) { 2090 if (!*++argv) show_iproute_help(); 2091 req.msg.rtm_type = idx; 2092 ok |= type_ok; 2093 } 2094 if (ok & dst_ok) error_exit("Duplicate argument 'to'"); 2095 parse_prefix(addr, &netmask, &len, *argv, req.msg.rtm_family); 2096 if (len) req.msg.rtm_family = ((len == 4) ? AF_INET : AF_INET6); 2097 req.msg.rtm_dst_len = netmask; 2098 ok |= dst_ok; 2099 if (len) add_string_to_rtattr(&req.hdr, sizeof(req),RTA_DST, addr, len); 2100 } 2101 } 2102 2103 if (d) { 2104 idx = get_ifaceindex(d,1); 2105 add_string_to_rtattr(&req.hdr, sizeof(req), 2106 RTA_OIF, (char*)&idx, sizeof(idx)); 2107 } 2108 if (mxrta->rta_len > RTA_LENGTH(0)) { 2109 if (mxlock) 2110 add_uint32_rtattr_to_buffer(mxrta, sizeof(mxbuf), RTAX_LOCK, mxlock); 2111 add_string_to_rtattr(&req.hdr, sizeof(req), 2112 RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta)); 2113 } 2114 2115 if (req.msg.rtm_type == RTN_LOCAL || req.msg.rtm_type == RTN_NAT) 2116 req.msg.rtm_scope = RT_SCOPE_HOST; 2117 else if (req.msg.rtm_type == RTN_BROADCAST||req.msg.rtm_type == RTN_MULTICAST 2118 || req.msg.rtm_type == RTN_ANYCAST) 2119 req.msg.rtm_scope = RT_SCOPE_LINK; 2120 else if (req.msg.rtm_type == RTN_UNICAST || req.msg.rtm_type == RTN_UNSPEC) { 2121 if (TT.route_cmd == RTM_DELROUTE) 2122 req.msg.rtm_scope = RT_SCOPE_NOWHERE; 2123 else if (!(ok & gtwy_ok)) 2124 req.msg.rtm_scope = RT_SCOPE_LINK; 2125 } 2126 if (req.msg.rtm_family == AF_UNSPEC) req.msg.rtm_family = AF_INET; 2127 send_nlmesg(0, 0, 0, &req, sizeof(req)); 2128 filter_nlmesg(NULL, NULL); 2129 return 0; 2130 } 2131 2132 static int iproute(char **argv) 2133 { 2134 int idx = 1; 2135 struct arglist cmd_objectlist1[] = {{"add", 0}, {"append", 1},{"change", 2}, 2136 {"chg", 3},{"delete",4}, {"get", 5}, {"list", 6}, {"show", 7}, 2137 {"prepend", 8},{"replace", 9},{"test", 10}, {"flush", 11},{NULL,-1}}; 2138 2139 TT.route_cmd = RTM_NEWROUTE; 2140 switch (idx = substring_to_idx(*argv , cmd_objectlist1)) { 2141 case 0: // add 2142 return route_update(++argv , NLM_F_CREATE|NLM_F_EXCL); 2143 case 1: // append 2144 return route_update(++argv , NLM_F_CREATE|NLM_F_APPEND); 2145 case 2: // change 2146 case 3: // chg 2147 return route_update(++argv , NLM_F_REPLACE); 2148 case 4: // delete 2149 TT.route_cmd = RTM_DELROUTE; 2150 return route_update(++argv , RTM_DELROUTE); 2151 case 5: 2152 return route_get(++argv); 2153 case 6: 2154 case 7: 2155 return route_show_flush(++argv); 2156 case 8: // prepend 2157 return route_update(++argv , NLM_F_CREATE); 2158 case 9: // replace 2159 return route_update(++argv , NLM_F_CREATE|NLM_F_REPLACE); 2160 case 10: // test 2161 return route_update(++argv , NLM_F_EXCL); 2162 case 11: // flush 2163 return route_show_flush(++argv); 2164 default: 2165 if (!*argv) return route_show_flush(argv); 2166 else show_iproute_help(); 2167 } 2168 return 0; // non reachable code. 2169 } 2170 2171 2172 // =========================================================================== 2173 // code for ip rule. 2174 // =========================================================================== 2175 static void show_iprule_help(void) 2176 { 2177 char *errmsg = "usage: ip rule [ list | add | del ] SELECTOR ACTION\n" 2178 "SELECTOR := [ from PREFIX ] [ to PREFIX ] [pref NUMBER] [ tos TOS ]\n" 2179 " [ fwmark FWMARK] [ dev/iif STRING ] [type TYPE]\n" 2180 "ACTION := [ table TABLE_ID ] [ realms [SRCREALM/]DSTREALM ]"; 2181 2182 error_exit(errmsg); 2183 } 2184 2185 static int ruleupdate(char **argv) 2186 { 2187 int8_t idx, tflag = 0, opt = (*argv[-1] == 'a') ? RTM_NEWRULE : RTM_DELRULE; 2188 struct arglist options[] = {{"from", 0}, {"to", 1}, {"preference", 2}, 2189 {"order", 2}, {"priority", 2}, {"tos", 3}, {"dsfield", 3}, {"fwmark", 4}, 2190 {"realms", 5}, {"table", 6}, {"lookup", 6}, {"dev", 7}, {"iif", 7}, 2191 {"nat", 8}, {"map-to", 8}, {"type", 9}, {"help", 10}, {NULL, -1}}; 2192 struct { 2193 struct nlmsghdr mhdr; 2194 struct rtmsg msg; 2195 char buf[1024]; 2196 } request; 2197 2198 memset(&request, 0, sizeof(request)); 2199 request.mhdr.nlmsg_type = opt; 2200 request.mhdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 2201 request.mhdr.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | 2202 ((opt == RTM_DELRULE) ? 0 : NLM_F_CREATE | NLM_F_EXCL); 2203 request.msg.rtm_family = TT.addressfamily; 2204 request.msg.rtm_protocol = RTPROT_BOOT; 2205 request.msg.rtm_scope = RT_SCOPE_UNIVERSE; 2206 request.msg.rtm_table = 0; 2207 request.msg.rtm_type = ((opt == RTM_DELRULE) ? RTN_UNSPEC : RTN_UNICAST); 2208 2209 for (; *argv; argv++) { 2210 switch ((idx = substring_to_idx(*argv, options))) { 2211 case 0: 2212 case 1: 2213 { // e.g. from IP/Netmask and to IP/Netmask. 2214 uint32_t addr[4] = {0,}, netmask = 0; 2215 uint8_t len = 0, *tmp; 2216 2217 if (!*++argv) error_exit("'%s': Missing Prefix", argv[-1]); 2218 parse_prefix(addr, &netmask, &len, *argv, request.msg.rtm_family); 2219 2220 tmp = idx ? &request.msg.rtm_dst_len : &request.msg.rtm_src_len; 2221 if (!netmask) *tmp = 0; 2222 else *tmp = netmask; 2223 2224 add_string_to_rtattr(&request.mhdr, sizeof(request), 2225 (idx ? RTA_DST : RTA_SRC), addr, len); 2226 } 2227 break; 2228 case 2: 2229 case 4: 2230 { // e.g. Preference p# and fwmark MARK 2231 uint32_t pref; 2232 char *ptr; 2233 2234 if (!*++argv) 2235 error_exit("Missing %s", (idx == 2) ? "Preference" : "fwmark"); 2236 pref = strtoul(*argv, &ptr, 0); 2237 if (!ptr || (ptr == *argv) || *ptr || pref > 0xFFFFFFFFUL) 2238 error_exit("Invalid %s", (idx == 2) ? "Preference" : "fwmark"); 2239 add_string_to_rtattr(&request.mhdr, sizeof(request), 2240 ((idx == 2) ? RTA_PRIORITY : RTA_PROTOINFO), 2241 (void *)&pref, sizeof(uint32_t)); 2242 } 2243 break; 2244 case 3: 2245 { 2246 uint32_t tos; 2247 if (!*++argv) error_exit("Missing TOS key"); 2248 if ((tos = idxfromRPDB(*argv, RPDB_rtdsfield)) < 0) 2249 error_exit("Invalid TOS"); 2250 request.msg.rtm_tos = tos; 2251 } 2252 break; 2253 case 5: 2254 { // e.g. realms FROM_realm/TO_realm 2255 uint32_t realms = 0; 2256 int ret; 2257 char *ptr; 2258 2259 if (!*++argv) error_exit("Missing REALMSID"); 2260 if ((ptr = strchr(*argv, '/'))) { 2261 *ptr = 0; 2262 if ((ret = idxfromRPDB(*argv, RPDB_rtrealms)) < 0) 2263 error_exit("Invalid realms"); 2264 realms = ret; 2265 realms <<= 16; 2266 *ptr++ = '/'; 2267 } else ptr = *argv; 2268 if ((ret = idxfromRPDB(ptr, RPDB_rtrealms)) < 0) 2269 error_exit("Invalid realms"); 2270 realms |= ret; 2271 add_string_to_rtattr(&request.mhdr, sizeof(request), 2272 RTA_FLOW, (void *)&realms, sizeof(uint32_t)); 2273 } 2274 break; 2275 case 6: 2276 { // e.g. table tid/tableName 2277 int tid; 2278 if (!*++argv) error_exit("Missing TableID"); 2279 if ((tid = idxfromRPDB(*argv, RPDB_rttables)) < 0) 2280 error_exit("Invalid TID"); 2281 request.msg.rtm_table = tid; 2282 tflag = 1; 2283 } 2284 break; 2285 case 7: 2286 { 2287 if (!*++argv) error_exit("Missing dev/iif NAME"); 2288 add_string_to_rtattr(&request.mhdr, sizeof(request), 2289 RTA_IIF, *argv, strlen(*argv)+1); 2290 } 2291 break; 2292 case 8: 2293 { 2294 uint32_t addr[4] = {0,}; 2295 uint8_t af = AF_UNSPEC; 2296 2297 if (!*++argv) error_exit("Missing nat/map-to ADDRESS"); 2298 if (get_prefix(addr, &af /* Un-used variable */, *argv, AF_INET)) 2299 error_exit("Invalid mapping Address"); 2300 2301 add_string_to_rtattr(&request.mhdr, sizeof(request), 2302 RTA_GATEWAY, addr, sizeof(uint32_t)); 2303 request.msg.rtm_type = RTN_NAT; 2304 } 2305 break; 2306 case 9: 2307 { 2308 if (!*++argv) error_exit("TYPE Missing"); 2309 request.msg.rtm_type = rtmtype_str2idx(*argv); 2310 } 2311 break; 2312 case 10: 2313 show_iprule_help(); 2314 break; // Unreachable code. 2315 default: 2316 error_exit("Invalid argument '%s'", *argv); 2317 break; // Unreachable code. 2318 } 2319 } 2320 2321 if (!request.msg.rtm_family) request.msg.rtm_family = AF_INET; 2322 if (!tflag && opt == RTM_NEWRULE) request.msg.rtm_table = RT_TABLE_MAIN; 2323 2324 send_nlmesg(0, 0, 0, &request, sizeof(request)); 2325 return (filter_nlmesg(NULL, NULL)); 2326 } 2327 2328 static int show_rules(struct nlmsghdr *mhdr, 2329 char **argv __attribute__ ((__unused__))) 2330 { 2331 struct rtmsg *msg = NLMSG_DATA(mhdr); 2332 struct rtattr *rta, *attr[RTA_MAX+1] = {0,}; 2333 int32_t tvar, msglen = mhdr->nlmsg_len - NLMSG_LENGTH(sizeof(struct rtmsg)); 2334 int hlen = ((msg->rtm_family == AF_INET) ? 32 2335 : ((msg->rtm_family == AF_INET6) ? 128 : -1)); 2336 2337 if (mhdr->nlmsg_type != RTM_NEWRULE) return 0; 2338 if (msglen < 0) return 1; 2339 2340 tvar = msglen; 2341 for (rta = RTM_RTA(msg); RTA_OK(rta, tvar); rta=RTA_NEXT(rta, tvar)) 2342 if (rta->rta_type <= RTA_MAX) attr[rta->rta_type] = rta; 2343 2344 if (tvar) error_msg("deficit %d, rtalen = %d!", tvar, rta->rta_len); 2345 2346 printf("%u:\tfrom ", attr[RTA_PRIORITY] ? 2347 *(unsigned *)RTA_DATA(attr[RTA_PRIORITY]) : 0); 2348 2349 if (attr[RTA_SRC]) { 2350 printf("%s", (msg->rtm_family == AF_INET || msg->rtm_family == AF_INET6) 2351 ? inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_SRC]), 2352 toybuf, sizeof(toybuf)) 2353 : "???"); 2354 (msg->rtm_src_len != hlen) ? printf("/%u", msg->rtm_src_len) : 0; 2355 } else msg->rtm_src_len ? printf("0/%d", msg->rtm_src_len) : printf("all"); 2356 2357 xputc(' '); 2358 if (attr[RTA_DST]) { 2359 printf("to %s", (msg->rtm_family == AF_INET || msg->rtm_family == AF_INET6) 2360 ? inet_ntop(msg->rtm_family, RTA_DATA(attr[RTA_DST]), 2361 toybuf, sizeof(toybuf)) : "???"); 2362 (msg->rtm_dst_len != hlen) ? printf("/%u", msg->rtm_dst_len) : xputc(' '); 2363 } else if (msg->rtm_dst_len) 2364 printf("to 0/%d ", msg->rtm_dst_len); 2365 2366 if (msg->rtm_tos) 2367 printf("tos %s ", namefromRPDB(msg->rtm_tos, RPDB_rtdsfield)); 2368 2369 if (attr[RTA_PROTOINFO]) 2370 printf("fwmark %#x ", *(uint32_t*)RTA_DATA(attr[RTA_PROTOINFO])); 2371 2372 if (attr[RTA_IIF]) printf("iif %s ", (char*)RTA_DATA(attr[RTA_IIF])); 2373 2374 if (msg->rtm_table) 2375 printf("lookup %s ", namefromRPDB(msg->rtm_table, RPDB_rttables)); 2376 2377 if (attr[RTA_FLOW]) { 2378 u_int32_t from, to = *(u_int32_t *)RTA_DATA(attr[RTA_FLOW]); 2379 char *format = "realms %s/"; 2380 2381 to = (from = (to >> 16)) & 0xFFFF; 2382 format = (from ? format: "%s"); 2383 printf(format, namefromRPDB((from ? from : to), RPDB_rtrealms)); 2384 } 2385 2386 if (msg->rtm_type == RTN_NAT) { 2387 if (!attr[RTA_GATEWAY]) printf("masquerade"); 2388 else printf("map-to %s ", inet_ntop(msg->rtm_family, 2389 RTA_DATA(attr[RTA_GATEWAY]), toybuf, sizeof(toybuf))); 2390 } else if (msg->rtm_type != RTN_UNICAST) 2391 printf("%s", rtmtype_idx2str(msg->rtm_type)); 2392 2393 xputc('\n'); 2394 return 0; 2395 } 2396 2397 static int rulelist(char **argv) 2398 { 2399 if (*argv) { 2400 error_msg("'ip rule show' does not take any arguments."); 2401 return 1; 2402 } 2403 send_nlmesg(RTM_GETRULE, NLM_F_ROOT | NLM_F_MATCH | NLM_F_REQUEST, 2404 ((TT.addressfamily != AF_UNSPEC) ? TT.addressfamily : AF_INET), NULL, 0); 2405 return filter_nlmesg(show_rules, argv); 2406 } 2407 2408 static int iprule(char **argv) 2409 { 2410 int idx; 2411 struct arglist options[] = {{"add", 0}, {"delete", 0}, {"list", 1}, 2412 {"show", 1}, {NULL, -1}}; 2413 cmdobj ipcmd, cmdobjlist[] = {ruleupdate, rulelist}; 2414 2415 if (!*argv) idx = 1; 2416 else if ((idx = substring_to_idx(*argv++, options)) == -1) 2417 show_iprule_help(); 2418 ipcmd = cmdobjlist[idx]; 2419 return ipcmd(argv); 2420 } 2421 //============================================================================ 2422 // code for ip tunnel. 2423 //============================================================================ 2424 static void show_iptunnel_help(void) 2425 { 2426 char *errmsg = "usage: iptunnel { add | change | del | show } [NAME]\n" 2427 " [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n" 2428 " [[i|o]seq] [[i|o]key KEY] [[i|o]csum] [ttl TTL]\n" 2429 " [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]"; 2430 2431 error_exit(errmsg); 2432 } 2433 2434 static int tnl_ioctl(char *dev, int rtype, struct ip_tunnel_parm *ptnl) 2435 { 2436 struct ifreq req; 2437 int fd, ret = 0; 2438 2439 if ((rtype == SIOCCHGTUNNEL || rtype == SIOCDELTUNNEL) && *ptnl->name) 2440 xstrncpy(req.ifr_name, ptnl->name, IF_NAMESIZE); 2441 else xstrncpy(req.ifr_name, dev, IF_NAMESIZE); 2442 2443 if (rtype != SIOCGIFHWADDR) req.ifr_ifru.ifru_data = (void*)ptnl; 2444 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 2445 2446 if (rtype == SIOCGETTUNNEL) ret = ioctl(fd, rtype, &req); 2447 else if (rtype == SIOCGIFHWADDR) 2448 ret = (ioctl(fd, rtype, &req) < 0) ? -1 : req.ifr_addr.sa_family; 2449 else xioctl(fd, rtype, &req); 2450 2451 close(fd); 2452 return ret; 2453 } 2454 2455 static int display_tunnel(struct ip_tunnel_parm *ptnl) 2456 { 2457 char rmt_addr[64], lcl_addr[64], ikey_str[64], okey_str[64]; 2458 2459 printf("%s: %s/ip", ptnl->name, ptnl->iph.protocol == IPPROTO_IPIP ? "ip" : 2460 (ptnl->iph.protocol == IPPROTO_GRE ? "gre" : 2461 (ptnl->iph.protocol == IPPROTO_IPV6 ? "ipv6" : "unknown"))); 2462 printf(" remote %s local %s ", ptnl->iph.daddr ? 2463 inet_ntop(AF_INET, &ptnl->iph.daddr, rmt_addr, sizeof(rmt_addr)) : "any", 2464 ptnl->iph.saddr ? inet_ntop(AF_INET, &ptnl->iph.saddr, lcl_addr, 2465 sizeof(lcl_addr)) : "any"); 2466 if (ptnl->link) { 2467 struct ifreq req; 2468 int fd; 2469 2470 req.ifr_ifindex = ptnl->link; 2471 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 2472 if (ioctl(fd, SIOCGIFNAME, &req) < 0) perror_msg("SIOCGIFNAME"); 2473 else printf(" dev %s ", req.ifr_name); 2474 close(fd); 2475 } 2476 if (ptnl->iph.ttl) printf(" ttl %d ", ptnl->iph.ttl); 2477 else printf(" ttl inherit "); 2478 2479 if (ptnl->iph.tos) { 2480 printf(" tos"); 2481 if (ptnl->iph.tos & 1) printf(" inherit"); 2482 if (ptnl->iph.tos & ~1) printf("%c%s ", ptnl->iph.tos & 1 ? '/' : ' ', 2483 namefromRPDB((ptnl->iph.tos & ~1), RPDB_rtdsfield)); 2484 } 2485 if (!(ptnl->iph.frag_off & htons(IP_DF))) printf(" nopmtudisc"); 2486 inet_ntop(AF_INET, &ptnl->i_key, ikey_str, sizeof(ikey_str)); 2487 if ((ptnl->i_flags & GRE_KEY) && (ptnl->o_flags & GRE_KEY) 2488 && ptnl->o_key == ptnl->i_key) printf(" key %s", ikey_str); 2489 else if ((ptnl->i_flags | ptnl->o_flags) & GRE_KEY) { 2490 inet_ntop(AF_INET, &ptnl->o_key, okey_str, sizeof(okey_str)); 2491 if (ptnl->i_flags & GRE_KEY) printf(" ikey %s ", ikey_str); 2492 if (ptnl->o_flags & GRE_KEY) printf(" okey %s ", okey_str); 2493 } 2494 if (ptnl->i_flags & GRE_SEQ) printf("\n Drop packets out of sequence.\n"); 2495 if (ptnl->i_flags & GRE_CSUM) 2496 printf("\n Checksum in received packet is required."); 2497 if (ptnl->o_flags & GRE_SEQ) printf("\n Sequence packets on output."); 2498 if (ptnl->o_flags & GRE_CSUM) printf("\n Checksum output packets."); 2499 xputc('\n'); 2500 return 0; 2501 } 2502 2503 static int read_tunnel(struct ip_tunnel_parm *ptnl) 2504 { 2505 int count = 0; 2506 char iface[IF_NAMESIZE]; 2507 struct ip_tunnel_parm iptnl; 2508 FILE *fp = xfopen("/proc/net/dev", "r"); 2509 2510 while (fgets(toybuf, sizeof(toybuf), fp)) { 2511 char *ptr; 2512 int ret; 2513 2514 if (count++ < 2) continue; // 1st two lines are header. 2515 2516 ptr = strchr(toybuf, ':'); 2517 if (!ptr || (*ptr++ = 0, sscanf(toybuf, "%s", iface) != 1)) 2518 error_exit("invalid format of '/proc/net/dev'"); 2519 if (*ptnl->name && strcmp(ptnl->name, iface)) continue; 2520 if ((ret = tnl_ioctl(iface, SIOCGIFHWADDR, &iptnl)) < 0) { 2521 error_msg("failed to get type of '%s'", iface); 2522 continue; 2523 } 2524 if (ret != ARPHRD_TUNNEL && ret != ARPHRD_SIT && 2525 ret != ARPHRD_IPGRE) continue; 2526 2527 memset(&iptnl, 0, sizeof(iptnl)); 2528 if (tnl_ioctl(iface, SIOCGETTUNNEL, &iptnl) < 0) continue; 2529 if ((ptnl->link && iptnl.link != ptnl->link) || (*ptnl->name && 2530 strcmp(iptnl.name, ptnl->name)) || (ptnl->iph.daddr && 2531 iptnl.iph.daddr != ptnl->iph.daddr) || (ptnl->iph.saddr && 2532 iptnl.iph.saddr != ptnl->iph.saddr) || (ptnl->i_key && 2533 iptnl.i_key != ptnl->i_key)) continue; 2534 display_tunnel(&iptnl); 2535 } 2536 fclose(fp); 2537 return 0; 2538 } 2539 2540 static void parse_iptunnel_args(struct ip_tunnel_parm *ptnl, char **argv, 2541 int ipt_opt_idx) 2542 { 2543 int idx; 2544 uint8_t af = AF_INET; 2545 uint32_t addr = 0; 2546 struct arglist opts[] = { {"mode", 0}, {"key", 1}, {"ikey", 2}, 2547 {"okey", 3}, {"seq", 4}, {"iseq", 5}, {"oseq", 6}, {"csum", 7}, 2548 {"icsum", 8}, {"ocsum", 9}, {"nopmtudisc", 10}, {"pmtudisc", 11}, 2549 {"remote", 12}, {"local", 13},{"dev", 14}, {"ttl", 15}, {"tos", 16}, 2550 {"dsfield", 17}, {"name", 18}, {NULL, -1} 2551 }; 2552 2553 ptnl->iph.version = 4; // The value indicates the version of IP (4 or 6) 2554 ptnl->iph.ihl = 5; // Minimum Internet Header Length 2555 // frag_off is measured in units of 8 octets (64 bits) 2556 ptnl->iph.frag_off = htons(IP_DF); 2557 if (*argv && ipt_opt_idx <= 2 && string_to_idx(*argv, opts) == -1) { 2558 xstrncpy(ptnl->name, *argv, IF_NAMESIZE); 2559 if (ipt_opt_idx == 1) { 2560 struct ip_tunnel_parm iptnl_old; 2561 2562 memset(&iptnl_old, 0, sizeof(iptnl_old)); 2563 tnl_ioctl(ptnl->name, SIOCGETTUNNEL, &iptnl_old); 2564 *ptnl = iptnl_old; 2565 } 2566 argv++; 2567 } 2568 for (; *argv; argv++, addr = 0) { 2569 switch (idx = string_to_idx(*argv, opts)) { 2570 case 0: 2571 if (!*++argv) error_exit("mode is missing"); 2572 if ((!strcmp("ipip", *argv) || !strcmp("ip/ip", *argv))) 2573 ptnl->iph.protocol = IPPROTO_IPIP; 2574 else if ((!strcmp("gre", *argv) || !strcmp("gre/ip", *argv))) 2575 ptnl->iph.protocol = IPPROTO_GRE; 2576 else if ((!strcmp("sit", *argv) || !strcmp("ipv6/ip", *argv))) 2577 ptnl->iph.protocol = IPPROTO_IPV6; 2578 else show_iptunnel_help(); 2579 break; 2580 case 1: 2581 case 2: 2582 case 3: 2583 { 2584 struct addrinfo *info, hint; 2585 int ret; 2586 2587 if (!*++argv) error_exit("key value is missing"); 2588 memset(&hint, 0, sizeof(hint)); 2589 hint.ai_family = AF_INET; 2590 ret = getaddrinfo(*argv, NULL, &hint, &info); 2591 if (ret || !info) error_exit("invalid argument to key"); 2592 freeaddrinfo(info); 2593 2594 if (strchr(*argv, '.')) { 2595 if (get_prefix(&addr, &af, *argv, AF_INET)) 2596 error_exit("invalid key '%s'", *argv); 2597 } else { 2598 unsigned key_val; 2599 2600 sscanf(*argv, "%u", &key_val); 2601 addr = htonl(key_val); 2602 } 2603 if (idx == 1) { 2604 ptnl->i_flags |= GRE_KEY; 2605 ptnl->o_flags |= GRE_KEY; 2606 ptnl->i_key = ptnl->o_key = addr; 2607 } else if (idx == 2) { 2608 ptnl->i_flags |= GRE_KEY; 2609 ptnl->i_key = addr; 2610 } else { 2611 ptnl->o_flags |= GRE_KEY; 2612 ptnl->o_key = addr; 2613 } 2614 } 2615 break; 2616 case 4: 2617 ptnl->i_flags |= GRE_SEQ; 2618 ptnl->o_flags |= GRE_SEQ; 2619 break; 2620 case 5: 2621 ptnl->i_flags |= GRE_SEQ; 2622 break; 2623 case 6: 2624 ptnl->o_flags |= GRE_SEQ; 2625 break; 2626 case 7: 2627 ptnl->i_flags |= GRE_CSUM; 2628 ptnl->o_flags |= GRE_CSUM; 2629 break; 2630 case 8: 2631 ptnl->i_flags |= GRE_CSUM; 2632 break; 2633 case 9: 2634 ptnl->o_flags |= GRE_CSUM; 2635 break; 2636 case 10: 2637 ptnl->iph.frag_off = 0; 2638 break; 2639 case 11: 2640 ptnl->iph.frag_off = htons(IP_DF); 2641 break; 2642 case 12: 2643 case 13: 2644 if (!*++argv) error_exit("remote/local address is missing"); 2645 if (get_prefix(&addr, &af, *argv, AF_INET)) 2646 error_exit("invalid remote/local address '%s'", *argv); 2647 (idx == 12) ? (ptnl->iph.daddr = addr) : (ptnl->iph.saddr = addr); 2648 break; 2649 case 14: 2650 if (!*++argv) error_exit("device name is missing"); 2651 else { 2652 struct ifreq req; 2653 int fd; 2654 2655 xstrncpy(req.ifr_name, *argv, IFNAMSIZ); 2656 fd = xsocket(AF_INET, SOCK_DGRAM, 0); 2657 xioctl(fd, SIOCGIFINDEX, &req); 2658 close(fd); 2659 ptnl->link = req.ifr_ifindex; 2660 } 2661 break; 2662 case 15: 2663 if (!*++argv) error_exit("ttl value is missing"); 2664 if (strcmp(*argv, "inherit")) 2665 ptnl->iph.ttl = atolx_range(*argv, 0, 255); 2666 break; 2667 case 16: 2668 case 17: 2669 if (!*++argv) error_exit("tos value is missing"); 2670 if (strcmp(*argv, "inherit")) { 2671 char *ptr; 2672 unsigned long tval = strtoul(*argv, &ptr, 16); 2673 2674 if (tval > 255) error_exit("invalid tos value '%s'", *argv); 2675 if (*ptr) { 2676 int ret; 2677 2678 if ((ret = idxfromRPDB(*argv, RPDB_rtdsfield)) < 0) 2679 error_exit("invalid tos value"); 2680 ptnl->iph.tos = ret; 2681 } else ptnl->iph.tos = tval; 2682 } else ptnl->iph.tos = 1; 2683 break; 2684 case 18: 2685 if (*ptnl->name) error_exit("invalid tunnel"); 2686 else { 2687 if (!*++argv) error_exit("name is missing"); 2688 xstrncpy(ptnl->name, *argv, IF_NAMESIZE); 2689 } 2690 break; 2691 default: 2692 if (*ptnl->name) error_exit("invalid tunnel"); 2693 xstrncpy(ptnl->name, *argv, IF_NAMESIZE); 2694 break; 2695 } 2696 } 2697 if (ptnl->iph.protocol == IPPROTO_IPIP || 2698 ptnl->iph.protocol == IPPROTO_IPV6) { 2699 if ((ptnl->i_flags & GRE_KEY) || (ptnl->o_flags & GRE_KEY)) 2700 error_exit("[i|o]key is allowed with gre only"); 2701 if ((ptnl->i_flags & GRE_SEQ) || (ptnl->o_flags & GRE_SEQ)) 2702 error_exit("[i|o]seq is allowed with gre only"); 2703 if ((ptnl->i_flags & GRE_CSUM) || (ptnl->o_flags & GRE_CSUM)) 2704 error_exit("[i|o]csum is allowed with gre only"); 2705 } 2706 if (!ptnl->i_key && IN_MULTICAST(ntohl(ptnl->iph.daddr))) { 2707 ptnl->i_key = ptnl->iph.daddr; 2708 ptnl->i_flags |= GRE_KEY; 2709 } 2710 if (!ptnl->o_key && IN_MULTICAST(ntohl(ptnl->iph.daddr))) { 2711 ptnl->o_key = ptnl->iph.daddr; 2712 ptnl->o_flags |= GRE_KEY; 2713 } 2714 if (IN_MULTICAST(ntohl(ptnl->iph.daddr)) && !ptnl->iph.saddr) 2715 error_exit("broadcast tunnel requires a source address"); 2716 } 2717 2718 static int tunnellist(char **argv) 2719 { 2720 struct ip_tunnel_parm iptnl; 2721 int ret = 0; 2722 2723 memset(&iptnl, 0, sizeof(iptnl)); 2724 parse_iptunnel_args(&iptnl, argv, 3); 2725 2726 if (iptnl.iph.protocol == IPPROTO_IPIP) 2727 ret = tnl_ioctl(*iptnl.name ? iptnl.name : "tunl0", SIOCGETTUNNEL, &iptnl); 2728 else if (iptnl.iph.protocol == IPPROTO_GRE) 2729 ret = tnl_ioctl(*iptnl.name ? iptnl.name : "gre0", SIOCGETTUNNEL, &iptnl); 2730 else if (iptnl.iph.protocol == IPPROTO_IPV6) 2731 ret = tnl_ioctl(*iptnl.name ? iptnl.name : "sit0", SIOCGETTUNNEL, &iptnl); 2732 else return read_tunnel(&iptnl); 2733 2734 if (ret < 0) { 2735 perror_msg("SIOCGETTUNNEL"); 2736 return ret; 2737 } else return display_tunnel(&iptnl); 2738 } 2739 2740 // Performing add, change, & delete tunnel action, according to passed req_type 2741 static int tunnelupdate(char **argv) 2742 { 2743 struct ip_tunnel_parm iptnl; 2744 int idx = 2, rtype = SIOCDELTUNNEL; 2745 2746 if (*argv[-1] == 'a') { 2747 idx = 0; 2748 rtype = SIOCADDTUNNEL; 2749 } else if (*argv[-1] == 'c') { 2750 idx = 1; 2751 rtype = SIOCCHGTUNNEL; 2752 } 2753 2754 memset(&iptnl, 0, sizeof(iptnl)); 2755 parse_iptunnel_args(&iptnl, argv, idx); 2756 if (idx != 2 && iptnl.iph.ttl && !(iptnl.iph.frag_off)) 2757 error_exit("ttl > 0 and nopmtudisc are incompatible"); 2758 if (iptnl.iph.protocol == IPPROTO_IPIP) 2759 return (tnl_ioctl("tunl0", rtype, &iptnl) < 0) ? 1 : 0; 2760 else if (iptnl.iph.protocol == IPPROTO_GRE) 2761 return (tnl_ioctl("gre0", rtype, &iptnl) < 0) ? 1 : 0; 2762 else if (iptnl.iph.protocol == IPPROTO_IPV6) 2763 return (tnl_ioctl("sit0", rtype, &iptnl) < 0) ? 1 : 0; 2764 else { 2765 if (idx != 2) error_exit("invalid tunnel mode"); 2766 return (tnl_ioctl(iptnl.name, rtype, &iptnl) < 0) ? 1 : 0; 2767 } 2768 } 2769 2770 static int iptunnel(char **argv) 2771 { 2772 int idx; 2773 struct arglist opts[] = {{"add", 0}, {"change", 0}, {"del", 0}, 2774 {"delete", 0}, {"show", 1}, {"list", 1}, {"lst", 1}, {NULL, -1} 2775 }; 2776 cmdobj ipcmd, cmdobjlist[] = {tunnelupdate, tunnellist}; 2777 2778 if (!*argv) idx = 1; 2779 else if ((idx = substring_to_idx(*argv++, opts)) == -1) 2780 show_iptunnel_help(); 2781 ipcmd = cmdobjlist[idx]; 2782 return ipcmd(argv); 2783 } 2784 2785 // =========================================================================== 2786 // Common code, which is used for all ip options. 2787 // =========================================================================== 2788 2789 // Parse netlink messages and call input callback handler for action 2790 static int filter_nlmesg(int (*fun)(struct nlmsghdr *mhdr, char **argv), 2791 char **argv) 2792 { 2793 while (1) { 2794 struct nlmsghdr *mhdr; 2795 int msglen = recv(TT.sockfd, TT.gbuf, MESG_LEN, 0); 2796 2797 if ((msglen < 0) && (errno == EINTR || errno == EAGAIN)) continue; 2798 else if (msglen < 0) { 2799 error_msg("netlink receive error %s", strerror(errno)); 2800 return 1; 2801 } else if (!msglen) { 2802 error_msg("EOF on netlink"); 2803 return 1; 2804 } 2805 2806 for (mhdr = (struct nlmsghdr*)TT.gbuf; NLMSG_OK(mhdr, msglen); 2807 mhdr = NLMSG_NEXT(mhdr, msglen)) { 2808 int err; 2809 if (mhdr->nlmsg_pid != getpid()) 2810 continue; 2811 switch (mhdr->nlmsg_type) { 2812 case NLMSG_DONE: 2813 return 0; 2814 case NLMSG_ERROR: 2815 { 2816 struct nlmsgerr *merr = (struct nlmsgerr*)NLMSG_DATA(mhdr); 2817 2818 if (merr->error == 0) return 0; 2819 if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct nlmsgerr))) 2820 error_msg("ERROR truncated"); 2821 else { 2822 errno = -merr->error; 2823 perror_msg("RTNETLINK answers"); 2824 } 2825 return 1; 2826 } 2827 default: 2828 if (fun && (err = fun(mhdr, argv))) return err; 2829 break; 2830 } 2831 } // End of for loop. 2832 } // End of while loop. 2833 return 0; 2834 } 2835 2836 void ip_main(void) 2837 { 2838 char **optargv = toys.argv; 2839 int idx, isip = !(toys.which->name[2]); //1 -> if only ip 2840 cmdobj ipcmd, cmdobjlist[] = {ipaddr, iplink, iproute, iprule, iptunnel}; 2841 2842 for (++optargv; *optargv; ++optargv) { 2843 char *ptr = *optargv; 2844 struct arglist ip_options[] = {{"oneline", 0}, {"family", 1}, 2845 {"4", 1}, {"6", 1}, {"0", 1}, {"stats", 2}, {NULL, -1}}; 2846 2847 if (*ptr != '-') break; 2848 else if ((*(ptr+1) == '-') && (*(ptr+2))) ptr +=2; 2849 //escape "--" and stop ip arg parsing. 2850 else if ((*(ptr+1) == '-') && (!*(ptr+2))) { 2851 *ptr +=1; 2852 break; 2853 } else ptr +=1; 2854 switch (substring_to_idx(ptr, ip_options)) { 2855 case 0: TT.singleline = 1; 2856 break; 2857 case 1: { 2858 if (isdigit(*ptr)) { 2859 long num = atolx(ptr); 2860 if (num == 4) TT.addressfamily = AF_INET; 2861 else if (num == 6) TT.addressfamily = AF_INET6; 2862 else TT.addressfamily = AF_PACKET; 2863 } else { 2864 struct arglist ip_aflist[] = {{"inet", AF_INET}, 2865 {"inet6", AF_INET6}, {"link", AF_PACKET}, {NULL, -1}}; 2866 2867 if (!*++optargv) help_exit(0); 2868 if ((TT.addressfamily = string_to_idx(*optargv, ip_aflist)) == -1) 2869 error_exit("wrong family '%s'", *optargv); 2870 } 2871 } 2872 break; 2873 case 2: 2874 TT.stats++; 2875 break; 2876 default: help_exit(0); 2877 break; // unreachable code. 2878 } 2879 } 2880 2881 TT.sockfd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 2882 2883 if (isip) {// only for ip 2884 if (*optargv) { 2885 struct arglist ip_objectlist[] = { {"address", 0}, {"link", 1}, 2886 {"route", 2}, {"rule", 3}, {"tunnel", 4}, {"tunl", 4}, {NULL, -1}}; 2887 2888 if ((idx = substring_to_idx(*optargv, ip_objectlist)) == -1) help_exit(0); 2889 ipcmd = cmdobjlist[idx]; 2890 toys.exitval = ipcmd(++optargv); 2891 } else help_exit(0); 2892 } else { 2893 struct arglist ip_objectlist[] = { {"ipaddr", 0}, {"iplink", 1}, 2894 {"iproute", 2}, {"iprule", 3}, {"iptunnel", 4}, {NULL, -1}}; 2895 if ((idx = string_to_idx(toys.which->name, ip_objectlist)) == -1) 2896 help_exit(0); 2897 ipcmd = cmdobjlist[idx]; 2898 toys.exitval = ipcmd(optargv); 2899 } 2900 xclose(TT.sockfd); 2901 if (rtdsfield_init) free_alist(rt_dsfield); 2902 if (rtrealms_init) free_alist(rt_realms); 2903 if (rtscope_init) free_alist(rt_scope); 2904 if (rttable_init) free_alist(rt_tables); 2905 if (rtprotos_init) free_alist(rt_protos); 2906 } 2907