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