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