1 /* 2 * iprule.c "ip rule". 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License 6 * as published by the Free Software Foundation; either version 7 * 2 of the License, or (at your option) any later version. 8 * 9 * Authors: Alexey Kuznetsov, <kuznet (at) ms2.inr.ac.ru> 10 * 11 */ 12 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <unistd.h> 16 #include <syslog.h> 17 #include <fcntl.h> 18 #include <sys/socket.h> 19 #include <netinet/in.h> 20 #include <netinet/ip.h> 21 #include <arpa/inet.h> 22 #include <string.h> 23 #include <linux/fib_rules.h> 24 #include <errno.h> 25 26 #include "rt_names.h" 27 #include "utils.h" 28 #include "ip_common.h" 29 30 extern struct rtnl_handle rth; 31 32 static void usage(void) __attribute__((noreturn)); 33 34 static void usage(void) 35 { 36 fprintf(stderr, "Usage: ip rule [ list | add | del | flush | save ] SELECTOR ACTION\n"); 37 fprintf(stderr, " ip rule restore\n"); 38 fprintf(stderr, "SELECTOR := [ not ] [ from PREFIX ] [ to PREFIX ] [ tos TOS ] [ fwmark FWMARK[/MASK] ]\n"); 39 fprintf(stderr, " [ iif STRING ] [ oif STRING ] [ pref NUMBER ] [ uidrange UID1-UID2 ]\n"); 40 fprintf(stderr, "ACTION := [ table TABLE_ID ]\n"); 41 fprintf(stderr, " [ realms [SRCREALM/]DSTREALM ]\n"); 42 fprintf(stderr, " [ goto NUMBER ]\n"); 43 fprintf(stderr, " SUPPRESSOR\n"); 44 fprintf(stderr, "SUPPRESSOR := [ suppress_prefixlength NUMBER ]\n"); 45 fprintf(stderr, " [ suppress_ifgroup DEVGROUP ]\n"); 46 fprintf(stderr, "TABLE_ID := [ local | main | default | NUMBER ]\n"); 47 exit(-1); 48 } 49 50 int print_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 51 { 52 FILE *fp = (FILE*)arg; 53 struct rtmsg *r = NLMSG_DATA(n); 54 int len = n->nlmsg_len; 55 int host_len = -1; 56 __u32 table; 57 struct rtattr * tb[FRA_MAX+1]; 58 char abuf[256]; 59 SPRINT_BUF(b1); 60 61 if (n->nlmsg_type != RTM_NEWRULE && n->nlmsg_type != RTM_DELRULE) 62 return 0; 63 64 len -= NLMSG_LENGTH(sizeof(*r)); 65 if (len < 0) 66 return -1; 67 68 parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); 69 70 host_len = af_bit_len(r->rtm_family); 71 72 if (n->nlmsg_type == RTM_DELRULE) 73 fprintf(fp, "Deleted "); 74 75 if (tb[FRA_PRIORITY]) 76 fprintf(fp, "%u:\t", *(unsigned*)RTA_DATA(tb[FRA_PRIORITY])); 77 else 78 fprintf(fp, "0:\t"); 79 80 if (r->rtm_flags & FIB_RULE_INVERT) 81 fprintf(fp, "not "); 82 83 if (tb[FRA_SRC]) { 84 if (r->rtm_src_len != host_len) { 85 fprintf(fp, "from %s/%u ", rt_addr_n2a(r->rtm_family, 86 RTA_PAYLOAD(tb[FRA_SRC]), 87 RTA_DATA(tb[FRA_SRC]), 88 abuf, sizeof(abuf)), 89 r->rtm_src_len 90 ); 91 } else { 92 fprintf(fp, "from %s ", format_host(r->rtm_family, 93 RTA_PAYLOAD(tb[FRA_SRC]), 94 RTA_DATA(tb[FRA_SRC]), 95 abuf, sizeof(abuf)) 96 ); 97 } 98 } else if (r->rtm_src_len) { 99 fprintf(fp, "from 0/%d ", r->rtm_src_len); 100 } else { 101 fprintf(fp, "from all "); 102 } 103 104 if (tb[FRA_DST]) { 105 if (r->rtm_dst_len != host_len) { 106 fprintf(fp, "to %s/%u ", rt_addr_n2a(r->rtm_family, 107 RTA_PAYLOAD(tb[FRA_DST]), 108 RTA_DATA(tb[FRA_DST]), 109 abuf, sizeof(abuf)), 110 r->rtm_dst_len 111 ); 112 } else { 113 fprintf(fp, "to %s ", format_host(r->rtm_family, 114 RTA_PAYLOAD(tb[FRA_DST]), 115 RTA_DATA(tb[FRA_DST]), 116 abuf, sizeof(abuf))); 117 } 118 } else if (r->rtm_dst_len) { 119 fprintf(fp, "to 0/%d ", r->rtm_dst_len); 120 } 121 122 if (r->rtm_tos) { 123 SPRINT_BUF(b1); 124 fprintf(fp, "tos %s ", rtnl_dsfield_n2a(r->rtm_tos, b1, sizeof(b1))); 125 } 126 127 if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) { 128 __u32 mark = 0, mask = 0; 129 130 if (tb[FRA_FWMARK]) 131 mark = rta_getattr_u32(tb[FRA_FWMARK]); 132 133 if (tb[FRA_FWMASK] && 134 (mask = rta_getattr_u32(tb[FRA_FWMASK])) != 0xFFFFFFFF) 135 fprintf(fp, "fwmark 0x%x/0x%x ", mark, mask); 136 else 137 fprintf(fp, "fwmark 0x%x ", mark); 138 } 139 140 if (tb[FRA_IFNAME]) { 141 fprintf(fp, "iif %s ", rta_getattr_str(tb[FRA_IFNAME])); 142 if (r->rtm_flags & FIB_RULE_IIF_DETACHED) 143 fprintf(fp, "[detached] "); 144 } 145 146 if (tb[FRA_OIFNAME]) { 147 fprintf(fp, "oif %s ", rta_getattr_str(tb[FRA_OIFNAME])); 148 if (r->rtm_flags & FIB_RULE_OIF_DETACHED) 149 fprintf(fp, "[detached] "); 150 } 151 152 if (tb[FRA_UID_START] || tb[FRA_UID_END]) { 153 fprintf(fp, "uidrange "); 154 if (tb[FRA_UID_START]) 155 fprintf(fp, "%u", rta_getattr_u32(tb[FRA_UID_START])); 156 else 157 fprintf(fp, "???"); 158 159 if (tb[FRA_UID_END]) 160 fprintf(fp, "-%u ", rta_getattr_u32(tb[FRA_UID_END])); 161 else 162 fprintf(fp, "-??? "); 163 } 164 165 table = rtm_get_table(r, tb); 166 if (table) { 167 fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); 168 169 if (tb[FRA_SUPPRESS_PREFIXLEN]) { 170 int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]); 171 if (pl != -1) { 172 fprintf(fp, "suppress_prefixlength %d ", pl); 173 } 174 } 175 if (tb[FRA_SUPPRESS_IFGROUP]) { 176 int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]); 177 if (group != -1) { 178 SPRINT_BUF(b1); 179 fprintf(fp, "suppress_ifgroup %s ", rtnl_group_n2a(group, b1, sizeof(b1))); 180 } 181 } 182 } 183 184 if (tb[FRA_FLOW]) { 185 __u32 to = rta_getattr_u32(tb[FRA_FLOW]); 186 __u32 from = to>>16; 187 to &= 0xFFFF; 188 if (from) { 189 fprintf(fp, "realms %s/", 190 rtnl_rtrealm_n2a(from, b1, sizeof(b1))); 191 } 192 fprintf(fp, "%s ", 193 rtnl_rtrealm_n2a(to, b1, sizeof(b1))); 194 } 195 196 if (r->rtm_type == RTN_NAT) { 197 if (tb[RTA_GATEWAY]) { 198 fprintf(fp, "map-to %s ", 199 format_host(r->rtm_family, 200 RTA_PAYLOAD(tb[RTA_GATEWAY]), 201 RTA_DATA(tb[RTA_GATEWAY]), 202 abuf, sizeof(abuf))); 203 } else 204 fprintf(fp, "masquerade"); 205 } else if (r->rtm_type == FR_ACT_GOTO) { 206 fprintf(fp, "goto "); 207 if (tb[FRA_GOTO]) 208 fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO])); 209 else 210 fprintf(fp, "none"); 211 if (r->rtm_flags & FIB_RULE_UNRESOLVED) 212 fprintf(fp, " [unresolved]"); 213 } else if (r->rtm_type == FR_ACT_NOP) 214 fprintf(fp, "nop"); 215 else if (r->rtm_type != RTN_UNICAST) 216 fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); 217 218 fprintf(fp, "\n"); 219 fflush(fp); 220 return 0; 221 } 222 223 static __u32 rule_dump_magic = 0x71706986; 224 225 static int save_rule_prep(void) 226 { 227 int ret; 228 229 if (isatty(STDOUT_FILENO)) { 230 fprintf(stderr, "Not sending a binary stream to stdout\n"); 231 return -1; 232 } 233 234 ret = write(STDOUT_FILENO, &rule_dump_magic, sizeof(rule_dump_magic)); 235 if (ret != sizeof(rule_dump_magic)) { 236 fprintf(stderr, "Can't write magic to dump file\n"); 237 return -1; 238 } 239 240 return 0; 241 } 242 243 static int save_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 244 { 245 int ret; 246 247 ret = write(STDOUT_FILENO, n, n->nlmsg_len); 248 if ((ret > 0) && (ret != n->nlmsg_len)) { 249 fprintf(stderr, "Short write while saving nlmsg\n"); 250 ret = -EIO; 251 } 252 253 return ret == n->nlmsg_len ? 0 : ret; 254 } 255 256 static int iprule_list_or_save(int argc, char **argv, int save) 257 { 258 rtnl_filter_t filter = print_rule; 259 int af = preferred_family; 260 261 if (af == AF_UNSPEC) 262 af = AF_INET; 263 264 if (argc > 0) { 265 fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n", 266 save ? "save" : "show"); 267 return -1; 268 } 269 270 if (save) { 271 if (save_rule_prep()) 272 return -1; 273 filter = save_rule; 274 } 275 276 if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { 277 perror("Cannot send dump request"); 278 return 1; 279 } 280 281 if (rtnl_dump_filter(&rth, filter, stdout) < 0) { 282 fprintf(stderr, "Dump terminated\n"); 283 return 1; 284 } 285 286 return 0; 287 } 288 289 static int rule_dump_check_magic(void) 290 { 291 int ret; 292 __u32 magic = 0; 293 294 if (isatty(STDIN_FILENO)) { 295 fprintf(stderr, "Can't restore rule dump from a terminal\n"); 296 return -1; 297 } 298 299 ret = fread(&magic, sizeof(magic), 1, stdin); 300 if (magic != rule_dump_magic) { 301 fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", ret, magic); 302 return -1; 303 } 304 305 return 0; 306 } 307 308 static int restore_handler(const struct sockaddr_nl *nl, 309 struct rtnl_ctrl_data *ctrl, 310 struct nlmsghdr *n, void *arg) 311 { 312 int ret; 313 314 n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; 315 316 ll_init_map(&rth); 317 318 ret = rtnl_talk(&rth, n, n, sizeof(*n)); 319 if ((ret < 0) && (errno == EEXIST)) 320 ret = 0; 321 322 return ret; 323 } 324 325 326 static int iprule_restore(void) 327 { 328 if (rule_dump_check_magic()) 329 exit(-1); 330 331 exit(rtnl_from_file(stdin, &restore_handler, NULL)); 332 } 333 334 static int iprule_modify(int cmd, int argc, char **argv) 335 { 336 int table_ok = 0; 337 struct { 338 struct nlmsghdr n; 339 struct rtmsg r; 340 char buf[1024]; 341 } req; 342 343 memset(&req, 0, sizeof(req)); 344 345 req.n.nlmsg_type = cmd; 346 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 347 req.n.nlmsg_flags = NLM_F_REQUEST; 348 req.r.rtm_family = preferred_family; 349 req.r.rtm_protocol = RTPROT_BOOT; 350 req.r.rtm_scope = RT_SCOPE_UNIVERSE; 351 req.r.rtm_table = 0; 352 req.r.rtm_type = RTN_UNSPEC; 353 req.r.rtm_flags = 0; 354 355 if (cmd == RTM_NEWRULE) { 356 req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; 357 req.r.rtm_type = RTN_UNICAST; 358 } 359 360 while (argc > 0) { 361 if (strcmp(*argv, "not") == 0) { 362 req.r.rtm_flags |= FIB_RULE_INVERT; 363 } else if (strcmp(*argv, "from") == 0) { 364 inet_prefix dst; 365 NEXT_ARG(); 366 get_prefix(&dst, *argv, req.r.rtm_family); 367 req.r.rtm_src_len = dst.bitlen; 368 addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen); 369 } else if (strcmp(*argv, "to") == 0) { 370 inet_prefix dst; 371 NEXT_ARG(); 372 get_prefix(&dst, *argv, req.r.rtm_family); 373 req.r.rtm_dst_len = dst.bitlen; 374 addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen); 375 } else if (matches(*argv, "preference") == 0 || 376 matches(*argv, "order") == 0 || 377 matches(*argv, "priority") == 0) { 378 __u32 pref; 379 NEXT_ARG(); 380 if (get_u32(&pref, *argv, 0)) 381 invarg("preference value is invalid\n", *argv); 382 addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref); 383 } else if (strcmp(*argv, "tos") == 0 || 384 matches(*argv, "dsfield") == 0) { 385 __u32 tos; 386 NEXT_ARG(); 387 if (rtnl_dsfield_a2n(&tos, *argv)) 388 invarg("TOS value is invalid\n", *argv); 389 req.r.rtm_tos = tos; 390 } else if (strcmp(*argv, "fwmark") == 0) { 391 char *slash; 392 __u32 fwmark, fwmask; 393 NEXT_ARG(); 394 if ((slash = strchr(*argv, '/')) != NULL) 395 *slash = '\0'; 396 if (get_u32(&fwmark, *argv, 0)) 397 invarg("fwmark value is invalid\n", *argv); 398 addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark); 399 if (slash) { 400 if (get_u32(&fwmask, slash+1, 0)) 401 invarg("fwmask value is invalid\n", slash+1); 402 addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask); 403 } 404 } else if (matches(*argv, "realms") == 0) { 405 __u32 realm; 406 NEXT_ARG(); 407 if (get_rt_realms_or_raw(&realm, *argv)) 408 invarg("invalid realms\n", *argv); 409 addattr32(&req.n, sizeof(req), FRA_FLOW, realm); 410 } else if (matches(*argv, "table") == 0 || 411 strcmp(*argv, "lookup") == 0) { 412 __u32 tid; 413 NEXT_ARG(); 414 if (rtnl_rttable_a2n(&tid, *argv)) 415 invarg("invalid table ID\n", *argv); 416 if (tid < 256) 417 req.r.rtm_table = tid; 418 else { 419 req.r.rtm_table = RT_TABLE_UNSPEC; 420 addattr32(&req.n, sizeof(req), FRA_TABLE, tid); 421 } 422 table_ok = 1; 423 } else if (matches(*argv, "suppress_prefixlength") == 0 || 424 strcmp(*argv, "sup_pl") == 0) { 425 int pl; 426 NEXT_ARG(); 427 if (get_s32(&pl, *argv, 0) || pl < 0) 428 invarg("suppress_prefixlength value is invalid\n", *argv); 429 addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, pl); 430 } else if (matches(*argv, "suppress_ifgroup") == 0 || 431 strcmp(*argv, "sup_group") == 0) { 432 NEXT_ARG(); 433 int group; 434 if (rtnl_group_a2n(&group, *argv)) 435 invarg("Invalid \"suppress_ifgroup\" value\n", *argv); 436 addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, group); 437 } else if (strcmp(*argv, "dev") == 0 || 438 strcmp(*argv, "iif") == 0) { 439 NEXT_ARG(); 440 addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1); 441 } else if (strcmp(*argv, "oif") == 0) { 442 NEXT_ARG(); 443 addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *argv, strlen(*argv)+1); 444 } else if (strcmp(*argv, "nat") == 0 || 445 matches(*argv, "map-to") == 0) { 446 NEXT_ARG(); 447 fprintf(stderr, "Warning: route NAT is deprecated\n"); 448 addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv)); 449 req.r.rtm_type = RTN_NAT; 450 } else if (strcmp(*argv, "uidrange") == 0) { 451 __u32 uid_start, uid_end; 452 NEXT_ARG(); 453 if (sscanf(*argv, "%u-%u", &uid_start, &uid_end) != 2) 454 invarg("UID range is invalid\n", *argv); 455 addattr32(&req.n, sizeof(req), FRA_UID_START, uid_start); 456 addattr32(&req.n, sizeof(req), FRA_UID_END, uid_end); 457 } else { 458 int type; 459 460 if (strcmp(*argv, "type") == 0) { 461 NEXT_ARG(); 462 } 463 if (matches(*argv, "help") == 0) 464 usage(); 465 else if (matches(*argv, "goto") == 0) { 466 __u32 target; 467 type = FR_ACT_GOTO; 468 NEXT_ARG(); 469 if (get_u32(&target, *argv, 0)) 470 invarg("invalid target\n", *argv); 471 addattr32(&req.n, sizeof(req), FRA_GOTO, target); 472 } else if (matches(*argv, "nop") == 0) 473 type = FR_ACT_NOP; 474 else if (rtnl_rtntype_a2n(&type, *argv)) 475 invarg("Failed to parse rule type", *argv); 476 req.r.rtm_type = type; 477 table_ok = 1; 478 } 479 argc--; 480 argv++; 481 } 482 483 if (req.r.rtm_family == AF_UNSPEC) 484 req.r.rtm_family = AF_INET; 485 486 if (!table_ok && cmd == RTM_NEWRULE) 487 req.r.rtm_table = RT_TABLE_MAIN; 488 489 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) 490 return -2; 491 492 return 0; 493 } 494 495 496 static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 497 { 498 struct rtnl_handle rth2; 499 struct rtmsg *r = NLMSG_DATA(n); 500 int len = n->nlmsg_len; 501 struct rtattr * tb[FRA_MAX+1]; 502 503 len -= NLMSG_LENGTH(sizeof(*r)); 504 if (len < 0) 505 return -1; 506 507 parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); 508 509 if (tb[FRA_PRIORITY]) { 510 n->nlmsg_type = RTM_DELRULE; 511 n->nlmsg_flags = NLM_F_REQUEST; 512 513 if (rtnl_open(&rth2, 0) < 0) 514 return -1; 515 516 if (rtnl_talk(&rth2, n, NULL, 0) < 0) 517 return -2; 518 519 rtnl_close(&rth2); 520 } 521 522 return 0; 523 } 524 525 static int iprule_flush(int argc, char **argv) 526 { 527 int af = preferred_family; 528 529 if (af == AF_UNSPEC) 530 af = AF_INET; 531 532 if (argc > 0) { 533 fprintf(stderr, "\"ip rule flush\" does not allow arguments\n"); 534 return -1; 535 } 536 537 if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { 538 perror("Cannot send dump request"); 539 return 1; 540 } 541 542 if (rtnl_dump_filter(&rth, flush_rule, NULL) < 0) { 543 fprintf(stderr, "Flush terminated\n"); 544 return 1; 545 } 546 547 return 0; 548 } 549 550 int do_iprule(int argc, char **argv) 551 { 552 if (argc < 1) { 553 return iprule_list_or_save(0, NULL, 0); 554 } else if (matches(argv[0], "list") == 0 || 555 matches(argv[0], "lst") == 0 || 556 matches(argv[0], "show") == 0) { 557 return iprule_list_or_save(argc-1, argv+1, 0); 558 } else if (matches(argv[0], "save") == 0) { 559 return iprule_list_or_save(argc-1, argv+1, 1); 560 } else if (matches(argv[0], "restore") == 0) { 561 return iprule_restore(); 562 } else if (matches(argv[0], "add") == 0) { 563 return iprule_modify(RTM_NEWRULE, argc-1, argv+1); 564 } else if (matches(argv[0], "delete") == 0) { 565 return iprule_modify(RTM_DELRULE, argc-1, argv+1); 566 } else if (matches(argv[0], "flush") == 0) { 567 return iprule_flush(argc-1, argv+1); 568 } else if (matches(argv[0], "help") == 0) 569 usage(); 570 571 fprintf(stderr, "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv); 572 exit(-1); 573 } 574 575 int do_multirule(int argc, char **argv) 576 { 577 switch (preferred_family) { 578 case AF_UNSPEC: 579 case AF_INET: 580 preferred_family = RTNL_FAMILY_IPMR; 581 break; 582 case AF_INET6: 583 preferred_family = RTNL_FAMILY_IP6MR; 584 break; 585 case RTNL_FAMILY_IPMR: 586 case RTNL_FAMILY_IP6MR: 587 break; 588 default: 589 fprintf(stderr, "Multicast rules are only supported for IPv4/IPv6, was: %i\n", 590 preferred_family); 591 exit(-1); 592 } 593 594 return do_iprule(argc, argv); 595 } 596