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