1 /* 2 * Copyright (c) 2014 Yandex LLC 3 * Copyright (c) 2014 Alexander V. Chernikov 4 * 5 * Redistribution and use in source forms, with and without modification, 6 * are permitted provided that this entire comment appears intact. 7 * 8 * Redistribution in binary form may occur without any restrictions. 9 * Obviously, it would be nice if you gave credit where credit is due 10 * but requiring it would be too onerous. 11 * 12 * This software is provided ``AS IS'' without any warranties of any kind. 13 * 14 * in-kernel ipfw tables support. 15 * 16 * $FreeBSD$ 17 */ 18 19 20 #include <sys/types.h> 21 #include <sys/param.h> 22 #include <sys/socket.h> 23 #include <sys/sysctl.h> 24 25 #include <ctype.h> 26 #include <err.h> 27 #include <errno.h> 28 #include <netdb.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <string.h> 32 #include <sysexits.h> 33 34 #include <net/if.h> 35 #include <netinet/in.h> 36 #include <netinet/ip_fw.h> 37 #include <arpa/inet.h> 38 #include <netdb.h> 39 40 #include "ipfw2.h" 41 42 static void table_modify_record(ipfw_obj_header *oh, int ac, char *av[], 43 int add, int quiet, int update, int atomic); 44 static int table_flush(ipfw_obj_header *oh); 45 static int table_destroy(ipfw_obj_header *oh); 46 static int table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i); 47 static int table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i); 48 static int table_do_swap(ipfw_obj_header *oh, char *second); 49 static void table_create(ipfw_obj_header *oh, int ac, char *av[]); 50 static void table_modify(ipfw_obj_header *oh, int ac, char *av[]); 51 static void table_lookup(ipfw_obj_header *oh, int ac, char *av[]); 52 static void table_lock(ipfw_obj_header *oh, int lock); 53 static int table_swap(ipfw_obj_header *oh, char *second); 54 static int table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i); 55 static int table_show_info(ipfw_xtable_info *i, void *arg); 56 static void table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, 57 uint32_t set, uint16_t uidx); 58 59 static int table_flush_one(ipfw_xtable_info *i, void *arg); 60 static int table_show_one(ipfw_xtable_info *i, void *arg); 61 static int table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh); 62 static void table_show_list(ipfw_obj_header *oh, int need_header); 63 static void table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent); 64 65 static void tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 66 char *key, int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi); 67 static void tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, 68 char *arg, uint8_t type, uint32_t vmask); 69 static void table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 70 uint32_t vmask, int print_ip); 71 72 typedef int (table_cb_t)(ipfw_xtable_info *i, void *arg); 73 static int tables_foreach(table_cb_t *f, void *arg, int sort); 74 75 #ifndef s6_addr32 76 #define s6_addr32 __u6_addr.__u6_addr32 77 #endif 78 79 static struct _s_x tabletypes[] = { 80 { "addr", IPFW_TABLE_ADDR }, 81 { "iface", IPFW_TABLE_INTERFACE }, 82 { "number", IPFW_TABLE_NUMBER }, 83 { "flow", IPFW_TABLE_FLOW }, 84 { NULL, 0 } 85 }; 86 87 static struct _s_x tablevaltypes[] = { 88 { "skipto", IPFW_VTYPE_SKIPTO }, 89 { "pipe", IPFW_VTYPE_PIPE }, 90 { "fib", IPFW_VTYPE_FIB }, 91 { "nat", IPFW_VTYPE_NAT }, 92 { "dscp", IPFW_VTYPE_DSCP }, 93 { "tag", IPFW_VTYPE_TAG }, 94 { "divert", IPFW_VTYPE_DIVERT }, 95 { "netgraph", IPFW_VTYPE_NETGRAPH }, 96 { "limit", IPFW_VTYPE_LIMIT }, 97 { "ipv4", IPFW_VTYPE_NH4 }, 98 { "ipv6", IPFW_VTYPE_NH6 }, 99 { NULL, 0 } 100 }; 101 102 static struct _s_x tablecmds[] = { 103 { "add", TOK_ADD }, 104 { "delete", TOK_DEL }, 105 { "create", TOK_CREATE }, 106 { "destroy", TOK_DESTROY }, 107 { "flush", TOK_FLUSH }, 108 { "modify", TOK_MODIFY }, 109 { "swap", TOK_SWAP }, 110 { "info", TOK_INFO }, 111 { "detail", TOK_DETAIL }, 112 { "list", TOK_LIST }, 113 { "lookup", TOK_LOOKUP }, 114 { "atomic", TOK_ATOMIC }, 115 { "lock", TOK_LOCK }, 116 { "unlock", TOK_UNLOCK }, 117 { NULL, 0 } 118 }; 119 120 static int 121 lookup_host (char *host, struct in_addr *ipaddr) 122 { 123 struct hostent *he; 124 125 if (!inet_aton(host, ipaddr)) { 126 #ifndef FSTACK 127 if ((he = gethostbyname(host)) == NULL) 128 return(-1); 129 *ipaddr = *(struct in_addr *)he->h_addr_list[0]; 130 #else 131 return (-1); 132 #endif 133 } 134 return(0); 135 } 136 137 /* 138 * This one handles all table-related commands 139 * ipfw table NAME create ... 140 * ipfw table NAME modify ... 141 * ipfw table NAME destroy 142 * ipfw table NAME swap NAME 143 * ipfw table NAME lock 144 * ipfw table NAME unlock 145 * ipfw table NAME add addr[/masklen] [value] 146 * ipfw table NAME add [addr[/masklen] value] [addr[/masklen] value] .. 147 * ipfw table NAME delete addr[/masklen] [addr[/masklen]] .. 148 * ipfw table NAME lookup addr 149 * ipfw table {NAME | all} flush 150 * ipfw table {NAME | all} list 151 * ipfw table {NAME | all} info 152 * ipfw table {NAME | all} detail 153 */ 154 void 155 ipfw_table_handler(int ac, char *av[]) 156 { 157 int do_add, is_all; 158 int atomic, error, tcmd; 159 ipfw_xtable_info i; 160 ipfw_obj_header oh; 161 char *tablename; 162 uint32_t set; 163 void *arg; 164 165 memset(&oh, 0, sizeof(oh)); 166 is_all = 0; 167 if (co.use_set != 0) 168 set = co.use_set - 1; 169 else 170 set = 0; 171 172 ac--; av++; 173 NEED1("table needs name"); 174 tablename = *av; 175 176 if (table_check_name(tablename) == 0) { 177 table_fill_ntlv(&oh.ntlv, *av, set, 1); 178 oh.idx = 1; 179 } else { 180 if (strcmp(tablename, "all") == 0) 181 is_all = 1; 182 else 183 errx(EX_USAGE, "table name %s is invalid", tablename); 184 } 185 ac--; av++; 186 NEED1("table needs command"); 187 188 tcmd = get_token(tablecmds, *av, "table command"); 189 /* Check if atomic operation was requested */ 190 atomic = 0; 191 if (tcmd == TOK_ATOMIC) { 192 ac--; av++; 193 NEED1("atomic needs command"); 194 tcmd = get_token(tablecmds, *av, "table command"); 195 switch (tcmd) { 196 case TOK_ADD: 197 break; 198 default: 199 errx(EX_USAGE, "atomic is not compatible with %s", *av); 200 } 201 atomic = 1; 202 } 203 204 switch (tcmd) { 205 case TOK_LIST: 206 case TOK_INFO: 207 case TOK_DETAIL: 208 case TOK_FLUSH: 209 break; 210 default: 211 if (is_all != 0) 212 errx(EX_USAGE, "table name required"); 213 } 214 215 switch (tcmd) { 216 case TOK_ADD: 217 case TOK_DEL: 218 do_add = **av == 'a'; 219 ac--; av++; 220 table_modify_record(&oh, ac, av, do_add, co.do_quiet, 221 co.do_quiet, atomic); 222 break; 223 case TOK_CREATE: 224 ac--; av++; 225 table_create(&oh, ac, av); 226 break; 227 case TOK_MODIFY: 228 ac--; av++; 229 table_modify(&oh, ac, av); 230 break; 231 case TOK_DESTROY: 232 if (table_destroy(&oh) == 0) 233 break; 234 if (errno != ESRCH) 235 err(EX_OSERR, "failed to destroy table %s", tablename); 236 /* ESRCH isn't fatal, warn if not quiet mode */ 237 if (co.do_quiet == 0) 238 warn("failed to destroy table %s", tablename); 239 break; 240 case TOK_FLUSH: 241 if (is_all == 0) { 242 if ((error = table_flush(&oh)) == 0) 243 break; 244 if (errno != ESRCH) 245 err(EX_OSERR, "failed to flush table %s info", 246 tablename); 247 /* ESRCH isn't fatal, warn if not quiet mode */ 248 if (co.do_quiet == 0) 249 warn("failed to flush table %s info", 250 tablename); 251 } else { 252 error = tables_foreach(table_flush_one, &oh, 1); 253 if (error != 0) 254 err(EX_OSERR, "failed to flush tables list"); 255 /* XXX: we ignore errors here */ 256 } 257 break; 258 case TOK_SWAP: 259 ac--; av++; 260 NEED1("second table name required"); 261 table_swap(&oh, *av); 262 break; 263 case TOK_LOCK: 264 case TOK_UNLOCK: 265 table_lock(&oh, (tcmd == TOK_LOCK)); 266 break; 267 case TOK_DETAIL: 268 case TOK_INFO: 269 arg = (tcmd == TOK_DETAIL) ? (void *)1 : NULL; 270 if (is_all == 0) { 271 if ((error = table_get_info(&oh, &i)) != 0) 272 err(EX_OSERR, "failed to request table info"); 273 table_show_info(&i, arg); 274 } else { 275 error = tables_foreach(table_show_info, arg, 1); 276 if (error != 0) 277 err(EX_OSERR, "failed to request tables list"); 278 } 279 break; 280 case TOK_LIST: 281 if (is_all == 0) { 282 ipfw_xtable_info i; 283 if ((error = table_get_info(&oh, &i)) != 0) 284 err(EX_OSERR, "failed to request table info"); 285 table_show_one(&i, NULL); 286 } else { 287 error = tables_foreach(table_show_one, NULL, 1); 288 if (error != 0) 289 err(EX_OSERR, "failed to request tables list"); 290 } 291 break; 292 case TOK_LOOKUP: 293 ac--; av++; 294 table_lookup(&oh, ac, av); 295 break; 296 } 297 } 298 299 static void 300 table_fill_ntlv(ipfw_obj_ntlv *ntlv, const char *name, uint32_t set, 301 uint16_t uidx) 302 { 303 304 ntlv->head.type = IPFW_TLV_TBL_NAME; 305 ntlv->head.length = sizeof(ipfw_obj_ntlv); 306 ntlv->idx = uidx; 307 ntlv->set = set; 308 strlcpy(ntlv->name, name, sizeof(ntlv->name)); 309 } 310 311 static void 312 table_fill_objheader(ipfw_obj_header *oh, ipfw_xtable_info *i) 313 { 314 315 oh->idx = 1; 316 table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 317 } 318 319 static struct _s_x tablenewcmds[] = { 320 { "type", TOK_TYPE }, 321 { "valtype", TOK_VALTYPE }, 322 { "algo", TOK_ALGO }, 323 { "limit", TOK_LIMIT }, 324 { "locked", TOK_LOCK }, 325 { NULL, 0 } 326 }; 327 328 static struct _s_x flowtypecmds[] = { 329 { "src-ip", IPFW_TFFLAG_SRCIP }, 330 { "proto", IPFW_TFFLAG_PROTO }, 331 { "src-port", IPFW_TFFLAG_SRCPORT }, 332 { "dst-ip", IPFW_TFFLAG_DSTIP }, 333 { "dst-port", IPFW_TFFLAG_DSTPORT }, 334 { NULL, 0 } 335 }; 336 337 int 338 table_parse_type(uint8_t ttype, char *p, uint8_t *tflags) 339 { 340 uint32_t fset, fclear; 341 char *e; 342 343 /* Parse type options */ 344 switch(ttype) { 345 case IPFW_TABLE_FLOW: 346 fset = fclear = 0; 347 if (fill_flags(flowtypecmds, p, &e, &fset, &fclear) != 0) 348 errx(EX_USAGE, 349 "unable to parse flow option %s", e); 350 *tflags = fset; 351 break; 352 default: 353 return (EX_USAGE); 354 } 355 356 return (0); 357 } 358 359 void 360 table_print_type(char *tbuf, size_t size, uint8_t type, uint8_t tflags) 361 { 362 const char *tname; 363 int l; 364 365 if ((tname = match_value(tabletypes, type)) == NULL) 366 tname = "unknown"; 367 368 l = snprintf(tbuf, size, "%s", tname); 369 tbuf += l; 370 size -= l; 371 372 switch(type) { 373 case IPFW_TABLE_FLOW: 374 if (tflags != 0) { 375 *tbuf++ = ':'; 376 l--; 377 print_flags_buffer(tbuf, size, flowtypecmds, tflags); 378 } 379 break; 380 } 381 } 382 383 /* 384 * Creates new table 385 * 386 * ipfw table NAME create [ type { addr | iface | number | flow } ] 387 * [ algo algoname ] 388 */ 389 static void 390 table_create(ipfw_obj_header *oh, int ac, char *av[]) 391 { 392 ipfw_xtable_info xi; 393 int error, tcmd, val; 394 uint32_t fset, fclear; 395 char *e, *p; 396 char tbuf[128]; 397 398 memset(&xi, 0, sizeof(xi)); 399 400 while (ac > 0) { 401 tcmd = get_token(tablenewcmds, *av, "option"); 402 ac--; av++; 403 404 switch (tcmd) { 405 case TOK_LIMIT: 406 NEED1("limit value required"); 407 xi.limit = strtol(*av, NULL, 10); 408 ac--; av++; 409 break; 410 case TOK_TYPE: 411 NEED1("table type required"); 412 /* Type may have suboptions after ':' */ 413 if ((p = strchr(*av, ':')) != NULL) 414 *p++ = '\0'; 415 val = match_token(tabletypes, *av); 416 if (val == -1) { 417 concat_tokens(tbuf, sizeof(tbuf), tabletypes, 418 ", "); 419 errx(EX_USAGE, 420 "Unknown tabletype: %s. Supported: %s", 421 *av, tbuf); 422 } 423 xi.type = val; 424 if (p != NULL) { 425 error = table_parse_type(val, p, &xi.tflags); 426 if (error != 0) 427 errx(EX_USAGE, 428 "Unsupported suboptions: %s", p); 429 } 430 ac--; av++; 431 break; 432 case TOK_VALTYPE: 433 NEED1("table value type required"); 434 fset = fclear = 0; 435 val = fill_flags(tablevaltypes, *av, &e, &fset, &fclear); 436 if (val != -1) { 437 xi.vmask = fset; 438 ac--; av++; 439 break; 440 } 441 concat_tokens(tbuf, sizeof(tbuf), tablevaltypes, ", "); 442 errx(EX_USAGE, "Unknown value type: %s. Supported: %s", 443 e, tbuf); 444 break; 445 case TOK_ALGO: 446 NEED1("table algorithm name required"); 447 if (strlen(*av) > sizeof(xi.algoname)) 448 errx(EX_USAGE, "algorithm name too long"); 449 strlcpy(xi.algoname, *av, sizeof(xi.algoname)); 450 ac--; av++; 451 break; 452 case TOK_LOCK: 453 xi.flags |= IPFW_TGFLAGS_LOCKED; 454 break; 455 } 456 } 457 458 /* Set some defaults to preserve compatibility. */ 459 if (xi.algoname[0] == '\0' && xi.type == 0) 460 xi.type = IPFW_TABLE_ADDR; 461 if (xi.vmask == 0) 462 xi.vmask = IPFW_VTYPE_LEGACY; 463 464 if ((error = table_do_create(oh, &xi)) != 0) 465 err(EX_OSERR, "Table creation failed"); 466 } 467 468 /* 469 * Creates new table 470 * 471 * Request: [ ipfw_obj_header ipfw_xtable_info ] 472 * 473 * Returns 0 on success. 474 */ 475 static int 476 table_do_create(ipfw_obj_header *oh, ipfw_xtable_info *i) 477 { 478 char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 479 int error; 480 481 memcpy(tbuf, oh, sizeof(*oh)); 482 memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 483 oh = (ipfw_obj_header *)tbuf; 484 485 error = do_set3(IP_FW_TABLE_XCREATE, &oh->opheader, sizeof(tbuf)); 486 487 return (error); 488 } 489 490 /* 491 * Modifies existing table 492 * 493 * ipfw table NAME modify [ limit number ] 494 */ 495 static void 496 table_modify(ipfw_obj_header *oh, int ac, char *av[]) 497 { 498 ipfw_xtable_info xi; 499 int tcmd; 500 501 memset(&xi, 0, sizeof(xi)); 502 503 while (ac > 0) { 504 tcmd = get_token(tablenewcmds, *av, "option"); 505 ac--; av++; 506 507 switch (tcmd) { 508 case TOK_LIMIT: 509 NEED1("limit value required"); 510 xi.limit = strtol(*av, NULL, 10); 511 xi.mflags |= IPFW_TMFLAGS_LIMIT; 512 ac--; av++; 513 break; 514 default: 515 errx(EX_USAGE, "cmd is not supported for modificatiob"); 516 } 517 } 518 519 if (table_do_modify(oh, &xi) != 0) 520 err(EX_OSERR, "Table modification failed"); 521 } 522 523 /* 524 * Modifies existing table. 525 * 526 * Request: [ ipfw_obj_header ipfw_xtable_info ] 527 * 528 * Returns 0 on success. 529 */ 530 static int 531 table_do_modify(ipfw_obj_header *oh, ipfw_xtable_info *i) 532 { 533 char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 534 int error; 535 536 memcpy(tbuf, oh, sizeof(*oh)); 537 memcpy(tbuf + sizeof(*oh), i, sizeof(*i)); 538 oh = (ipfw_obj_header *)tbuf; 539 540 error = do_set3(IP_FW_TABLE_XMODIFY, &oh->opheader, sizeof(tbuf)); 541 542 return (error); 543 } 544 545 /* 546 * Locks or unlocks given table 547 */ 548 static void 549 table_lock(ipfw_obj_header *oh, int lock) 550 { 551 ipfw_xtable_info xi; 552 553 memset(&xi, 0, sizeof(xi)); 554 555 xi.mflags |= IPFW_TMFLAGS_LOCK; 556 xi.flags |= (lock != 0) ? IPFW_TGFLAGS_LOCKED : 0; 557 558 if (table_do_modify(oh, &xi) != 0) 559 err(EX_OSERR, "Table %s failed", lock != 0 ? "lock" : "unlock"); 560 } 561 562 /* 563 * Destroys given table specified by @oh->ntlv. 564 * Returns 0 on success. 565 */ 566 static int 567 table_destroy(ipfw_obj_header *oh) 568 { 569 570 if (do_set3(IP_FW_TABLE_XDESTROY, &oh->opheader, sizeof(*oh)) != 0) 571 return (-1); 572 573 return (0); 574 } 575 576 /* 577 * Flushes given table specified by @oh->ntlv. 578 * Returns 0 on success. 579 */ 580 static int 581 table_flush(ipfw_obj_header *oh) 582 { 583 584 if (do_set3(IP_FW_TABLE_XFLUSH, &oh->opheader, sizeof(*oh)) != 0) 585 return (-1); 586 587 return (0); 588 } 589 590 static int 591 table_do_swap(ipfw_obj_header *oh, char *second) 592 { 593 char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_ntlv)]; 594 int error; 595 596 memset(tbuf, 0, sizeof(tbuf)); 597 memcpy(tbuf, oh, sizeof(*oh)); 598 oh = (ipfw_obj_header *)tbuf; 599 table_fill_ntlv((ipfw_obj_ntlv *)(oh + 1), second, oh->ntlv.set, 1); 600 601 error = do_set3(IP_FW_TABLE_XSWAP, &oh->opheader, sizeof(tbuf)); 602 603 return (error); 604 } 605 606 /* 607 * Swaps given table with @second one. 608 */ 609 static int 610 table_swap(ipfw_obj_header *oh, char *second) 611 { 612 613 if (table_check_name(second) != 0) 614 errx(EX_USAGE, "table name %s is invalid", second); 615 616 if (table_do_swap(oh, second) == 0) 617 return (0); 618 619 switch (errno) { 620 case EINVAL: 621 errx(EX_USAGE, "Unable to swap table: check types"); 622 case EFBIG: 623 errx(EX_USAGE, "Unable to swap table: check limits"); 624 } 625 626 return (0); 627 } 628 629 630 /* 631 * Retrieves table in given table specified by @oh->ntlv. 632 * it inside @i. 633 * Returns 0 on success. 634 */ 635 static int 636 table_get_info(ipfw_obj_header *oh, ipfw_xtable_info *i) 637 { 638 char tbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_xtable_info)]; 639 size_t sz; 640 641 sz = sizeof(tbuf); 642 memset(tbuf, 0, sizeof(tbuf)); 643 memcpy(tbuf, oh, sizeof(*oh)); 644 oh = (ipfw_obj_header *)tbuf; 645 646 if (do_get3(IP_FW_TABLE_XINFO, &oh->opheader, &sz) != 0) 647 return (errno); 648 649 if (sz < sizeof(tbuf)) 650 return (EINVAL); 651 652 *i = *(ipfw_xtable_info *)(oh + 1); 653 654 return (0); 655 } 656 657 static struct _s_x tablealgoclass[] = { 658 { "hash", IPFW_TACLASS_HASH }, 659 { "array", IPFW_TACLASS_ARRAY }, 660 { "radix", IPFW_TACLASS_RADIX }, 661 { NULL, 0 } 662 }; 663 664 struct ta_cldata { 665 uint8_t taclass; 666 uint8_t spare4; 667 uint16_t itemsize; 668 uint16_t itemsize6; 669 uint32_t size; 670 uint32_t count; 671 }; 672 673 /* 674 * Print global/per-AF table @i algorithm info. 675 */ 676 static void 677 table_show_tainfo(ipfw_xtable_info *i, struct ta_cldata *d, 678 const char *af, const char *taclass) 679 { 680 681 switch (d->taclass) { 682 case IPFW_TACLASS_HASH: 683 case IPFW_TACLASS_ARRAY: 684 printf(" %salgorithm %s info\n", af, taclass); 685 if (d->itemsize == d->itemsize6) 686 printf(" size: %u items: %u itemsize: %u\n", 687 d->size, d->count, d->itemsize); 688 else 689 printf(" size: %u items: %u " 690 "itemsize4: %u itemsize6: %u\n", 691 d->size, d->count, 692 d->itemsize, d->itemsize6); 693 break; 694 case IPFW_TACLASS_RADIX: 695 printf(" %salgorithm %s info\n", af, taclass); 696 if (d->itemsize == d->itemsize6) 697 printf(" items: %u itemsize: %u\n", 698 d->count, d->itemsize); 699 else 700 printf(" items: %u " 701 "itemsize4: %u itemsize6: %u\n", 702 d->count, d->itemsize, d->itemsize6); 703 break; 704 default: 705 printf(" algo class: %s\n", taclass); 706 } 707 } 708 709 static void 710 table_print_valheader(char *buf, size_t bufsize, uint32_t vmask) 711 { 712 713 if (vmask == IPFW_VTYPE_LEGACY) { 714 snprintf(buf, bufsize, "legacy"); 715 return; 716 } 717 718 memset(buf, 0, bufsize); 719 print_flags_buffer(buf, bufsize, tablevaltypes, vmask); 720 } 721 722 /* 723 * Prints table info struct @i in human-readable form. 724 */ 725 static int 726 table_show_info(ipfw_xtable_info *i, void *arg) 727 { 728 const char *vtype; 729 ipfw_ta_tinfo *tainfo; 730 int afdata, afitem; 731 struct ta_cldata d; 732 char ttype[64], tvtype[64]; 733 734 table_print_type(ttype, sizeof(ttype), i->type, i->tflags); 735 table_print_valheader(tvtype, sizeof(tvtype), i->vmask); 736 737 printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 738 if ((i->flags & IPFW_TGFLAGS_LOCKED) != 0) 739 printf(" kindex: %d, type: %s, locked\n", i->kidx, ttype); 740 else 741 printf(" kindex: %d, type: %s\n", i->kidx, ttype); 742 printf(" references: %u, valtype: %s\n", i->refcnt, tvtype); 743 printf(" algorithm: %s\n", i->algoname); 744 printf(" items: %u, size: %u\n", i->count, i->size); 745 if (i->limit > 0) 746 printf(" limit: %u\n", i->limit); 747 748 /* Print algo-specific info if requested & set */ 749 if (arg == NULL) 750 return (0); 751 752 if ((i->ta_info.flags & IPFW_TATFLAGS_DATA) == 0) 753 return (0); 754 tainfo = &i->ta_info; 755 756 afdata = 0; 757 afitem = 0; 758 if (tainfo->flags & IPFW_TATFLAGS_AFDATA) 759 afdata = 1; 760 if (tainfo->flags & IPFW_TATFLAGS_AFITEM) 761 afitem = 1; 762 763 memset(&d, 0, sizeof(d)); 764 d.taclass = tainfo->taclass4; 765 d.size = tainfo->size4; 766 d.count = tainfo->count4; 767 d.itemsize = tainfo->itemsize4; 768 if (afdata == 0 && afitem != 0) 769 d.itemsize6 = tainfo->itemsize6; 770 else 771 d.itemsize6 = d.itemsize; 772 if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 773 vtype = "unknown"; 774 775 if (afdata == 0) { 776 table_show_tainfo(i, &d, "", vtype); 777 } else { 778 table_show_tainfo(i, &d, "IPv4 ", vtype); 779 memset(&d, 0, sizeof(d)); 780 d.taclass = tainfo->taclass6; 781 if ((vtype = match_value(tablealgoclass, d.taclass)) == NULL) 782 vtype = "unknown"; 783 d.size = tainfo->size6; 784 d.count = tainfo->count6; 785 d.itemsize = tainfo->itemsize6; 786 d.itemsize6 = d.itemsize; 787 table_show_tainfo(i, &d, "IPv6 ", vtype); 788 } 789 790 return (0); 791 } 792 793 794 /* 795 * Function wrappers which can be used either 796 * as is or as foreach function parameter. 797 */ 798 799 static int 800 table_show_one(ipfw_xtable_info *i, void *arg) 801 { 802 ipfw_obj_header *oh; 803 int error; 804 805 if ((error = table_do_get_list(i, &oh)) != 0) { 806 err(EX_OSERR, "Error requesting table %s list", i->tablename); 807 return (error); 808 } 809 810 table_show_list(oh, 1); 811 812 free(oh); 813 return (0); 814 } 815 816 static int 817 table_flush_one(ipfw_xtable_info *i, void *arg) 818 { 819 ipfw_obj_header *oh; 820 821 oh = (ipfw_obj_header *)arg; 822 823 table_fill_ntlv(&oh->ntlv, i->tablename, i->set, 1); 824 825 return (table_flush(oh)); 826 } 827 828 static int 829 table_do_modify_record(int cmd, ipfw_obj_header *oh, 830 ipfw_obj_tentry *tent, int count, int atomic) 831 { 832 ipfw_obj_ctlv *ctlv; 833 ipfw_obj_tentry *tent_base; 834 caddr_t pbuf; 835 char xbuf[sizeof(*oh) + sizeof(ipfw_obj_ctlv) + sizeof(*tent)]; 836 int error, i; 837 size_t sz; 838 839 sz = sizeof(*ctlv) + sizeof(*tent) * count; 840 if (count == 1) { 841 memset(xbuf, 0, sizeof(xbuf)); 842 pbuf = xbuf; 843 } else { 844 if ((pbuf = calloc(1, sizeof(*oh) + sz)) == NULL) 845 return (ENOMEM); 846 } 847 848 memcpy(pbuf, oh, sizeof(*oh)); 849 oh = (ipfw_obj_header *)pbuf; 850 oh->opheader.version = 1; 851 852 ctlv = (ipfw_obj_ctlv *)(oh + 1); 853 ctlv->count = count; 854 ctlv->head.length = sz; 855 if (atomic != 0) 856 ctlv->flags |= IPFW_CTF_ATOMIC; 857 858 tent_base = tent; 859 memcpy(ctlv + 1, tent, sizeof(*tent) * count); 860 tent = (ipfw_obj_tentry *)(ctlv + 1); 861 for (i = 0; i < count; i++, tent++) { 862 tent->head.length = sizeof(ipfw_obj_tentry); 863 tent->idx = oh->idx; 864 } 865 866 sz += sizeof(*oh); 867 error = do_get3(cmd, &oh->opheader, &sz); 868 tent = (ipfw_obj_tentry *)(ctlv + 1); 869 /* Copy result back to provided buffer */ 870 memcpy(tent_base, ctlv + 1, sizeof(*tent) * count); 871 872 if (pbuf != xbuf) 873 free(pbuf); 874 875 return (error); 876 } 877 878 static void 879 table_modify_record(ipfw_obj_header *oh, int ac, char *av[], int add, 880 int quiet, int update, int atomic) 881 { 882 ipfw_obj_tentry *ptent, tent, *tent_buf; 883 ipfw_xtable_info xi; 884 uint8_t type; 885 uint32_t vmask; 886 int cmd, count, error, i, ignored; 887 char *texterr, *etxt, *px; 888 889 if (ac == 0) 890 errx(EX_USAGE, "address required"); 891 892 if (add != 0) { 893 cmd = IP_FW_TABLE_XADD; 894 texterr = "Adding record failed"; 895 } else { 896 cmd = IP_FW_TABLE_XDEL; 897 texterr = "Deleting record failed"; 898 } 899 900 /* 901 * Calculate number of entries: 902 * Assume [key val] x N for add 903 * and 904 * key x N for delete 905 */ 906 count = (add != 0) ? ac / 2 + 1 : ac; 907 908 if (count <= 1) { 909 /* Adding single entry with/without value */ 910 memset(&tent, 0, sizeof(tent)); 911 tent_buf = &tent; 912 } else { 913 914 if ((tent_buf = calloc(count, sizeof(tent))) == NULL) 915 errx(EX_OSERR, 916 "Unable to allocate memory for all entries"); 917 } 918 ptent = tent_buf; 919 920 memset(&xi, 0, sizeof(xi)); 921 count = 0; 922 while (ac > 0) { 923 tentry_fill_key(oh, ptent, *av, add, &type, &vmask, &xi); 924 925 /* 926 * Compatibility layer: auto-create table if not exists. 927 */ 928 if (xi.tablename[0] == '\0') { 929 xi.type = type; 930 xi.vmask = vmask; 931 strlcpy(xi.tablename, oh->ntlv.name, 932 sizeof(xi.tablename)); 933 if (quiet == 0) 934 warnx("DEPRECATED: inserting data into " 935 "non-existent table %s. (auto-created)", 936 xi.tablename); 937 table_do_create(oh, &xi); 938 } 939 940 oh->ntlv.type = type; 941 ac--; av++; 942 943 if (add != 0 && ac > 0) { 944 tentry_fill_value(oh, ptent, *av, type, vmask); 945 ac--; av++; 946 } 947 948 if (update != 0) 949 ptent->head.flags |= IPFW_TF_UPDATE; 950 951 count++; 952 ptent++; 953 } 954 955 error = table_do_modify_record(cmd, oh, tent_buf, count, atomic); 956 957 /* 958 * Compatibility stuff: do not yell on duplicate keys or 959 * failed deletions. 960 */ 961 if (error == 0 || (error == EEXIST && add != 0) || 962 (error == ENOENT && add == 0)) { 963 if (quiet != 0) { 964 if (tent_buf != &tent) 965 free(tent_buf); 966 return; 967 } 968 } 969 970 /* Report results back */ 971 ptent = tent_buf; 972 for (i = 0; i < count; ptent++, i++) { 973 ignored = 0; 974 switch (ptent->result) { 975 case IPFW_TR_ADDED: 976 px = "added"; 977 break; 978 case IPFW_TR_DELETED: 979 px = "deleted"; 980 break; 981 case IPFW_TR_UPDATED: 982 px = "updated"; 983 break; 984 case IPFW_TR_LIMIT: 985 px = "limit"; 986 ignored = 1; 987 break; 988 case IPFW_TR_ERROR: 989 px = "error"; 990 ignored = 1; 991 break; 992 case IPFW_TR_NOTFOUND: 993 px = "notfound"; 994 ignored = 1; 995 break; 996 case IPFW_TR_EXISTS: 997 px = "exists"; 998 ignored = 1; 999 break; 1000 case IPFW_TR_IGNORED: 1001 px = "ignored"; 1002 ignored = 1; 1003 break; 1004 default: 1005 px = "unknown"; 1006 ignored = 1; 1007 } 1008 1009 if (error != 0 && atomic != 0 && ignored == 0) 1010 printf("%s(reverted): ", px); 1011 else 1012 printf("%s: ", px); 1013 1014 table_show_entry(&xi, ptent); 1015 } 1016 1017 if (tent_buf != &tent) 1018 free(tent_buf); 1019 1020 if (error == 0) 1021 return; 1022 /* Get real OS error */ 1023 error = errno; 1024 1025 /* Try to provide more human-readable error */ 1026 switch (error) { 1027 case EEXIST: 1028 etxt = "record already exists"; 1029 break; 1030 case EFBIG: 1031 etxt = "limit hit"; 1032 break; 1033 case ESRCH: 1034 etxt = "table not found"; 1035 break; 1036 case ENOENT: 1037 etxt = "record not found"; 1038 break; 1039 case EACCES: 1040 etxt = "table is locked"; 1041 break; 1042 default: 1043 etxt = strerror(error); 1044 } 1045 1046 errx(EX_OSERR, "%s: %s", texterr, etxt); 1047 } 1048 1049 static int 1050 table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 1051 ipfw_obj_tentry *xtent) 1052 { 1053 char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 1054 ipfw_obj_tentry *tent; 1055 uint8_t type; 1056 uint32_t vmask; 1057 size_t sz; 1058 1059 memcpy(xbuf, oh, sizeof(*oh)); 1060 oh = (ipfw_obj_header *)xbuf; 1061 tent = (ipfw_obj_tentry *)(oh + 1); 1062 1063 memset(tent, 0, sizeof(*tent)); 1064 tent->head.length = sizeof(*tent); 1065 tent->idx = 1; 1066 1067 tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); 1068 oh->ntlv.type = type; 1069 1070 sz = sizeof(xbuf); 1071 if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0) 1072 return (errno); 1073 1074 if (sz < sizeof(xbuf)) 1075 return (EINVAL); 1076 1077 *xtent = *tent; 1078 1079 return (0); 1080 } 1081 1082 static void 1083 table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 1084 { 1085 ipfw_obj_tentry xtent; 1086 ipfw_xtable_info xi; 1087 char key[64]; 1088 int error; 1089 1090 if (ac == 0) 1091 errx(EX_USAGE, "address required"); 1092 1093 strlcpy(key, *av, sizeof(key)); 1094 1095 memset(&xi, 0, sizeof(xi)); 1096 error = table_do_lookup(oh, key, &xi, &xtent); 1097 1098 switch (error) { 1099 case 0: 1100 break; 1101 case ESRCH: 1102 errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 1103 case ENOENT: 1104 errx(EX_UNAVAILABLE, "Entry %s not found", *av); 1105 case ENOTSUP: 1106 errx(EX_UNAVAILABLE, "Table %s algo does not support " 1107 "\"lookup\" method", oh->ntlv.name); 1108 default: 1109 err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 1110 } 1111 1112 table_show_entry(&xi, &xtent); 1113 } 1114 1115 static void 1116 tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 1117 uint8_t tflags) 1118 { 1119 char *p, *pp; 1120 int mask, af; 1121 struct in6_addr *paddr, tmp; 1122 struct tflow_entry *tfe; 1123 uint32_t key, *pkey; 1124 uint16_t port; 1125 struct protoent *pent; 1126 struct servent *sent; 1127 int masklen; 1128 1129 masklen = 0; 1130 af = 0; 1131 paddr = (struct in6_addr *)&tentry->k; 1132 1133 switch (type) { 1134 case IPFW_TABLE_ADDR: 1135 /* Remove / if exists */ 1136 if ((p = strchr(arg, '/')) != NULL) { 1137 *p = '\0'; 1138 mask = atoi(p + 1); 1139 } 1140 1141 if (inet_pton(AF_INET, arg, paddr) == 1) { 1142 if (p != NULL && mask > 32) 1143 errx(EX_DATAERR, "bad IPv4 mask width: %s", 1144 p + 1); 1145 1146 masklen = p ? mask : 32; 1147 af = AF_INET; 1148 } else if (inet_pton(AF_INET6_LINUX, arg, paddr) == 1) { 1149 if (IN6_IS_ADDR_V4COMPAT(paddr)) 1150 errx(EX_DATAERR, 1151 "Use IPv4 instead of v4-compatible"); 1152 if (p != NULL && mask > 128) 1153 errx(EX_DATAERR, "bad IPv6 mask width: %s", 1154 p + 1); 1155 1156 masklen = p ? mask : 128; 1157 af = AF_INET6_LINUX; 1158 } else { 1159 /* Assume FQDN */ 1160 if (lookup_host(arg, (struct in_addr *)paddr) != 0) 1161 errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 1162 1163 masklen = 32; 1164 type = IPFW_TABLE_ADDR; 1165 af = AF_INET; 1166 } 1167 break; 1168 case IPFW_TABLE_INTERFACE: 1169 /* Assume interface name. Copy significant data only */ 1170 mask = MIN(strlen(arg), IF_NAMESIZE - 1); 1171 memcpy(paddr, arg, mask); 1172 /* Set mask to exact match */ 1173 masklen = 8 * IF_NAMESIZE; 1174 break; 1175 case IPFW_TABLE_NUMBER: 1176 /* Port or any other key */ 1177 key = strtol(arg, &p, 10); 1178 if (*p != '\0') 1179 errx(EX_DATAERR, "Invalid number: %s", arg); 1180 1181 pkey = (uint32_t *)paddr; 1182 *pkey = key; 1183 masklen = 32; 1184 break; 1185 case IPFW_TABLE_FLOW: 1186 /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 1187 tfe = &tentry->k.flow; 1188 af = 0; 1189 1190 /* Handle <ipv4|ipv6> */ 1191 if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 1192 if ((p = strchr(arg, ',')) != NULL) 1193 *p++ = '\0'; 1194 /* Determine family using temporary storage */ 1195 if (inet_pton(AF_INET, arg, &tmp) == 1) { 1196 if (af != 0 && af != AF_INET) 1197 errx(EX_DATAERR, 1198 "Inconsistent address family\n"); 1199 af = AF_INET; 1200 memcpy(&tfe->a.a4.sip, &tmp, 4); 1201 } else if (inet_pton(AF_INET6_LINUX, arg, &tmp) == 1) { 1202 if (af != 0 && af != AF_INET6_LINUX) 1203 errx(EX_DATAERR, 1204 "Inconsistent address family\n"); 1205 af = AF_INET6_LINUX; 1206 memcpy(&tfe->a.a6.sip6, &tmp, 16); 1207 } 1208 1209 arg = p; 1210 } 1211 1212 /* Handle <proto-num|proto-name> */ 1213 if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 1214 if (arg == NULL) 1215 errx(EX_DATAERR, "invalid key: proto missing"); 1216 if ((p = strchr(arg, ',')) != NULL) 1217 *p++ = '\0'; 1218 1219 key = strtol(arg, &pp, 10); 1220 if (*pp != '\0') { 1221 if ((pent = getprotobyname(arg)) == NULL) 1222 errx(EX_DATAERR, "Unknown proto: %s", 1223 arg); 1224 else 1225 key = pent->p_proto; 1226 } 1227 1228 if (key > 255) 1229 errx(EX_DATAERR, "Bad protocol number: %u",key); 1230 1231 tfe->proto = key; 1232 1233 arg = p; 1234 } 1235 1236 /* Handle <port-num|service-name> */ 1237 if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1238 if (arg == NULL) 1239 errx(EX_DATAERR, "invalid key: src port missing"); 1240 if ((p = strchr(arg, ',')) != NULL) 1241 *p++ = '\0'; 1242 1243 if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1244 if ((sent = getservbyname(arg, NULL)) == NULL) 1245 errx(EX_DATAERR, "Unknown service: %s", 1246 arg); 1247 else 1248 key = sent->s_port; 1249 } 1250 1251 tfe->sport = port; 1252 1253 arg = p; 1254 } 1255 1256 /* Handle <ipv4|ipv6>*/ 1257 if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 1258 if (arg == NULL) 1259 errx(EX_DATAERR, "invalid key: dst ip missing"); 1260 if ((p = strchr(arg, ',')) != NULL) 1261 *p++ = '\0'; 1262 /* Determine family using temporary storage */ 1263 if (inet_pton(AF_INET, arg, &tmp) == 1) { 1264 if (af != 0 && af != AF_INET) 1265 errx(EX_DATAERR, 1266 "Inconsistent address family"); 1267 af = AF_INET; 1268 memcpy(&tfe->a.a4.dip, &tmp, 4); 1269 } else if (inet_pton(AF_INET6_LINUX, arg, &tmp) == 1) { 1270 if (af != 0 && af != AF_INET6_LINUX) 1271 errx(EX_DATAERR, 1272 "Inconsistent address family"); 1273 af = AF_INET6_LINUX; 1274 memcpy(&tfe->a.a6.dip6, &tmp, 16); 1275 } 1276 1277 arg = p; 1278 } 1279 1280 /* Handle <port-num|service-name> */ 1281 if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1282 if (arg == NULL) 1283 errx(EX_DATAERR, "invalid key: dst port missing"); 1284 if ((p = strchr(arg, ',')) != NULL) 1285 *p++ = '\0'; 1286 1287 if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1288 if ((sent = getservbyname(arg, NULL)) == NULL) 1289 errx(EX_DATAERR, "Unknown service: %s", 1290 arg); 1291 else 1292 key = sent->s_port; 1293 } 1294 1295 tfe->dport = port; 1296 1297 arg = p; 1298 } 1299 1300 tfe->af = af; 1301 1302 break; 1303 1304 default: 1305 errx(EX_DATAERR, "Unsupported table type: %d", type); 1306 } 1307 1308 tentry->subtype = af; 1309 tentry->masklen = masklen; 1310 } 1311 1312 /* 1313 * Tries to guess table key type. 1314 * This procedure is used in legacy table auto-create 1315 * code AND in `ipfw -n` ruleset checking. 1316 * 1317 * Imported from old table_fill_xentry() parse code. 1318 */ 1319 static int 1320 guess_key_type(char *key, uint8_t *ptype) 1321 { 1322 char *p; 1323 struct in6_addr addr; 1324 uint32_t kv; 1325 1326 if (ishexnumber(*key) != 0 || *key == ':') { 1327 /* Remove / if exists */ 1328 if ((p = strchr(key, '/')) != NULL) 1329 *p = '\0'; 1330 1331 if ((inet_pton(AF_INET, key, &addr) == 1) || 1332 (inet_pton(AF_INET6_LINUX, key, &addr) == 1)) { 1333 *ptype = IPFW_TABLE_CIDR; 1334 if (p != NULL) 1335 *p = '/'; 1336 return (0); 1337 } else { 1338 /* Port or any other key */ 1339 /* Skip non-base 10 entries like 'fa1' */ 1340 kv = strtol(key, &p, 10); 1341 if (*p == '\0') { 1342 *ptype = IPFW_TABLE_NUMBER; 1343 return (0); 1344 } else if ((p != key) && (*p == '.')) { 1345 /* 1346 * Warn on IPv4 address strings 1347 * which are "valid" for inet_aton() but not 1348 * in inet_pton(). 1349 * 1350 * Typical examples: '10.5' or '10.0.0.05' 1351 */ 1352 return (1); 1353 } 1354 } 1355 } 1356 1357 if (strchr(key, '.') == NULL) { 1358 *ptype = IPFW_TABLE_INTERFACE; 1359 return (0); 1360 } 1361 1362 if (lookup_host(key, (struct in_addr *)&addr) != 0) 1363 return (1); 1364 1365 *ptype = IPFW_TABLE_CIDR; 1366 return (0); 1367 } 1368 1369 static void 1370 tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 1371 int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi) 1372 { 1373 uint8_t type, tflags; 1374 uint32_t vmask; 1375 int error; 1376 1377 type = 0; 1378 tflags = 0; 1379 vmask = 0; 1380 1381 if (xi->tablename[0] == '\0') 1382 error = table_get_info(oh, xi); 1383 else 1384 error = 0; 1385 1386 if (error == 0) { 1387 if (co.test_only == 0) { 1388 /* Table found */ 1389 type = xi->type; 1390 tflags = xi->tflags; 1391 vmask = xi->vmask; 1392 } else { 1393 /* 1394 * We're running `ipfw -n` 1395 * Compatibility layer: try to guess key type 1396 * before failing. 1397 */ 1398 if (guess_key_type(key, &type) != 0) { 1399 /* Inknown key */ 1400 errx(EX_USAGE, "Cannot guess " 1401 "key '%s' type", key); 1402 } 1403 vmask = IPFW_VTYPE_LEGACY; 1404 } 1405 } else { 1406 if (error != ESRCH) 1407 errx(EX_OSERR, "Error requesting table %s info", 1408 oh->ntlv.name); 1409 if (add == 0) 1410 errx(EX_DATAERR, "Table %s does not exist", 1411 oh->ntlv.name); 1412 /* 1413 * Table does not exist 1414 * Compatibility layer: try to guess key type before failing. 1415 */ 1416 if (guess_key_type(key, &type) != 0) { 1417 /* Inknown key */ 1418 errx(EX_USAGE, "Table %s does not exist, cannot guess " 1419 "key '%s' type", oh->ntlv.name, key); 1420 } 1421 1422 vmask = IPFW_VTYPE_LEGACY; 1423 } 1424 1425 tentry_fill_key_type(key, tent, type, tflags); 1426 1427 *ptype = type; 1428 *pvmask = vmask; 1429 } 1430 1431 static void 1432 set_legacy_value(uint32_t val, ipfw_table_value *v) 1433 { 1434 v->tag = val; 1435 v->pipe = val; 1436 v->divert = val; 1437 v->skipto = val; 1438 v->netgraph = val; 1439 v->fib = val; 1440 v->nat = val; 1441 v->nh4 = val; 1442 v->dscp = (uint8_t)val; 1443 v->limit = val; 1444 } 1445 1446 static void 1447 tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 1448 uint8_t type, uint32_t vmask) 1449 { 1450 struct addrinfo hints, *res; 1451 uint32_t a4, flag, val; 1452 ipfw_table_value *v; 1453 uint32_t i; 1454 int dval; 1455 char *comma, *e, *etype, *n, *p; 1456 1457 v = &tent->v.value; 1458 1459 /* Compat layer: keep old behavior for legacy value types */ 1460 if (vmask == IPFW_VTYPE_LEGACY) { 1461 /* Try to interpret as number first */ 1462 val = strtoul(arg, &p, 0); 1463 if (*p == '\0') { 1464 set_legacy_value(val, v); 1465 return; 1466 } 1467 if (inet_pton(AF_INET, arg, &val) == 1) { 1468 set_legacy_value(ntohl(val), v); 1469 return; 1470 } 1471 /* Try hostname */ 1472 if (lookup_host(arg, (struct in_addr *)&val) == 0) { 1473 set_legacy_value(val, v); 1474 return; 1475 } 1476 errx(EX_OSERR, "Unable to parse value %s", arg); 1477 } 1478 1479 /* 1480 * Shorthands: handle single value if vmask consists 1481 * of numbers only. e.g.: 1482 * vmask = "fib,skipto" -> treat input "1" as "1,1" 1483 */ 1484 1485 n = arg; 1486 etype = NULL; 1487 for (i = 1; i < (1 << 31); i *= 2) { 1488 if ((flag = (vmask & i)) == 0) 1489 continue; 1490 vmask &= ~flag; 1491 1492 if ((comma = strchr(n, ',')) != NULL) 1493 *comma = '\0'; 1494 1495 switch (flag) { 1496 case IPFW_VTYPE_TAG: 1497 v->tag = strtol(n, &e, 10); 1498 if (*e != '\0') 1499 etype = "tag"; 1500 break; 1501 case IPFW_VTYPE_PIPE: 1502 v->pipe = strtol(n, &e, 10); 1503 if (*e != '\0') 1504 etype = "pipe"; 1505 break; 1506 case IPFW_VTYPE_DIVERT: 1507 v->divert = strtol(n, &e, 10); 1508 if (*e != '\0') 1509 etype = "divert"; 1510 break; 1511 case IPFW_VTYPE_SKIPTO: 1512 v->skipto = strtol(n, &e, 10); 1513 if (*e != '\0') 1514 etype = "skipto"; 1515 break; 1516 case IPFW_VTYPE_NETGRAPH: 1517 v->netgraph = strtol(n, &e, 10); 1518 if (*e != '\0') 1519 etype = "netgraph"; 1520 break; 1521 case IPFW_VTYPE_FIB: 1522 v->fib = strtol(n, &e, 10); 1523 if (*e != '\0') 1524 etype = "fib"; 1525 break; 1526 case IPFW_VTYPE_NAT: 1527 v->nat = strtol(n, &e, 10); 1528 if (*e != '\0') 1529 etype = "nat"; 1530 break; 1531 case IPFW_VTYPE_LIMIT: 1532 v->limit = strtol(n, &e, 10); 1533 if (*e != '\0') 1534 etype = "limit"; 1535 break; 1536 case IPFW_VTYPE_NH4: 1537 if (strchr(n, '.') != NULL && 1538 inet_pton(AF_INET, n, &a4) == 1) { 1539 v->nh4 = ntohl(a4); 1540 break; 1541 } 1542 if (lookup_host(n, (struct in_addr *)&v->nh4) == 0) 1543 break; 1544 etype = "ipv4"; 1545 break; 1546 case IPFW_VTYPE_DSCP: 1547 if (isalpha(*n)) { 1548 if ((dval = match_token(f_ipdscp, n)) != -1) { 1549 v->dscp = dval; 1550 break; 1551 } else 1552 etype = "DSCP code"; 1553 } else { 1554 v->dscp = strtol(n, &e, 10); 1555 if (v->dscp > 63 || *e != '\0') 1556 etype = "DSCP value"; 1557 } 1558 break; 1559 case IPFW_VTYPE_NH6: 1560 if (strchr(n, ':') != NULL) { 1561 memset(&hints, 0, sizeof(hints)); 1562 hints.ai_family = AF_INET6_LINUX; 1563 hints.ai_flags = AI_NUMERICHOST; 1564 if (getaddrinfo(n, NULL, &hints, &res) == 0) { 1565 v->nh6 = ((struct sockaddr_in6 *) 1566 res->ai_addr)->sin6_addr; 1567 v->zoneid = ((struct sockaddr_in6 *) 1568 res->ai_addr)->sin6_scope_id; 1569 freeaddrinfo(res); 1570 break; 1571 } 1572 } 1573 etype = "ipv6"; 1574 break; 1575 } 1576 1577 if (etype != NULL) 1578 errx(EX_USAGE, "Unable to parse %s as %s", n, etype); 1579 1580 if (comma != NULL) 1581 *comma++ = ','; 1582 1583 if ((n = comma) != NULL) 1584 continue; 1585 1586 /* End of input. */ 1587 if (vmask != 0) 1588 errx(EX_USAGE, "Not enough fields inside value"); 1589 } 1590 } 1591 1592 /* 1593 * Compare table names. 1594 * Honor number comparison. 1595 */ 1596 static int 1597 tablename_cmp(const void *a, const void *b) 1598 { 1599 ipfw_xtable_info *ia, *ib; 1600 1601 ia = (ipfw_xtable_info *)a; 1602 ib = (ipfw_xtable_info *)b; 1603 1604 return (stringnum_cmp(ia->tablename, ib->tablename)); 1605 } 1606 1607 /* 1608 * Retrieves table list from kernel, 1609 * optionally sorts it and calls requested function for each table. 1610 * Returns 0 on success. 1611 */ 1612 static int 1613 tables_foreach(table_cb_t *f, void *arg, int sort) 1614 { 1615 ipfw_obj_lheader *olh; 1616 ipfw_xtable_info *info; 1617 size_t sz; 1618 int i, error; 1619 1620 /* Start with reasonable default */ 1621 sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); 1622 1623 for (;;) { 1624 if ((olh = calloc(1, sz)) == NULL) 1625 return (ENOMEM); 1626 1627 olh->size = sz; 1628 if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) { 1629 sz = olh->size; 1630 free(olh); 1631 if (errno != ENOMEM) 1632 return (errno); 1633 continue; 1634 } 1635 1636 if (sort != 0) 1637 qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1638 1639 info = (ipfw_xtable_info *)(olh + 1); 1640 for (i = 0; i < olh->count; i++) { 1641 error = f(info, arg); /* Ignore errors for now */ 1642 info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1643 } 1644 1645 free(olh); 1646 break; 1647 } 1648 1649 return (0); 1650 } 1651 1652 1653 /* 1654 * Retrieves all entries for given table @i in 1655 * eXtended format. Allocate buffer large enough 1656 * to store result. Called needs to free it later. 1657 * 1658 * Returns 0 on success. 1659 */ 1660 static int 1661 table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) 1662 { 1663 ipfw_obj_header *oh; 1664 size_t sz; 1665 int c; 1666 1667 sz = 0; 1668 oh = NULL; 1669 for (c = 0; c < 8; c++) { 1670 if (sz < i->size) 1671 sz = i->size + 44; 1672 if (oh != NULL) 1673 free(oh); 1674 if ((oh = calloc(1, sz)) == NULL) 1675 continue; 1676 table_fill_objheader(oh, i); 1677 oh->opheader.version = 1; /* Current version */ 1678 if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) { 1679 *poh = oh; 1680 return (0); 1681 } 1682 1683 if (errno != ENOMEM) 1684 break; 1685 } 1686 free(oh); 1687 1688 return (errno); 1689 } 1690 1691 /* 1692 * Shows all entries from @oh in human-readable format 1693 */ 1694 static void 1695 table_show_list(ipfw_obj_header *oh, int need_header) 1696 { 1697 ipfw_obj_tentry *tent; 1698 uint32_t count; 1699 ipfw_xtable_info *i; 1700 1701 i = (ipfw_xtable_info *)(oh + 1); 1702 tent = (ipfw_obj_tentry *)(i + 1); 1703 1704 if (need_header) 1705 printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1706 1707 count = i->count; 1708 while (count > 0) { 1709 table_show_entry(i, tent); 1710 tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 1711 count--; 1712 } 1713 } 1714 1715 static void 1716 table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 1717 uint32_t vmask, int print_ip) 1718 { 1719 char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2]; 1720 struct sockaddr_in6 sa6; 1721 uint32_t flag, i, l; 1722 size_t sz; 1723 struct in_addr a4; 1724 1725 sz = bufsize; 1726 1727 /* 1728 * Some shorthands for printing values: 1729 * legacy assumes all values are equal, so keep the first one. 1730 */ 1731 if (vmask == IPFW_VTYPE_LEGACY) { 1732 if (print_ip != 0) { 1733 flag = htonl(v->tag); 1734 inet_ntop(AF_INET, &flag, buf, sz); 1735 } else 1736 snprintf(buf, sz, "%u", v->tag); 1737 return; 1738 } 1739 1740 for (i = 1; i < (1 << 31); i *= 2) { 1741 if ((flag = (vmask & i)) == 0) 1742 continue; 1743 l = 0; 1744 1745 switch (flag) { 1746 case IPFW_VTYPE_TAG: 1747 l = snprintf(buf, sz, "%u,", v->tag); 1748 break; 1749 case IPFW_VTYPE_PIPE: 1750 l = snprintf(buf, sz, "%u,", v->pipe); 1751 break; 1752 case IPFW_VTYPE_DIVERT: 1753 l = snprintf(buf, sz, "%d,", v->divert); 1754 break; 1755 case IPFW_VTYPE_SKIPTO: 1756 l = snprintf(buf, sz, "%d,", v->skipto); 1757 break; 1758 case IPFW_VTYPE_NETGRAPH: 1759 l = snprintf(buf, sz, "%u,", v->netgraph); 1760 break; 1761 case IPFW_VTYPE_FIB: 1762 l = snprintf(buf, sz, "%u,", v->fib); 1763 break; 1764 case IPFW_VTYPE_NAT: 1765 l = snprintf(buf, sz, "%u,", v->nat); 1766 break; 1767 case IPFW_VTYPE_LIMIT: 1768 l = snprintf(buf, sz, "%u,", v->limit); 1769 break; 1770 case IPFW_VTYPE_NH4: 1771 a4.s_addr = htonl(v->nh4); 1772 inet_ntop(AF_INET, &a4, abuf, sizeof(abuf)); 1773 l = snprintf(buf, sz, "%s,", abuf); 1774 break; 1775 case IPFW_VTYPE_DSCP: 1776 l = snprintf(buf, sz, "%d,", v->dscp); 1777 break; 1778 case IPFW_VTYPE_NH6: 1779 sa6.sin6_family = AF_INET6_LINUX; 1780 sa6.sin6_len = sizeof(sa6); 1781 sa6.sin6_addr = v->nh6; 1782 sa6.sin6_port = 0; 1783 sa6.sin6_scope_id = v->zoneid; 1784 if (getnameinfo((const struct sockaddr *)&sa6, 1785 sa6.sin6_len, abuf, sizeof(abuf), NULL, 0, 1786 NI_NUMERICHOST) == 0) 1787 l = snprintf(buf, sz, "%s,", abuf); 1788 break; 1789 } 1790 1791 buf += l; 1792 sz -= l; 1793 } 1794 1795 if (sz != bufsize) 1796 *(buf - 1) = '\0'; 1797 } 1798 1799 static void 1800 table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 1801 { 1802 char *comma, tbuf[128], pval[128]; 1803 void *paddr; 1804 struct tflow_entry *tfe; 1805 1806 table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask, 1807 co.do_value_as_ip); 1808 1809 switch (i->type) { 1810 case IPFW_TABLE_ADDR: 1811 /* IPv4 or IPv6 prefixes */ 1812 inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1813 printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1814 break; 1815 case IPFW_TABLE_INTERFACE: 1816 /* Interface names */ 1817 printf("%s %s\n", tent->k.iface, pval); 1818 break; 1819 case IPFW_TABLE_NUMBER: 1820 /* numbers */ 1821 printf("%u %s\n", tent->k.key, pval); 1822 break; 1823 case IPFW_TABLE_FLOW: 1824 /* flows */ 1825 tfe = &tent->k.flow; 1826 comma = ""; 1827 1828 if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1829 if (tfe->af == AF_INET) 1830 paddr = &tfe->a.a4.sip; 1831 else 1832 paddr = &tfe->a.a6.sip6; 1833 1834 inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1835 printf("%s%s", comma, tbuf); 1836 comma = ","; 1837 } 1838 1839 if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1840 printf("%s%d", comma, tfe->proto); 1841 comma = ","; 1842 } 1843 1844 if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1845 printf("%s%d", comma, ntohs(tfe->sport)); 1846 comma = ","; 1847 } 1848 if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1849 if (tfe->af == AF_INET) 1850 paddr = &tfe->a.a4.dip; 1851 else 1852 paddr = &tfe->a.a6.dip6; 1853 1854 inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1855 printf("%s%s", comma, tbuf); 1856 comma = ","; 1857 } 1858 1859 if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1860 printf("%s%d", comma, ntohs(tfe->dport)); 1861 comma = ","; 1862 } 1863 1864 printf(" %s\n", pval); 1865 } 1866 } 1867 1868 static int 1869 table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh) 1870 { 1871 ipfw_obj_lheader req, *olh; 1872 size_t sz; 1873 1874 memset(&req, 0, sizeof(req)); 1875 sz = sizeof(req); 1876 1877 if (do_get3(opcode, &req.opheader, &sz) != 0) 1878 if (errno != ENOMEM) 1879 return (errno); 1880 1881 sz = req.size; 1882 if ((olh = calloc(1, sz)) == NULL) 1883 return (ENOMEM); 1884 1885 olh->size = sz; 1886 if (do_get3(opcode, &olh->opheader, &sz) != 0) { 1887 free(olh); 1888 return (errno); 1889 } 1890 1891 *polh = olh; 1892 return (0); 1893 } 1894 1895 static int 1896 table_do_get_algolist(ipfw_obj_lheader **polh) 1897 { 1898 1899 return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh)); 1900 } 1901 1902 static int 1903 table_do_get_vlist(ipfw_obj_lheader **polh) 1904 { 1905 1906 return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh)); 1907 } 1908 1909 void 1910 ipfw_list_ta(int ac, char *av[]) 1911 { 1912 ipfw_obj_lheader *olh; 1913 ipfw_ta_info *info; 1914 int error, i; 1915 const char *atype; 1916 1917 error = table_do_get_algolist(&olh); 1918 if (error != 0) 1919 err(EX_OSERR, "Unable to request algorithm list"); 1920 1921 info = (ipfw_ta_info *)(olh + 1); 1922 for (i = 0; i < olh->count; i++) { 1923 if ((atype = match_value(tabletypes, info->type)) == NULL) 1924 atype = "unknown"; 1925 printf("--- %s ---\n", info->algoname); 1926 printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 1927 1928 info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 1929 } 1930 1931 free(olh); 1932 } 1933 1934 1935 /* Copy of current kernel table_value structure */ 1936 struct _table_value { 1937 uint32_t tag; /* O_TAG/O_TAGGED */ 1938 uint32_t pipe; /* O_PIPE/O_QUEUE */ 1939 uint16_t divert; /* O_DIVERT/O_TEE */ 1940 uint16_t skipto; /* skipto, CALLRET */ 1941 uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */ 1942 uint32_t fib; /* O_SETFIB */ 1943 uint32_t nat; /* O_NAT */ 1944 uint32_t nh4; 1945 uint8_t dscp; 1946 uint8_t spare0; 1947 uint16_t spare1; 1948 /* -- 32 bytes -- */ 1949 struct in6_addr nh6; 1950 uint32_t limit; /* O_LIMIT */ 1951 uint32_t zoneid; 1952 uint64_t refcnt; /* Number of references */ 1953 }; 1954 1955 int 1956 compare_values(const void *_a, const void *_b) 1957 { 1958 struct _table_value *a, *b; 1959 1960 a = (struct _table_value *)_a; 1961 b = (struct _table_value *)_b; 1962 1963 if (a->spare1 < b->spare1) 1964 return (-1); 1965 else if (a->spare1 > b->spare1) 1966 return (1); 1967 1968 return (0); 1969 } 1970 1971 void 1972 ipfw_list_values(int ac, char *av[]) 1973 { 1974 ipfw_obj_lheader *olh; 1975 struct _table_value *v; 1976 int error, i; 1977 uint32_t vmask; 1978 char buf[128]; 1979 1980 error = table_do_get_vlist(&olh); 1981 if (error != 0) 1982 err(EX_OSERR, "Unable to request value list"); 1983 1984 vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */ 1985 1986 table_print_valheader(buf, sizeof(buf), vmask); 1987 printf("HEADER: %s\n", buf); 1988 v = (struct _table_value *)(olh + 1); 1989 qsort(v, olh->count, olh->objsize, compare_values); 1990 for (i = 0; i < olh->count; i++) { 1991 table_show_value(buf, sizeof(buf), (ipfw_table_value *)v, 1992 vmask, 0); 1993 printf("[%u] refs=%lu %s\n", v->spare1, (u_long)v->refcnt, buf); 1994 v = (struct _table_value *)((caddr_t)v + olh->objsize); 1995 } 1996 1997 free(olh); 1998 } 1999 2000 int 2001 table_check_name(const char *tablename) 2002 { 2003 2004 if (ipfw_check_object_name(tablename) != 0) 2005 return (EINVAL); 2006 /* Restrict some 'special' names */ 2007 if (strcmp(tablename, "all") == 0) 2008 return (EINVAL); 2009 return (0); 2010 } 2011 2012