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