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