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