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