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_RANGE]) { 153 struct fib_rule_uid_range *r = RTA_DATA(tb[FRA_UID_RANGE]); 154 155 fprintf(fp, "uidrange %u-%u ", r->start, r->end); 156 } 157 158 table = rtm_get_table(r, tb); 159 if (table) { 160 fprintf(fp, "lookup %s ", rtnl_rttable_n2a(table, b1, sizeof(b1))); 161 162 if (tb[FRA_SUPPRESS_PREFIXLEN]) { 163 int pl = rta_getattr_u32(tb[FRA_SUPPRESS_PREFIXLEN]); 164 if (pl != -1) { 165 fprintf(fp, "suppress_prefixlength %d ", pl); 166 } 167 } 168 if (tb[FRA_SUPPRESS_IFGROUP]) { 169 int group = rta_getattr_u32(tb[FRA_SUPPRESS_IFGROUP]); 170 if (group != -1) { 171 SPRINT_BUF(b1); 172 fprintf(fp, "suppress_ifgroup %s ", rtnl_group_n2a(group, b1, sizeof(b1))); 173 } 174 } 175 } 176 177 if (tb[FRA_FLOW]) { 178 __u32 to = rta_getattr_u32(tb[FRA_FLOW]); 179 __u32 from = to>>16; 180 to &= 0xFFFF; 181 if (from) { 182 fprintf(fp, "realms %s/", 183 rtnl_rtrealm_n2a(from, b1, sizeof(b1))); 184 } 185 fprintf(fp, "%s ", 186 rtnl_rtrealm_n2a(to, b1, sizeof(b1))); 187 } 188 189 if (r->rtm_type == RTN_NAT) { 190 if (tb[RTA_GATEWAY]) { 191 fprintf(fp, "map-to %s ", 192 format_host(r->rtm_family, 193 RTA_PAYLOAD(tb[RTA_GATEWAY]), 194 RTA_DATA(tb[RTA_GATEWAY]), 195 abuf, sizeof(abuf))); 196 } else 197 fprintf(fp, "masquerade"); 198 } else if (r->rtm_type == FR_ACT_GOTO) { 199 fprintf(fp, "goto "); 200 if (tb[FRA_GOTO]) 201 fprintf(fp, "%u", rta_getattr_u32(tb[FRA_GOTO])); 202 else 203 fprintf(fp, "none"); 204 if (r->rtm_flags & FIB_RULE_UNRESOLVED) 205 fprintf(fp, " [unresolved]"); 206 } else if (r->rtm_type == FR_ACT_NOP) 207 fprintf(fp, "nop"); 208 else if (r->rtm_type != RTN_UNICAST) 209 fprintf(fp, "%s", rtnl_rtntype_n2a(r->rtm_type, b1, sizeof(b1))); 210 211 fprintf(fp, "\n"); 212 fflush(fp); 213 return 0; 214 } 215 216 static __u32 rule_dump_magic = 0x71706986; 217 218 static int save_rule_prep(void) 219 { 220 int ret; 221 222 if (isatty(STDOUT_FILENO)) { 223 fprintf(stderr, "Not sending a binary stream to stdout\n"); 224 return -1; 225 } 226 227 ret = write(STDOUT_FILENO, &rule_dump_magic, sizeof(rule_dump_magic)); 228 if (ret != sizeof(rule_dump_magic)) { 229 fprintf(stderr, "Can't write magic to dump file\n"); 230 return -1; 231 } 232 233 return 0; 234 } 235 236 static int save_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 237 { 238 int ret; 239 240 ret = write(STDOUT_FILENO, n, n->nlmsg_len); 241 if ((ret > 0) && (ret != n->nlmsg_len)) { 242 fprintf(stderr, "Short write while saving nlmsg\n"); 243 ret = -EIO; 244 } 245 246 return ret == n->nlmsg_len ? 0 : ret; 247 } 248 249 static int iprule_list_or_save(int argc, char **argv, int save) 250 { 251 rtnl_filter_t filter = print_rule; 252 int af = preferred_family; 253 254 if (af == AF_UNSPEC) 255 af = AF_INET; 256 257 if (argc > 0) { 258 fprintf(stderr, "\"ip rule %s\" does not take any arguments.\n", 259 save ? "save" : "show"); 260 return -1; 261 } 262 263 if (save) { 264 if (save_rule_prep()) 265 return -1; 266 filter = save_rule; 267 } 268 269 if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { 270 perror("Cannot send dump request"); 271 return 1; 272 } 273 274 if (rtnl_dump_filter(&rth, filter, stdout) < 0) { 275 fprintf(stderr, "Dump terminated\n"); 276 return 1; 277 } 278 279 return 0; 280 } 281 282 static int rule_dump_check_magic(void) 283 { 284 int ret; 285 __u32 magic = 0; 286 287 if (isatty(STDIN_FILENO)) { 288 fprintf(stderr, "Can't restore rule dump from a terminal\n"); 289 return -1; 290 } 291 292 ret = fread(&magic, sizeof(magic), 1, stdin); 293 if (magic != rule_dump_magic) { 294 fprintf(stderr, "Magic mismatch (%d elems, %x magic)\n", ret, magic); 295 return -1; 296 } 297 298 return 0; 299 } 300 301 static int restore_handler(const struct sockaddr_nl *nl, 302 struct rtnl_ctrl_data *ctrl, 303 struct nlmsghdr *n, void *arg) 304 { 305 int ret; 306 307 n->nlmsg_flags |= NLM_F_REQUEST | NLM_F_CREATE | NLM_F_ACK; 308 309 ll_init_map(&rth); 310 311 ret = rtnl_talk(&rth, n, n, sizeof(*n)); 312 if ((ret < 0) && (errno == EEXIST)) 313 ret = 0; 314 315 return ret; 316 } 317 318 319 static int iprule_restore(void) 320 { 321 if (rule_dump_check_magic()) 322 exit(-1); 323 324 exit(rtnl_from_file(stdin, &restore_handler, NULL)); 325 } 326 327 static int iprule_modify(int cmd, int argc, char **argv) 328 { 329 int table_ok = 0; 330 struct { 331 struct nlmsghdr n; 332 struct rtmsg r; 333 char buf[1024]; 334 } req; 335 336 memset(&req, 0, sizeof(req)); 337 338 req.n.nlmsg_type = cmd; 339 req.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); 340 req.n.nlmsg_flags = NLM_F_REQUEST; 341 req.r.rtm_family = preferred_family; 342 req.r.rtm_protocol = RTPROT_BOOT; 343 req.r.rtm_scope = RT_SCOPE_UNIVERSE; 344 req.r.rtm_table = 0; 345 req.r.rtm_type = RTN_UNSPEC; 346 req.r.rtm_flags = 0; 347 348 if (cmd == RTM_NEWRULE) { 349 req.n.nlmsg_flags |= NLM_F_CREATE|NLM_F_EXCL; 350 req.r.rtm_type = RTN_UNICAST; 351 } 352 353 while (argc > 0) { 354 if (strcmp(*argv, "not") == 0) { 355 req.r.rtm_flags |= FIB_RULE_INVERT; 356 } else if (strcmp(*argv, "from") == 0) { 357 inet_prefix dst; 358 NEXT_ARG(); 359 get_prefix(&dst, *argv, req.r.rtm_family); 360 req.r.rtm_src_len = dst.bitlen; 361 addattr_l(&req.n, sizeof(req), FRA_SRC, &dst.data, dst.bytelen); 362 } else if (strcmp(*argv, "to") == 0) { 363 inet_prefix dst; 364 NEXT_ARG(); 365 get_prefix(&dst, *argv, req.r.rtm_family); 366 req.r.rtm_dst_len = dst.bitlen; 367 addattr_l(&req.n, sizeof(req), FRA_DST, &dst.data, dst.bytelen); 368 } else if (matches(*argv, "preference") == 0 || 369 matches(*argv, "order") == 0 || 370 matches(*argv, "priority") == 0) { 371 __u32 pref; 372 NEXT_ARG(); 373 if (get_u32(&pref, *argv, 0)) 374 invarg("preference value is invalid\n", *argv); 375 addattr32(&req.n, sizeof(req), FRA_PRIORITY, pref); 376 } else if (strcmp(*argv, "tos") == 0 || 377 matches(*argv, "dsfield") == 0) { 378 __u32 tos; 379 NEXT_ARG(); 380 if (rtnl_dsfield_a2n(&tos, *argv)) 381 invarg("TOS value is invalid\n", *argv); 382 req.r.rtm_tos = tos; 383 } else if (strcmp(*argv, "fwmark") == 0) { 384 char *slash; 385 __u32 fwmark, fwmask; 386 NEXT_ARG(); 387 if ((slash = strchr(*argv, '/')) != NULL) 388 *slash = '\0'; 389 if (get_u32(&fwmark, *argv, 0)) 390 invarg("fwmark value is invalid\n", *argv); 391 addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark); 392 if (slash) { 393 if (get_u32(&fwmask, slash+1, 0)) 394 invarg("fwmask value is invalid\n", slash+1); 395 addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask); 396 } 397 } else if (matches(*argv, "realms") == 0) { 398 __u32 realm; 399 NEXT_ARG(); 400 if (get_rt_realms_or_raw(&realm, *argv)) 401 invarg("invalid realms\n", *argv); 402 addattr32(&req.n, sizeof(req), FRA_FLOW, realm); 403 } else if (matches(*argv, "table") == 0 || 404 strcmp(*argv, "lookup") == 0) { 405 __u32 tid; 406 NEXT_ARG(); 407 if (rtnl_rttable_a2n(&tid, *argv)) 408 invarg("invalid table ID\n", *argv); 409 if (tid < 256) 410 req.r.rtm_table = tid; 411 else { 412 req.r.rtm_table = RT_TABLE_UNSPEC; 413 addattr32(&req.n, sizeof(req), FRA_TABLE, tid); 414 } 415 table_ok = 1; 416 } else if (matches(*argv, "suppress_prefixlength") == 0 || 417 strcmp(*argv, "sup_pl") == 0) { 418 int pl; 419 NEXT_ARG(); 420 if (get_s32(&pl, *argv, 0) || pl < 0) 421 invarg("suppress_prefixlength value is invalid\n", *argv); 422 addattr32(&req.n, sizeof(req), FRA_SUPPRESS_PREFIXLEN, pl); 423 } else if (matches(*argv, "suppress_ifgroup") == 0 || 424 strcmp(*argv, "sup_group") == 0) { 425 NEXT_ARG(); 426 int group; 427 if (rtnl_group_a2n(&group, *argv)) 428 invarg("Invalid \"suppress_ifgroup\" value\n", *argv); 429 addattr32(&req.n, sizeof(req), FRA_SUPPRESS_IFGROUP, group); 430 } else if (strcmp(*argv, "dev") == 0 || 431 strcmp(*argv, "iif") == 0) { 432 NEXT_ARG(); 433 addattr_l(&req.n, sizeof(req), FRA_IFNAME, *argv, strlen(*argv)+1); 434 } else if (strcmp(*argv, "oif") == 0) { 435 NEXT_ARG(); 436 addattr_l(&req.n, sizeof(req), FRA_OIFNAME, *argv, strlen(*argv)+1); 437 } else if (strcmp(*argv, "uidrange") == 0) { 438 struct fib_rule_uid_range r; 439 440 NEXT_ARG(); 441 if (sscanf(*argv, "%u-%u", &r.start, &r.end) != 2) 442 invarg("invalid UID range\n", *argv); 443 addattr_l(&req.n, sizeof(req), FRA_UID_RANGE, &r, 444 sizeof(r)); 445 } else if (strcmp(*argv, "nat") == 0 || 446 matches(*argv, "map-to") == 0) { 447 NEXT_ARG(); 448 fprintf(stderr, "Warning: route NAT is deprecated\n"); 449 addattr32(&req.n, sizeof(req), RTA_GATEWAY, get_addr32(*argv)); 450 req.r.rtm_type = RTN_NAT; 451 } else { 452 int type; 453 454 if (strcmp(*argv, "type") == 0) { 455 NEXT_ARG(); 456 } 457 if (matches(*argv, "help") == 0) 458 usage(); 459 else if (matches(*argv, "goto") == 0) { 460 __u32 target; 461 type = FR_ACT_GOTO; 462 NEXT_ARG(); 463 if (get_u32(&target, *argv, 0)) 464 invarg("invalid target\n", *argv); 465 addattr32(&req.n, sizeof(req), FRA_GOTO, target); 466 } else if (matches(*argv, "nop") == 0) 467 type = FR_ACT_NOP; 468 else if (rtnl_rtntype_a2n(&type, *argv)) 469 invarg("Failed to parse rule type", *argv); 470 req.r.rtm_type = type; 471 table_ok = 1; 472 } 473 argc--; 474 argv++; 475 } 476 477 if (req.r.rtm_family == AF_UNSPEC) 478 req.r.rtm_family = AF_INET; 479 480 if (!table_ok && cmd == RTM_NEWRULE) 481 req.r.rtm_table = RT_TABLE_MAIN; 482 483 if (rtnl_talk(&rth, &req.n, NULL, 0) < 0) 484 return -2; 485 486 return 0; 487 } 488 489 490 static int flush_rule(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg) 491 { 492 struct rtnl_handle rth2; 493 struct rtmsg *r = NLMSG_DATA(n); 494 int len = n->nlmsg_len; 495 struct rtattr * tb[FRA_MAX+1]; 496 497 len -= NLMSG_LENGTH(sizeof(*r)); 498 if (len < 0) 499 return -1; 500 501 parse_rtattr(tb, FRA_MAX, RTM_RTA(r), len); 502 503 if (tb[FRA_PRIORITY]) { 504 n->nlmsg_type = RTM_DELRULE; 505 n->nlmsg_flags = NLM_F_REQUEST; 506 507 if (rtnl_open(&rth2, 0) < 0) 508 return -1; 509 510 if (rtnl_talk(&rth2, n, NULL, 0) < 0) 511 return -2; 512 513 rtnl_close(&rth2); 514 } 515 516 return 0; 517 } 518 519 static int iprule_flush(int argc, char **argv) 520 { 521 int af = preferred_family; 522 523 if (af == AF_UNSPEC) 524 af = AF_INET; 525 526 if (argc > 0) { 527 fprintf(stderr, "\"ip rule flush\" does not allow arguments\n"); 528 return -1; 529 } 530 531 if (rtnl_wilddump_request(&rth, af, RTM_GETRULE) < 0) { 532 perror("Cannot send dump request"); 533 return 1; 534 } 535 536 if (rtnl_dump_filter(&rth, flush_rule, NULL) < 0) { 537 fprintf(stderr, "Flush terminated\n"); 538 return 1; 539 } 540 541 return 0; 542 } 543 544 int do_iprule(int argc, char **argv) 545 { 546 if (argc < 1) { 547 return iprule_list_or_save(0, NULL, 0); 548 } else if (matches(argv[0], "list") == 0 || 549 matches(argv[0], "lst") == 0 || 550 matches(argv[0], "show") == 0) { 551 return iprule_list_or_save(argc-1, argv+1, 0); 552 } else if (matches(argv[0], "save") == 0) { 553 return iprule_list_or_save(argc-1, argv+1, 1); 554 } else if (matches(argv[0], "restore") == 0) { 555 return iprule_restore(); 556 } else if (matches(argv[0], "add") == 0) { 557 return iprule_modify(RTM_NEWRULE, argc-1, argv+1); 558 } else if (matches(argv[0], "delete") == 0) { 559 return iprule_modify(RTM_DELRULE, argc-1, argv+1); 560 } else if (matches(argv[0], "flush") == 0) { 561 return iprule_flush(argc-1, argv+1); 562 } else if (matches(argv[0], "help") == 0) 563 usage(); 564 565 fprintf(stderr, "Command \"%s\" is unknown, try \"ip rule help\".\n", *argv); 566 exit(-1); 567 } 568 569 int do_multirule(int argc, char **argv) 570 { 571 switch (preferred_family) { 572 case AF_UNSPEC: 573 case AF_INET: 574 preferred_family = RTNL_FAMILY_IPMR; 575 break; 576 case AF_INET6: 577 preferred_family = RTNL_FAMILY_IP6MR; 578 break; 579 case RTNL_FAMILY_IPMR: 580 case RTNL_FAMILY_IP6MR: 581 break; 582 default: 583 fprintf(stderr, "Multicast rules are only supported for IPv4/IPv6, was: %i\n", 584 preferred_family); 585 exit(-1); 586 } 587 588 return do_iprule(argc, argv); 589 } 590