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 if (quiet == 0) 918 warnx("DEPRECATED: inserting data into " 919 "non-existent table %s. (auto-created)", 920 xi.tablename); 921 table_do_create(oh, &xi); 922 } 923 924 oh->ntlv.type = type; 925 ac--; av++; 926 927 if (add != 0 && ac > 0) { 928 tentry_fill_value(oh, ptent, *av, type, vmask); 929 ac--; av++; 930 } 931 932 if (update != 0) 933 ptent->head.flags |= IPFW_TF_UPDATE; 934 935 count++; 936 ptent++; 937 } 938 939 error = table_do_modify_record(cmd, oh, tent_buf, count, atomic); 940 941 /* 942 * Compatibility stuff: do not yell on duplicate keys or 943 * failed deletions. 944 */ 945 if (error == 0 || (error == EEXIST && add != 0) || 946 (error == ENOENT && add == 0)) { 947 if (quiet != 0) { 948 if (tent_buf != &tent) 949 free(tent_buf); 950 return; 951 } 952 } 953 954 /* Report results back */ 955 ptent = tent_buf; 956 for (i = 0; i < count; ptent++, i++) { 957 ignored = 0; 958 switch (ptent->result) { 959 case IPFW_TR_ADDED: 960 px = "added"; 961 break; 962 case IPFW_TR_DELETED: 963 px = "deleted"; 964 break; 965 case IPFW_TR_UPDATED: 966 px = "updated"; 967 break; 968 case IPFW_TR_LIMIT: 969 px = "limit"; 970 ignored = 1; 971 break; 972 case IPFW_TR_ERROR: 973 px = "error"; 974 ignored = 1; 975 break; 976 case IPFW_TR_NOTFOUND: 977 px = "notfound"; 978 ignored = 1; 979 break; 980 case IPFW_TR_EXISTS: 981 px = "exists"; 982 ignored = 1; 983 break; 984 case IPFW_TR_IGNORED: 985 px = "ignored"; 986 ignored = 1; 987 break; 988 default: 989 px = "unknown"; 990 ignored = 1; 991 } 992 993 if (error != 0 && atomic != 0 && ignored == 0) 994 printf("%s(reverted): ", px); 995 else 996 printf("%s: ", px); 997 998 table_show_entry(&xi, ptent); 999 } 1000 1001 if (tent_buf != &tent) 1002 free(tent_buf); 1003 1004 if (error == 0) 1005 return; 1006 /* Get real OS error */ 1007 error = errno; 1008 1009 /* Try to provide more human-readable error */ 1010 switch (error) { 1011 case EEXIST: 1012 etxt = "record already exists"; 1013 break; 1014 case EFBIG: 1015 etxt = "limit hit"; 1016 break; 1017 case ESRCH: 1018 etxt = "table not found"; 1019 break; 1020 case ENOENT: 1021 etxt = "record not found"; 1022 break; 1023 case EACCES: 1024 etxt = "table is locked"; 1025 break; 1026 default: 1027 etxt = strerror(error); 1028 } 1029 1030 errx(EX_OSERR, "%s: %s", texterr, etxt); 1031 } 1032 1033 static int 1034 table_do_lookup(ipfw_obj_header *oh, char *key, ipfw_xtable_info *xi, 1035 ipfw_obj_tentry *xtent) 1036 { 1037 char xbuf[sizeof(ipfw_obj_header) + sizeof(ipfw_obj_tentry)]; 1038 ipfw_obj_tentry *tent; 1039 uint8_t type; 1040 uint32_t vmask; 1041 size_t sz; 1042 1043 memcpy(xbuf, oh, sizeof(*oh)); 1044 oh = (ipfw_obj_header *)xbuf; 1045 tent = (ipfw_obj_tentry *)(oh + 1); 1046 1047 memset(tent, 0, sizeof(*tent)); 1048 tent->head.length = sizeof(*tent); 1049 tent->idx = 1; 1050 1051 tentry_fill_key(oh, tent, key, 0, &type, &vmask, xi); 1052 oh->ntlv.type = type; 1053 1054 sz = sizeof(xbuf); 1055 if (do_get3(IP_FW_TABLE_XFIND, &oh->opheader, &sz) != 0) 1056 return (errno); 1057 1058 if (sz < sizeof(xbuf)) 1059 return (EINVAL); 1060 1061 *xtent = *tent; 1062 1063 return (0); 1064 } 1065 1066 static void 1067 table_lookup(ipfw_obj_header *oh, int ac, char *av[]) 1068 { 1069 ipfw_obj_tentry xtent; 1070 ipfw_xtable_info xi; 1071 char key[64]; 1072 int error; 1073 1074 if (ac == 0) 1075 errx(EX_USAGE, "address required"); 1076 1077 strlcpy(key, *av, sizeof(key)); 1078 1079 memset(&xi, 0, sizeof(xi)); 1080 error = table_do_lookup(oh, key, &xi, &xtent); 1081 1082 switch (error) { 1083 case 0: 1084 break; 1085 case ESRCH: 1086 errx(EX_UNAVAILABLE, "Table %s not found", oh->ntlv.name); 1087 case ENOENT: 1088 errx(EX_UNAVAILABLE, "Entry %s not found", *av); 1089 case ENOTSUP: 1090 errx(EX_UNAVAILABLE, "Table %s algo does not support " 1091 "\"lookup\" method", oh->ntlv.name); 1092 default: 1093 err(EX_OSERR, "getsockopt(IP_FW_TABLE_XFIND)"); 1094 } 1095 1096 table_show_entry(&xi, &xtent); 1097 } 1098 1099 static void 1100 tentry_fill_key_type(char *arg, ipfw_obj_tentry *tentry, uint8_t type, 1101 uint8_t tflags) 1102 { 1103 char *p, *pp; 1104 int mask, af; 1105 struct in6_addr *paddr, tmp; 1106 struct tflow_entry *tfe; 1107 uint32_t key, *pkey; 1108 uint16_t port; 1109 struct protoent *pent; 1110 struct servent *sent; 1111 int masklen; 1112 1113 masklen = 0; 1114 af = 0; 1115 paddr = (struct in6_addr *)&tentry->k; 1116 1117 switch (type) { 1118 case IPFW_TABLE_ADDR: 1119 /* Remove / if exists */ 1120 if ((p = strchr(arg, '/')) != NULL) { 1121 *p = '\0'; 1122 mask = atoi(p + 1); 1123 } 1124 1125 if (inet_pton(AF_INET, arg, paddr) == 1) { 1126 if (p != NULL && mask > 32) 1127 errx(EX_DATAERR, "bad IPv4 mask width: %s", 1128 p + 1); 1129 1130 masklen = p ? mask : 32; 1131 af = AF_INET; 1132 } else if (inet_pton(AF_INET6, arg, paddr) == 1) { 1133 if (IN6_IS_ADDR_V4COMPAT(paddr)) 1134 errx(EX_DATAERR, 1135 "Use IPv4 instead of v4-compatible"); 1136 if (p != NULL && mask > 128) 1137 errx(EX_DATAERR, "bad IPv6 mask width: %s", 1138 p + 1); 1139 1140 masklen = p ? mask : 128; 1141 af = AF_INET6; 1142 } else { 1143 /* Assume FQDN */ 1144 if (lookup_host(arg, (struct in_addr *)paddr) != 0) 1145 errx(EX_NOHOST, "hostname ``%s'' unknown", arg); 1146 1147 masklen = 32; 1148 type = IPFW_TABLE_ADDR; 1149 af = AF_INET; 1150 } 1151 break; 1152 case IPFW_TABLE_INTERFACE: 1153 /* Assume interface name. Copy significant data only */ 1154 mask = MIN(strlen(arg), IF_NAMESIZE - 1); 1155 memcpy(paddr, arg, mask); 1156 /* Set mask to exact match */ 1157 masklen = 8 * IF_NAMESIZE; 1158 break; 1159 case IPFW_TABLE_NUMBER: 1160 /* Port or any other key */ 1161 key = strtol(arg, &p, 10); 1162 if (*p != '\0') 1163 errx(EX_DATAERR, "Invalid number: %s", arg); 1164 1165 pkey = (uint32_t *)paddr; 1166 *pkey = key; 1167 masklen = 32; 1168 break; 1169 case IPFW_TABLE_FLOW: 1170 /* Assume [src-ip][,proto][,src-port][,dst-ip][,dst-port] */ 1171 tfe = &tentry->k.flow; 1172 af = 0; 1173 1174 /* Handle <ipv4|ipv6> */ 1175 if ((tflags & IPFW_TFFLAG_SRCIP) != 0) { 1176 if ((p = strchr(arg, ',')) != NULL) 1177 *p++ = '\0'; 1178 /* Determine family using temporary storage */ 1179 if (inet_pton(AF_INET, arg, &tmp) == 1) { 1180 if (af != 0 && af != AF_INET) 1181 errx(EX_DATAERR, 1182 "Inconsistent address family\n"); 1183 af = AF_INET; 1184 memcpy(&tfe->a.a4.sip, &tmp, 4); 1185 } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1186 if (af != 0 && af != AF_INET6) 1187 errx(EX_DATAERR, 1188 "Inconsistent address family\n"); 1189 af = AF_INET6; 1190 memcpy(&tfe->a.a6.sip6, &tmp, 16); 1191 } 1192 1193 arg = p; 1194 } 1195 1196 /* Handle <proto-num|proto-name> */ 1197 if ((tflags & IPFW_TFFLAG_PROTO) != 0) { 1198 if (arg == NULL) 1199 errx(EX_DATAERR, "invalid key: proto missing"); 1200 if ((p = strchr(arg, ',')) != NULL) 1201 *p++ = '\0'; 1202 1203 key = strtol(arg, &pp, 10); 1204 if (*pp != '\0') { 1205 if ((pent = getprotobyname(arg)) == NULL) 1206 errx(EX_DATAERR, "Unknown proto: %s", 1207 arg); 1208 else 1209 key = pent->p_proto; 1210 } 1211 1212 if (key > 255) 1213 errx(EX_DATAERR, "Bad protocol number: %u",key); 1214 1215 tfe->proto = key; 1216 1217 arg = p; 1218 } 1219 1220 /* Handle <port-num|service-name> */ 1221 if ((tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1222 if (arg == NULL) 1223 errx(EX_DATAERR, "invalid key: src port missing"); 1224 if ((p = strchr(arg, ',')) != NULL) 1225 *p++ = '\0'; 1226 1227 if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1228 if ((sent = getservbyname(arg, NULL)) == NULL) 1229 errx(EX_DATAERR, "Unknown service: %s", 1230 arg); 1231 else 1232 key = sent->s_port; 1233 } 1234 1235 tfe->sport = port; 1236 1237 arg = p; 1238 } 1239 1240 /* Handle <ipv4|ipv6>*/ 1241 if ((tflags & IPFW_TFFLAG_DSTIP) != 0) { 1242 if (arg == NULL) 1243 errx(EX_DATAERR, "invalid key: dst ip missing"); 1244 if ((p = strchr(arg, ',')) != NULL) 1245 *p++ = '\0'; 1246 /* Determine family using temporary storage */ 1247 if (inet_pton(AF_INET, arg, &tmp) == 1) { 1248 if (af != 0 && af != AF_INET) 1249 errx(EX_DATAERR, 1250 "Inconsistent address family"); 1251 af = AF_INET; 1252 memcpy(&tfe->a.a4.dip, &tmp, 4); 1253 } else if (inet_pton(AF_INET6, arg, &tmp) == 1) { 1254 if (af != 0 && af != AF_INET6) 1255 errx(EX_DATAERR, 1256 "Inconsistent address family"); 1257 af = AF_INET6; 1258 memcpy(&tfe->a.a6.dip6, &tmp, 16); 1259 } 1260 1261 arg = p; 1262 } 1263 1264 /* Handle <port-num|service-name> */ 1265 if ((tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1266 if (arg == NULL) 1267 errx(EX_DATAERR, "invalid key: dst port missing"); 1268 if ((p = strchr(arg, ',')) != NULL) 1269 *p++ = '\0'; 1270 1271 if ((port = htons(strtol(arg, NULL, 10))) == 0) { 1272 if ((sent = getservbyname(arg, NULL)) == NULL) 1273 errx(EX_DATAERR, "Unknown service: %s", 1274 arg); 1275 else 1276 key = sent->s_port; 1277 } 1278 1279 tfe->dport = port; 1280 1281 arg = p; 1282 } 1283 1284 tfe->af = af; 1285 1286 break; 1287 1288 default: 1289 errx(EX_DATAERR, "Unsupported table type: %d", type); 1290 } 1291 1292 tentry->subtype = af; 1293 tentry->masklen = masklen; 1294 } 1295 1296 /* 1297 * Tries to guess table key type. 1298 * This procedure is used in legacy table auto-create 1299 * code AND in `ipfw -n` ruleset checking. 1300 * 1301 * Imported from old table_fill_xentry() parse code. 1302 */ 1303 static int 1304 guess_key_type(char *key, uint8_t *ptype) 1305 { 1306 char *p; 1307 struct in6_addr addr; 1308 uint32_t kv; 1309 1310 if (ishexnumber(*key) != 0 || *key == ':') { 1311 /* Remove / if exists */ 1312 if ((p = strchr(key, '/')) != NULL) 1313 *p = '\0'; 1314 1315 if ((inet_pton(AF_INET, key, &addr) == 1) || 1316 (inet_pton(AF_INET6, key, &addr) == 1)) { 1317 *ptype = IPFW_TABLE_CIDR; 1318 if (p != NULL) 1319 *p = '/'; 1320 return (0); 1321 } else { 1322 /* Port or any other key */ 1323 /* Skip non-base 10 entries like 'fa1' */ 1324 kv = strtol(key, &p, 10); 1325 if (*p == '\0') { 1326 *ptype = IPFW_TABLE_NUMBER; 1327 return (0); 1328 } else if ((p != key) && (*p == '.')) { 1329 /* 1330 * Warn on IPv4 address strings 1331 * which are "valid" for inet_aton() but not 1332 * in inet_pton(). 1333 * 1334 * Typical examples: '10.5' or '10.0.0.05' 1335 */ 1336 return (1); 1337 } 1338 } 1339 } 1340 1341 if (strchr(key, '.') == NULL) { 1342 *ptype = IPFW_TABLE_INTERFACE; 1343 return (0); 1344 } 1345 1346 if (lookup_host(key, (struct in_addr *)&addr) != 0) 1347 return (1); 1348 1349 *ptype = IPFW_TABLE_CIDR; 1350 return (0); 1351 } 1352 1353 static void 1354 tentry_fill_key(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *key, 1355 int add, uint8_t *ptype, uint32_t *pvmask, ipfw_xtable_info *xi) 1356 { 1357 uint8_t type, tflags; 1358 uint32_t vmask; 1359 int error; 1360 1361 type = 0; 1362 tflags = 0; 1363 vmask = 0; 1364 1365 if (xi->tablename[0] == '\0') 1366 error = table_get_info(oh, xi); 1367 else 1368 error = 0; 1369 1370 if (error == 0) { 1371 if (co.test_only == 0) { 1372 /* Table found */ 1373 type = xi->type; 1374 tflags = xi->tflags; 1375 vmask = xi->vmask; 1376 } else { 1377 /* 1378 * We're running `ipfw -n` 1379 * Compatibility layer: try to guess key type 1380 * before failing. 1381 */ 1382 if (guess_key_type(key, &type) != 0) { 1383 /* Inknown key */ 1384 errx(EX_USAGE, "Cannot guess " 1385 "key '%s' type", key); 1386 } 1387 vmask = IPFW_VTYPE_LEGACY; 1388 } 1389 } else { 1390 if (error != ESRCH) 1391 errx(EX_OSERR, "Error requesting table %s info", 1392 oh->ntlv.name); 1393 if (add == 0) 1394 errx(EX_DATAERR, "Table %s does not exist", 1395 oh->ntlv.name); 1396 /* 1397 * Table does not exist 1398 * Compatibility layer: try to guess key type before failing. 1399 */ 1400 if (guess_key_type(key, &type) != 0) { 1401 /* Inknown key */ 1402 errx(EX_USAGE, "Table %s does not exist, cannot guess " 1403 "key '%s' type", oh->ntlv.name, key); 1404 } 1405 1406 vmask = IPFW_VTYPE_LEGACY; 1407 } 1408 1409 tentry_fill_key_type(key, tent, type, tflags); 1410 1411 *ptype = type; 1412 *pvmask = vmask; 1413 } 1414 1415 static void 1416 set_legacy_value(uint32_t val, ipfw_table_value *v) 1417 { 1418 v->tag = val; 1419 v->pipe = val; 1420 v->divert = val; 1421 v->skipto = val; 1422 v->netgraph = val; 1423 v->fib = val; 1424 v->nat = val; 1425 v->nh4 = val; 1426 v->dscp = (uint8_t)val; 1427 v->limit = val; 1428 } 1429 1430 static void 1431 tentry_fill_value(ipfw_obj_header *oh, ipfw_obj_tentry *tent, char *arg, 1432 uint8_t type, uint32_t vmask) 1433 { 1434 struct addrinfo hints, *res; 1435 uint32_t a4, flag, val; 1436 ipfw_table_value *v; 1437 uint32_t i; 1438 int dval; 1439 char *comma, *e, *etype, *n, *p; 1440 1441 v = &tent->v.value; 1442 1443 /* Compat layer: keep old behavior for legacy value types */ 1444 if (vmask == IPFW_VTYPE_LEGACY) { 1445 /* Try to interpret as number first */ 1446 val = strtoul(arg, &p, 0); 1447 if (*p == '\0') { 1448 set_legacy_value(val, v); 1449 return; 1450 } 1451 if (inet_pton(AF_INET, arg, &val) == 1) { 1452 set_legacy_value(ntohl(val), v); 1453 return; 1454 } 1455 /* Try hostname */ 1456 if (lookup_host(arg, (struct in_addr *)&val) == 0) { 1457 set_legacy_value(val, v); 1458 return; 1459 } 1460 errx(EX_OSERR, "Unable to parse value %s", arg); 1461 } 1462 1463 /* 1464 * Shorthands: handle single value if vmask consists 1465 * of numbers only. e.g.: 1466 * vmask = "fib,skipto" -> treat input "1" as "1,1" 1467 */ 1468 1469 n = arg; 1470 etype = NULL; 1471 for (i = 1; i < (1 << 31); i *= 2) { 1472 if ((flag = (vmask & i)) == 0) 1473 continue; 1474 vmask &= ~flag; 1475 1476 if ((comma = strchr(n, ',')) != NULL) 1477 *comma = '\0'; 1478 1479 switch (flag) { 1480 case IPFW_VTYPE_TAG: 1481 v->tag = strtol(n, &e, 10); 1482 if (*e != '\0') 1483 etype = "tag"; 1484 break; 1485 case IPFW_VTYPE_PIPE: 1486 v->pipe = strtol(n, &e, 10); 1487 if (*e != '\0') 1488 etype = "pipe"; 1489 break; 1490 case IPFW_VTYPE_DIVERT: 1491 v->divert = strtol(n, &e, 10); 1492 if (*e != '\0') 1493 etype = "divert"; 1494 break; 1495 case IPFW_VTYPE_SKIPTO: 1496 v->skipto = strtol(n, &e, 10); 1497 if (*e != '\0') 1498 etype = "skipto"; 1499 break; 1500 case IPFW_VTYPE_NETGRAPH: 1501 v->netgraph = strtol(n, &e, 10); 1502 if (*e != '\0') 1503 etype = "netgraph"; 1504 break; 1505 case IPFW_VTYPE_FIB: 1506 v->fib = strtol(n, &e, 10); 1507 if (*e != '\0') 1508 etype = "fib"; 1509 break; 1510 case IPFW_VTYPE_NAT: 1511 v->nat = strtol(n, &e, 10); 1512 if (*e != '\0') 1513 etype = "nat"; 1514 break; 1515 case IPFW_VTYPE_LIMIT: 1516 v->limit = strtol(n, &e, 10); 1517 if (*e != '\0') 1518 etype = "limit"; 1519 break; 1520 case IPFW_VTYPE_NH4: 1521 if (strchr(n, '.') != NULL && 1522 inet_pton(AF_INET, n, &a4) == 1) { 1523 v->nh4 = ntohl(a4); 1524 break; 1525 } 1526 if (lookup_host(n, (struct in_addr *)&v->nh4) == 0) 1527 break; 1528 etype = "ipv4"; 1529 break; 1530 case IPFW_VTYPE_DSCP: 1531 if (isalpha(*n)) { 1532 if ((dval = match_token(f_ipdscp, n)) != -1) { 1533 v->dscp = dval; 1534 break; 1535 } else 1536 etype = "DSCP code"; 1537 } else { 1538 v->dscp = strtol(n, &e, 10); 1539 if (v->dscp > 63 || *e != '\0') 1540 etype = "DSCP value"; 1541 } 1542 break; 1543 case IPFW_VTYPE_NH6: 1544 if (strchr(n, ':') != NULL) { 1545 memset(&hints, 0, sizeof(hints)); 1546 hints.ai_family = AF_INET6; 1547 hints.ai_flags = AI_NUMERICHOST; 1548 if (getaddrinfo(n, NULL, &hints, &res) == 0) { 1549 v->nh6 = ((struct sockaddr_in6 *) 1550 res->ai_addr)->sin6_addr; 1551 v->zoneid = ((struct sockaddr_in6 *) 1552 res->ai_addr)->sin6_scope_id; 1553 freeaddrinfo(res); 1554 break; 1555 } 1556 } 1557 etype = "ipv6"; 1558 break; 1559 } 1560 1561 if (etype != NULL) 1562 errx(EX_USAGE, "Unable to parse %s as %s", n, etype); 1563 1564 if (comma != NULL) 1565 *comma++ = ','; 1566 1567 if ((n = comma) != NULL) 1568 continue; 1569 1570 /* End of input. */ 1571 if (vmask != 0) 1572 errx(EX_USAGE, "Not enough fields inside value"); 1573 } 1574 } 1575 1576 /* 1577 * Compare table names. 1578 * Honor number comparison. 1579 */ 1580 static int 1581 tablename_cmp(const void *a, const void *b) 1582 { 1583 ipfw_xtable_info *ia, *ib; 1584 1585 ia = (ipfw_xtable_info *)a; 1586 ib = (ipfw_xtable_info *)b; 1587 1588 return (stringnum_cmp(ia->tablename, ib->tablename)); 1589 } 1590 1591 /* 1592 * Retrieves table list from kernel, 1593 * optionally sorts it and calls requested function for each table. 1594 * Returns 0 on success. 1595 */ 1596 static int 1597 tables_foreach(table_cb_t *f, void *arg, int sort) 1598 { 1599 ipfw_obj_lheader *olh; 1600 ipfw_xtable_info *info; 1601 size_t sz; 1602 int i, error; 1603 1604 /* Start with reasonable default */ 1605 sz = sizeof(*olh) + 16 * sizeof(ipfw_xtable_info); 1606 1607 for (;;) { 1608 if ((olh = calloc(1, sz)) == NULL) 1609 return (ENOMEM); 1610 1611 olh->size = sz; 1612 if (do_get3(IP_FW_TABLES_XLIST, &olh->opheader, &sz) != 0) { 1613 sz = olh->size; 1614 free(olh); 1615 if (errno != ENOMEM) 1616 return (errno); 1617 continue; 1618 } 1619 1620 if (sort != 0) 1621 qsort(olh + 1, olh->count, olh->objsize, tablename_cmp); 1622 1623 info = (ipfw_xtable_info *)(olh + 1); 1624 for (i = 0; i < olh->count; i++) { 1625 error = f(info, arg); /* Ignore errors for now */ 1626 info = (ipfw_xtable_info *)((caddr_t)info + olh->objsize); 1627 } 1628 1629 free(olh); 1630 break; 1631 } 1632 1633 return (0); 1634 } 1635 1636 1637 /* 1638 * Retrieves all entries for given table @i in 1639 * eXtended format. Allocate buffer large enough 1640 * to store result. Called needs to free it later. 1641 * 1642 * Returns 0 on success. 1643 */ 1644 static int 1645 table_do_get_list(ipfw_xtable_info *i, ipfw_obj_header **poh) 1646 { 1647 ipfw_obj_header *oh; 1648 size_t sz; 1649 int c; 1650 1651 sz = 0; 1652 oh = NULL; 1653 for (c = 0; c < 8; c++) { 1654 if (sz < i->size) 1655 sz = i->size + 44; 1656 if (oh != NULL) 1657 free(oh); 1658 if ((oh = calloc(1, sz)) == NULL) 1659 continue; 1660 table_fill_objheader(oh, i); 1661 oh->opheader.version = 1; /* Current version */ 1662 if (do_get3(IP_FW_TABLE_XLIST, &oh->opheader, &sz) == 0) { 1663 *poh = oh; 1664 return (0); 1665 } 1666 1667 if (errno != ENOMEM) 1668 break; 1669 } 1670 free(oh); 1671 1672 return (errno); 1673 } 1674 1675 /* 1676 * Shows all entries from @oh in human-readable format 1677 */ 1678 static void 1679 table_show_list(ipfw_obj_header *oh, int need_header) 1680 { 1681 ipfw_obj_tentry *tent; 1682 uint32_t count; 1683 ipfw_xtable_info *i; 1684 1685 i = (ipfw_xtable_info *)(oh + 1); 1686 tent = (ipfw_obj_tentry *)(i + 1); 1687 1688 if (need_header) 1689 printf("--- table(%s), set(%u) ---\n", i->tablename, i->set); 1690 1691 count = i->count; 1692 while (count > 0) { 1693 table_show_entry(i, tent); 1694 tent = (ipfw_obj_tentry *)((caddr_t)tent + tent->head.length); 1695 count--; 1696 } 1697 } 1698 1699 static void 1700 table_show_value(char *buf, size_t bufsize, ipfw_table_value *v, 1701 uint32_t vmask, int print_ip) 1702 { 1703 char abuf[INET6_ADDRSTRLEN + IF_NAMESIZE + 2]; 1704 struct sockaddr_in6 sa6; 1705 uint32_t flag, i, l; 1706 size_t sz; 1707 struct in_addr a4; 1708 1709 sz = bufsize; 1710 1711 /* 1712 * Some shorthands for printing values: 1713 * legacy assumes all values are equal, so keep the first one. 1714 */ 1715 if (vmask == IPFW_VTYPE_LEGACY) { 1716 if (print_ip != 0) { 1717 flag = htonl(v->tag); 1718 inet_ntop(AF_INET, &flag, buf, sz); 1719 } else 1720 snprintf(buf, sz, "%u", v->tag); 1721 return; 1722 } 1723 1724 for (i = 1; i < (1 << 31); i *= 2) { 1725 if ((flag = (vmask & i)) == 0) 1726 continue; 1727 l = 0; 1728 1729 switch (flag) { 1730 case IPFW_VTYPE_TAG: 1731 l = snprintf(buf, sz, "%u,", v->tag); 1732 break; 1733 case IPFW_VTYPE_PIPE: 1734 l = snprintf(buf, sz, "%u,", v->pipe); 1735 break; 1736 case IPFW_VTYPE_DIVERT: 1737 l = snprintf(buf, sz, "%d,", v->divert); 1738 break; 1739 case IPFW_VTYPE_SKIPTO: 1740 l = snprintf(buf, sz, "%d,", v->skipto); 1741 break; 1742 case IPFW_VTYPE_NETGRAPH: 1743 l = snprintf(buf, sz, "%u,", v->netgraph); 1744 break; 1745 case IPFW_VTYPE_FIB: 1746 l = snprintf(buf, sz, "%u,", v->fib); 1747 break; 1748 case IPFW_VTYPE_NAT: 1749 l = snprintf(buf, sz, "%u,", v->nat); 1750 break; 1751 case IPFW_VTYPE_LIMIT: 1752 l = snprintf(buf, sz, "%u,", v->limit); 1753 break; 1754 case IPFW_VTYPE_NH4: 1755 a4.s_addr = htonl(v->nh4); 1756 inet_ntop(AF_INET, &a4, abuf, sizeof(abuf)); 1757 l = snprintf(buf, sz, "%s,", abuf); 1758 break; 1759 case IPFW_VTYPE_DSCP: 1760 l = snprintf(buf, sz, "%d,", v->dscp); 1761 break; 1762 case IPFW_VTYPE_NH6: 1763 sa6.sin6_family = AF_INET6; 1764 sa6.sin6_len = sizeof(sa6); 1765 sa6.sin6_addr = v->nh6; 1766 sa6.sin6_port = 0; 1767 sa6.sin6_scope_id = v->zoneid; 1768 if (getnameinfo((const struct sockaddr *)&sa6, 1769 sa6.sin6_len, abuf, sizeof(abuf), NULL, 0, 1770 NI_NUMERICHOST) == 0) 1771 l = snprintf(buf, sz, "%s,", abuf); 1772 break; 1773 } 1774 1775 buf += l; 1776 sz -= l; 1777 } 1778 1779 if (sz != bufsize) 1780 *(buf - 1) = '\0'; 1781 } 1782 1783 static void 1784 table_show_entry(ipfw_xtable_info *i, ipfw_obj_tentry *tent) 1785 { 1786 char *comma, tbuf[128], pval[128]; 1787 void *paddr; 1788 struct tflow_entry *tfe; 1789 1790 table_show_value(pval, sizeof(pval), &tent->v.value, i->vmask, 1791 co.do_value_as_ip); 1792 1793 switch (i->type) { 1794 case IPFW_TABLE_ADDR: 1795 /* IPv4 or IPv6 prefixes */ 1796 inet_ntop(tent->subtype, &tent->k, tbuf, sizeof(tbuf)); 1797 printf("%s/%u %s\n", tbuf, tent->masklen, pval); 1798 break; 1799 case IPFW_TABLE_INTERFACE: 1800 /* Interface names */ 1801 printf("%s %s\n", tent->k.iface, pval); 1802 break; 1803 case IPFW_TABLE_NUMBER: 1804 /* numbers */ 1805 printf("%u %s\n", tent->k.key, pval); 1806 break; 1807 case IPFW_TABLE_FLOW: 1808 /* flows */ 1809 tfe = &tent->k.flow; 1810 comma = ""; 1811 1812 if ((i->tflags & IPFW_TFFLAG_SRCIP) != 0) { 1813 if (tfe->af == AF_INET) 1814 paddr = &tfe->a.a4.sip; 1815 else 1816 paddr = &tfe->a.a6.sip6; 1817 1818 inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1819 printf("%s%s", comma, tbuf); 1820 comma = ","; 1821 } 1822 1823 if ((i->tflags & IPFW_TFFLAG_PROTO) != 0) { 1824 printf("%s%d", comma, tfe->proto); 1825 comma = ","; 1826 } 1827 1828 if ((i->tflags & IPFW_TFFLAG_SRCPORT) != 0) { 1829 printf("%s%d", comma, ntohs(tfe->sport)); 1830 comma = ","; 1831 } 1832 if ((i->tflags & IPFW_TFFLAG_DSTIP) != 0) { 1833 if (tfe->af == AF_INET) 1834 paddr = &tfe->a.a4.dip; 1835 else 1836 paddr = &tfe->a.a6.dip6; 1837 1838 inet_ntop(tfe->af, paddr, tbuf, sizeof(tbuf)); 1839 printf("%s%s", comma, tbuf); 1840 comma = ","; 1841 } 1842 1843 if ((i->tflags & IPFW_TFFLAG_DSTPORT) != 0) { 1844 printf("%s%d", comma, ntohs(tfe->dport)); 1845 comma = ","; 1846 } 1847 1848 printf(" %s\n", pval); 1849 } 1850 } 1851 1852 static int 1853 table_do_get_stdlist(uint16_t opcode, ipfw_obj_lheader **polh) 1854 { 1855 ipfw_obj_lheader req, *olh; 1856 size_t sz; 1857 1858 memset(&req, 0, sizeof(req)); 1859 sz = sizeof(req); 1860 1861 if (do_get3(opcode, &req.opheader, &sz) != 0) 1862 if (errno != ENOMEM) 1863 return (errno); 1864 1865 sz = req.size; 1866 if ((olh = calloc(1, sz)) == NULL) 1867 return (ENOMEM); 1868 1869 olh->size = sz; 1870 if (do_get3(opcode, &olh->opheader, &sz) != 0) { 1871 free(olh); 1872 return (errno); 1873 } 1874 1875 *polh = olh; 1876 return (0); 1877 } 1878 1879 static int 1880 table_do_get_algolist(ipfw_obj_lheader **polh) 1881 { 1882 1883 return (table_do_get_stdlist(IP_FW_TABLES_ALIST, polh)); 1884 } 1885 1886 static int 1887 table_do_get_vlist(ipfw_obj_lheader **polh) 1888 { 1889 1890 return (table_do_get_stdlist(IP_FW_TABLE_VLIST, polh)); 1891 } 1892 1893 void 1894 ipfw_list_ta(int ac, char *av[]) 1895 { 1896 ipfw_obj_lheader *olh; 1897 ipfw_ta_info *info; 1898 int error, i; 1899 const char *atype; 1900 1901 error = table_do_get_algolist(&olh); 1902 if (error != 0) 1903 err(EX_OSERR, "Unable to request algorithm list"); 1904 1905 info = (ipfw_ta_info *)(olh + 1); 1906 for (i = 0; i < olh->count; i++) { 1907 if ((atype = match_value(tabletypes, info->type)) == NULL) 1908 atype = "unknown"; 1909 printf("--- %s ---\n", info->algoname); 1910 printf(" type: %s\n refcount: %u\n", atype, info->refcnt); 1911 1912 info = (ipfw_ta_info *)((caddr_t)info + olh->objsize); 1913 } 1914 1915 free(olh); 1916 } 1917 1918 1919 /* Copy of current kernel table_value structure */ 1920 struct _table_value { 1921 uint32_t tag; /* O_TAG/O_TAGGED */ 1922 uint32_t pipe; /* O_PIPE/O_QUEUE */ 1923 uint16_t divert; /* O_DIVERT/O_TEE */ 1924 uint16_t skipto; /* skipto, CALLRET */ 1925 uint32_t netgraph; /* O_NETGRAPH/O_NGTEE */ 1926 uint32_t fib; /* O_SETFIB */ 1927 uint32_t nat; /* O_NAT */ 1928 uint32_t nh4; 1929 uint8_t dscp; 1930 uint8_t spare0; 1931 uint16_t spare1; 1932 /* -- 32 bytes -- */ 1933 struct in6_addr nh6; 1934 uint32_t limit; /* O_LIMIT */ 1935 uint32_t zoneid; 1936 uint64_t refcnt; /* Number of references */ 1937 }; 1938 1939 int 1940 compare_values(const void *_a, const void *_b) 1941 { 1942 struct _table_value *a, *b; 1943 1944 a = (struct _table_value *)_a; 1945 b = (struct _table_value *)_b; 1946 1947 if (a->spare1 < b->spare1) 1948 return (-1); 1949 else if (a->spare1 > b->spare1) 1950 return (1); 1951 1952 return (0); 1953 } 1954 1955 void 1956 ipfw_list_values(int ac, char *av[]) 1957 { 1958 ipfw_obj_lheader *olh; 1959 struct _table_value *v; 1960 int error, i; 1961 uint32_t vmask; 1962 char buf[128]; 1963 1964 error = table_do_get_vlist(&olh); 1965 if (error != 0) 1966 err(EX_OSERR, "Unable to request value list"); 1967 1968 vmask = 0x7FFFFFFF; /* Similar to IPFW_VTYPE_LEGACY */ 1969 1970 table_print_valheader(buf, sizeof(buf), vmask); 1971 printf("HEADER: %s\n", buf); 1972 v = (struct _table_value *)(olh + 1); 1973 qsort(v, olh->count, olh->objsize, compare_values); 1974 for (i = 0; i < olh->count; i++) { 1975 table_show_value(buf, sizeof(buf), (ipfw_table_value *)v, 1976 vmask, 0); 1977 printf("[%u] refs=%lu %s\n", v->spare1, (u_long)v->refcnt, buf); 1978 v = (struct _table_value *)((caddr_t)v + olh->objsize); 1979 } 1980 1981 free(olh); 1982 } 1983 1984 int 1985 table_check_name(const char *tablename) 1986 { 1987 1988 if (ipfw_check_object_name(tablename) != 0) 1989 return (EINVAL); 1990 /* Restrict some 'special' names */ 1991 if (strcmp(tablename, "all") == 0) 1992 return (EINVAL); 1993 return (0); 1994 } 1995 1996