1 /* $OpenBSD: pfctl_table.c,v 1.67 2008/06/10 20:55:02 mcbride Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 2002 Cedric Berger 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 13 * - Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * - Redistributions in binary form must reproduce the above 16 * copyright notice, this list of conditions and the following 17 * disclaimer in the documentation and/or other materials provided 18 * with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 24 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 28 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 30 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 * 33 */ 34 35 #include <sys/types.h> 36 #include <sys/ioctl.h> 37 #include <sys/socket.h> 38 39 #include <netinet/in.h> 40 #include <arpa/inet.h> 41 #include <net/if.h> 42 #include <net/pfvar.h> 43 44 #include <ctype.h> 45 #include <err.h> 46 #include <errno.h> 47 #include <netdb.h> 48 #include <stdarg.h> 49 #include <stdio.h> 50 #include <stdlib.h> 51 #include <string.h> 52 #include <time.h> 53 54 #include "pfctl_parser.h" 55 #include "pfctl.h" 56 57 extern void usage(void); 58 static int pfctl_table(int, char *[], char *, const char *, char *, 59 const char *, int); 60 static void print_table(const struct pfr_table *, int, int); 61 static int print_tstats(const struct pfr_tstats *, int); 62 static int load_addr(struct pfr_buffer *, int, char *[], char *, int); 63 static void print_addrx(struct pfr_addr *, struct pfr_addr *, int); 64 static int nonzero_astats(struct pfr_astats *); 65 static void print_astats(struct pfr_astats *, int); 66 static void radix_perror(void); 67 static void xprintf(int, const char *, ...); 68 static void print_iface(struct pfi_kif *, int); 69 70 static const char *stats_text[PFR_DIR_MAX][PFR_OP_TABLE_MAX] = { 71 { "In/Block:", "In/Pass:", "In/XPass:" }, 72 { "Out/Block:", "Out/Pass:", "Out/XPass:" } 73 }; 74 75 static const char *istats_text[2][2][2] = { 76 { { "In4/Pass:", "In4/Block:" }, { "Out4/Pass:", "Out4/Block:" } }, 77 { { "In6/Pass:", "In6/Block:" }, { "Out6/Pass:", "Out6/Block:" } } 78 }; 79 80 #define RVTEST(fct) do { \ 81 if ((!(opts & PF_OPT_NOACTION) || \ 82 (opts & PF_OPT_DUMMYACTION)) && \ 83 (fct)) { \ 84 radix_perror(); \ 85 goto _error; \ 86 } \ 87 } while (0) 88 89 #define CREATE_TABLE do { \ 90 table.pfrt_flags |= PFR_TFLAG_PERSIST; \ 91 if ((!(opts & PF_OPT_NOACTION) || \ 92 (opts & PF_OPT_DUMMYACTION)) && \ 93 (pfr_add_table(&table, &nadd, flags)) && \ 94 (errno != EPERM)) { \ 95 radix_perror(); \ 96 goto _error; \ 97 } \ 98 if (nadd) { \ 99 warn_namespace_collision(table.pfrt_name); \ 100 xprintf(opts, "%d table created", nadd); \ 101 if (opts & PF_OPT_NOACTION) \ 102 return (0); \ 103 } \ 104 table.pfrt_flags &= ~PFR_TFLAG_PERSIST; \ 105 } while(0) 106 107 int 108 pfctl_do_clear_tables(const char *anchor, int opts) 109 { 110 return pfctl_table(0, NULL, NULL, "-F", NULL, anchor, opts); 111 } 112 113 int 114 pfctl_show_tables(const char *anchor, int opts) 115 { 116 return pfctl_table(0, NULL, NULL, "-s", NULL, anchor, opts); 117 } 118 119 int 120 pfctl_command_tables(int argc, char *argv[], char *tname, 121 const char *command, char *file, const char *anchor, int opts) 122 { 123 if (tname == NULL || command == NULL) 124 usage(); 125 return pfctl_table(argc, argv, tname, command, file, anchor, opts); 126 } 127 128 int 129 pfctl_table(int argc, char *argv[], char *tname, const char *command, 130 char *file, const char *anchor, int opts) 131 { 132 struct pfr_table table; 133 struct pfr_buffer b, b2; 134 struct pfr_addr *a, *a2; 135 int nadd = 0, ndel = 0, nchange = 0, nzero = 0; 136 int rv = 0, flags = 0, nmatch = 0; 137 void *p; 138 139 if (command == NULL) 140 usage(); 141 if (opts & PF_OPT_NOACTION) 142 flags |= PFR_FLAG_DUMMY; 143 144 bzero(&b, sizeof(b)); 145 bzero(&b2, sizeof(b2)); 146 bzero(&table, sizeof(table)); 147 if (tname != NULL) { 148 if (strlen(tname) >= PF_TABLE_NAME_SIZE) 149 usage(); 150 if (strlcpy(table.pfrt_name, tname, 151 sizeof(table.pfrt_name)) >= sizeof(table.pfrt_name)) 152 errx(1, "pfctl_table: strlcpy"); 153 } 154 if (strlcpy(table.pfrt_anchor, anchor, 155 sizeof(table.pfrt_anchor)) >= sizeof(table.pfrt_anchor)) 156 errx(1, "pfctl_table: strlcpy"); 157 158 if (!strcmp(command, "-F")) { 159 if (argc || file != NULL) 160 usage(); 161 RVTEST(pfctl_clear_tables(pfh, &table, &ndel, flags)); 162 xprintf(opts, "%d tables deleted", ndel); 163 } else if (!strcmp(command, "-s")) { 164 b.pfrb_type = (opts & PF_OPT_VERBOSE2) ? 165 PFRB_TSTATS : PFRB_TABLES; 166 if (argc || file != NULL) 167 usage(); 168 169 if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0) 170 pfctl_print_title("TABLES:"); 171 172 if (opts & PF_OPT_VERBOSE2) { 173 uintptr_t arg = opts & PF_OPT_DEBUG; 174 pfctl_get_tstats(pfh, &table, 175 (pfctl_get_tstats_fn)print_tstats, (void *)arg); 176 } else { 177 for (;;) { 178 pfr_buf_grow(&b, b.pfrb_size); 179 b.pfrb_size = b.pfrb_msize; 180 RVTEST(pfr_get_tables(&table, 181 b.pfrb_caddr, &b.pfrb_size, flags)); 182 if (b.pfrb_size <= b.pfrb_msize) 183 break; 184 } 185 186 if ((opts & PF_OPT_SHOWALL) && b.pfrb_size > 0) 187 pfctl_print_title("TABLES:"); 188 189 PFRB_FOREACH(p, &b) 190 print_table(p, opts & PF_OPT_VERBOSE, 191 opts & PF_OPT_DEBUG); 192 } 193 } else if (!strcmp(command, "kill")) { 194 if (argc || file != NULL) 195 usage(); 196 RVTEST(pfr_del_table(&table, &ndel, flags)); 197 xprintf(opts, "%d table deleted", ndel); 198 } else if (!strcmp(command, "flush")) { 199 if (argc || file != NULL) 200 usage(); 201 RVTEST(pfr_clr_addrs(&table, &ndel, flags)); 202 xprintf(opts, "%d addresses deleted", ndel); 203 } else if (!strcmp(command, "add")) { 204 b.pfrb_type = PFRB_ADDRS; 205 if (load_addr(&b, argc, argv, file, 0)) 206 goto _error; 207 CREATE_TABLE; 208 if (opts & PF_OPT_VERBOSE) 209 flags |= PFR_FLAG_FEEDBACK; 210 RVTEST(pfr_add_addrs(&table, b.pfrb_caddr, b.pfrb_size, 211 &nadd, flags)); 212 xprintf(opts, "%d/%d addresses added", nadd, b.pfrb_size); 213 if (opts & PF_OPT_VERBOSE) 214 PFRB_FOREACH(a, &b) 215 if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) 216 print_addrx(a, NULL, 217 opts & PF_OPT_USEDNS); 218 } else if (!strcmp(command, "delete")) { 219 b.pfrb_type = PFRB_ADDRS; 220 if (load_addr(&b, argc, argv, file, 0)) 221 goto _error; 222 if (opts & PF_OPT_VERBOSE) 223 flags |= PFR_FLAG_FEEDBACK; 224 RVTEST(pfr_del_addrs(&table, b.pfrb_caddr, b.pfrb_size, 225 &ndel, flags)); 226 xprintf(opts, "%d/%d addresses deleted", ndel, b.pfrb_size); 227 if (opts & PF_OPT_VERBOSE) 228 PFRB_FOREACH(a, &b) 229 if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) 230 print_addrx(a, NULL, 231 opts & PF_OPT_USEDNS); 232 } else if (!strcmp(command, "replace")) { 233 b.pfrb_type = PFRB_ADDRS; 234 if (load_addr(&b, argc, argv, file, 0)) 235 goto _error; 236 CREATE_TABLE; 237 if (opts & PF_OPT_VERBOSE) 238 flags |= PFR_FLAG_FEEDBACK; 239 for (;;) { 240 int sz2 = b.pfrb_msize; 241 242 RVTEST(pfr_set_addrs(&table, b.pfrb_caddr, b.pfrb_size, 243 &sz2, &nadd, &ndel, &nchange, flags)); 244 if (sz2 <= b.pfrb_msize) { 245 b.pfrb_size = sz2; 246 break; 247 } else 248 pfr_buf_grow(&b, sz2); 249 } 250 if (nadd) 251 xprintf(opts, "%d addresses added", nadd); 252 if (ndel) 253 xprintf(opts, "%d addresses deleted", ndel); 254 if (nchange) 255 xprintf(opts, "%d addresses changed", nchange); 256 if (!nadd && !ndel && !nchange) 257 xprintf(opts, "no changes"); 258 if (opts & PF_OPT_VERBOSE) 259 PFRB_FOREACH(a, &b) 260 if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) 261 print_addrx(a, NULL, 262 opts & PF_OPT_USEDNS); 263 } else if (!strcmp(command, "expire")) { 264 const char *errstr; 265 u_int lifetime; 266 267 b.pfrb_type = PFRB_ASTATS; 268 b2.pfrb_type = PFRB_ADDRS; 269 if (argc != 1 || file != NULL) 270 usage(); 271 lifetime = strtonum(*argv, 0, UINT_MAX, &errstr); 272 if (errstr) 273 errx(1, "expiry time: %s", errstr); 274 for (;;) { 275 pfr_buf_grow(&b, b.pfrb_size); 276 b.pfrb_size = b.pfrb_msize; 277 RVTEST(pfr_get_astats(&table, b.pfrb_caddr, 278 &b.pfrb_size, flags)); 279 if (b.pfrb_size <= b.pfrb_msize) 280 break; 281 } 282 PFRB_FOREACH(p, &b) { 283 ((struct pfr_astats *)p)->pfras_a.pfra_fback = 0; 284 if (time(NULL) - ((struct pfr_astats *)p)->pfras_tzero > 285 lifetime) 286 if (pfr_buf_add(&b2, 287 &((struct pfr_astats *)p)->pfras_a)) 288 err(1, "duplicate buffer"); 289 } 290 291 if (opts & PF_OPT_VERBOSE) 292 flags |= PFR_FLAG_FEEDBACK; 293 RVTEST(pfr_del_addrs(&table, b2.pfrb_caddr, b2.pfrb_size, 294 &ndel, flags)); 295 xprintf(opts, "%d/%d addresses expired", ndel, b2.pfrb_size); 296 if (opts & PF_OPT_VERBOSE) 297 PFRB_FOREACH(a, &b2) 298 if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) 299 print_addrx(a, NULL, 300 opts & PF_OPT_USEDNS); 301 } else if (!strcmp(command, "reset")) { 302 struct pfr_astats *as; 303 304 b.pfrb_type = PFRB_ASTATS; 305 b2.pfrb_type = PFRB_ADDRS; 306 if (argc || file != NULL) 307 usage(); 308 do { 309 pfr_buf_grow(&b, b.pfrb_size); 310 b.pfrb_size = b.pfrb_msize; 311 RVTEST(pfr_get_astats(&table, b.pfrb_caddr, 312 &b.pfrb_size, flags)); 313 } while (b.pfrb_size > b.pfrb_msize); 314 PFRB_FOREACH(as, &b) { 315 as->pfras_a.pfra_fback = 0; 316 if (nonzero_astats(as)) 317 if (pfr_buf_add(&b2, &as->pfras_a)) 318 err(1, "duplicate buffer"); 319 } 320 321 if (opts & PF_OPT_VERBOSE) 322 flags |= PFR_FLAG_FEEDBACK; 323 RVTEST(pfr_clr_astats(&table, b2.pfrb_caddr, b2.pfrb_size, 324 &nzero, flags)); 325 xprintf(opts, "%d/%d stats cleared", nzero, b.pfrb_size); 326 if (opts & PF_OPT_VERBOSE) 327 PFRB_FOREACH(a, &b2) 328 if ((opts & PF_OPT_VERBOSE2) || a->pfra_fback) 329 print_addrx(a, NULL, 330 opts & PF_OPT_USEDNS); 331 } else if (!strcmp(command, "show")) { 332 b.pfrb_type = (opts & PF_OPT_VERBOSE) ? 333 PFRB_ASTATS : PFRB_ADDRS; 334 if (argc || file != NULL) 335 usage(); 336 for (;;) { 337 pfr_buf_grow(&b, b.pfrb_size); 338 b.pfrb_size = b.pfrb_msize; 339 if (opts & PF_OPT_VERBOSE) 340 RVTEST(pfr_get_astats(&table, b.pfrb_caddr, 341 &b.pfrb_size, flags)); 342 else 343 RVTEST(pfr_get_addrs(&table, b.pfrb_caddr, 344 &b.pfrb_size, flags)); 345 if (b.pfrb_size <= b.pfrb_msize) 346 break; 347 } 348 PFRB_FOREACH(p, &b) 349 if (opts & PF_OPT_VERBOSE) 350 print_astats(p, opts & PF_OPT_USEDNS); 351 else 352 print_addrx(p, NULL, opts & PF_OPT_USEDNS); 353 } else if (!strcmp(command, "test")) { 354 b.pfrb_type = PFRB_ADDRS; 355 b2.pfrb_type = PFRB_ADDRS; 356 357 if (load_addr(&b, argc, argv, file, 1)) 358 goto _error; 359 if (opts & PF_OPT_VERBOSE2) { 360 flags |= PFR_FLAG_REPLACE; 361 PFRB_FOREACH(a, &b) 362 if (pfr_buf_add(&b2, a)) 363 err(1, "duplicate buffer"); 364 } 365 RVTEST(pfr_tst_addrs(&table, b.pfrb_caddr, b.pfrb_size, 366 &nmatch, flags)); 367 xprintf(opts, "%d/%d addresses match", nmatch, b.pfrb_size); 368 if ((opts & PF_OPT_VERBOSE) && !(opts & PF_OPT_VERBOSE2)) 369 PFRB_FOREACH(a, &b) 370 if (a->pfra_fback == PFR_FB_MATCH) 371 print_addrx(a, NULL, 372 opts & PF_OPT_USEDNS); 373 if (opts & PF_OPT_VERBOSE2) { 374 a2 = NULL; 375 PFRB_FOREACH(a, &b) { 376 a2 = pfr_buf_next(&b2, a2); 377 print_addrx(a2, a, opts & PF_OPT_USEDNS); 378 } 379 } 380 if (nmatch < b.pfrb_size) 381 rv = 2; 382 } else if (!strcmp(command, "zero") && (argc || file != NULL)) { 383 b.pfrb_type = PFRB_ADDRS; 384 if (load_addr(&b, argc, argv, file, 0)) 385 goto _error; 386 if (opts & PF_OPT_VERBOSE) 387 flags |= PFR_FLAG_FEEDBACK; 388 RVTEST(pfr_clr_astats(&table, b.pfrb_caddr, b.pfrb_size, 389 &nzero, flags)); 390 xprintf(opts, "%d/%d addresses cleared", nzero, b.pfrb_size); 391 if (opts & PF_OPT_VERBOSE) 392 PFRB_FOREACH(a, &b) 393 if (opts & PF_OPT_VERBOSE2 || 394 a->pfra_fback != PFR_FB_NONE) 395 print_addrx(a, NULL, 396 opts & PF_OPT_USEDNS); 397 } else if (!strcmp(command, "zero")) { 398 flags |= PFR_FLAG_ADDRSTOO; 399 RVTEST(pfctl_clear_tstats(pfh, &table, &nzero, flags)); 400 xprintf(opts, "%d table/stats cleared", nzero); 401 } else 402 warnx("pfctl_table: unknown command '%s'", command); 403 goto _cleanup; 404 405 _error: 406 rv = -1; 407 _cleanup: 408 pfr_buf_clear(&b); 409 pfr_buf_clear(&b2); 410 return (rv); 411 } 412 413 void 414 print_table(const struct pfr_table *ta, int verbose, int debug) 415 { 416 if (!debug && !(ta->pfrt_flags & PFR_TFLAG_ACTIVE)) 417 return; 418 if (verbose) { 419 printf("%c%c%c%c%c%c%c\t%s", 420 (ta->pfrt_flags & PFR_TFLAG_CONST) ? 'c' : '-', 421 (ta->pfrt_flags & PFR_TFLAG_PERSIST) ? 'p' : '-', 422 (ta->pfrt_flags & PFR_TFLAG_ACTIVE) ? 'a' : '-', 423 (ta->pfrt_flags & PFR_TFLAG_INACTIVE) ? 'i' : '-', 424 (ta->pfrt_flags & PFR_TFLAG_REFERENCED) ? 'r' : '-', 425 (ta->pfrt_flags & PFR_TFLAG_REFDANCHOR) ? 'h' : '-', 426 (ta->pfrt_flags & PFR_TFLAG_COUNTERS) ? 'C' : '-', 427 ta->pfrt_name); 428 if (ta->pfrt_anchor[0]) 429 printf("\t%s", ta->pfrt_anchor); 430 puts(""); 431 } else 432 puts(ta->pfrt_name); 433 } 434 435 int 436 print_tstats(const struct pfr_tstats *ts, int debug) 437 { 438 time_t time = ts->pfrts_tzero; 439 int dir, op; 440 441 if (!debug && !(ts->pfrts_flags & PFR_TFLAG_ACTIVE)) 442 return (0); 443 print_table(&ts->pfrts_t, 1, debug); 444 printf("\tAddresses: %d\n", ts->pfrts_cnt); 445 printf("\tCleared: %s", ctime(&time)); 446 printf("\tReferences: [ Anchors: %-18d Rules: %-18d ]\n", 447 ts->pfrts_refcnt[PFR_REFCNT_ANCHOR], 448 ts->pfrts_refcnt[PFR_REFCNT_RULE]); 449 printf("\tEvaluations: [ NoMatch: %-18llu Match: %-18llu ]\n", 450 (unsigned long long)ts->pfrts_nomatch, 451 (unsigned long long)ts->pfrts_match); 452 for (dir = 0; dir < PFR_DIR_MAX; dir++) 453 for (op = 0; op < PFR_OP_TABLE_MAX; op++) 454 printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", 455 stats_text[dir][op], 456 (unsigned long long)ts->pfrts_packets[dir][op], 457 (unsigned long long)ts->pfrts_bytes[dir][op]); 458 459 return (0); 460 } 461 462 int 463 load_addr(struct pfr_buffer *b, int argc, char *argv[], char *file, 464 int nonetwork) 465 { 466 while (argc--) 467 if (append_addr(b, *argv++, nonetwork)) { 468 if (errno) 469 warn("cannot decode %s", argv[-1]); 470 return (-1); 471 } 472 if (pfr_buf_load(b, file, nonetwork, append_addr)) { 473 warn("cannot load %s", file); 474 return (-1); 475 } 476 return (0); 477 } 478 479 void 480 print_addrx(struct pfr_addr *ad, struct pfr_addr *rad, int dns) 481 { 482 char ch, buf[256] = "{error}"; 483 char fb[] = { ' ', 'M', 'A', 'D', 'C', 'Z', 'X', ' ', 'Y', ' ' }; 484 unsigned int fback, hostnet; 485 486 fback = (rad != NULL) ? rad->pfra_fback : ad->pfra_fback; 487 ch = (fback < sizeof(fb)/sizeof(*fb)) ? fb[fback] : '?'; 488 hostnet = (ad->pfra_af == AF_INET6) ? 128 : 32; 489 inet_ntop(ad->pfra_af, &ad->pfra_u, buf, sizeof(buf)); 490 printf("%c %c%s", ch, (ad->pfra_not?'!':' '), buf); 491 if (ad->pfra_net < hostnet) 492 printf("/%d", ad->pfra_net); 493 if (rad != NULL && fback != PFR_FB_NONE) { 494 if (strlcpy(buf, "{error}", sizeof(buf)) >= sizeof(buf)) 495 errx(1, "print_addrx: strlcpy"); 496 inet_ntop(rad->pfra_af, &rad->pfra_u, buf, sizeof(buf)); 497 printf("\t%c%s", (rad->pfra_not?'!':' '), buf); 498 if (rad->pfra_net < hostnet) 499 printf("/%d", rad->pfra_net); 500 } 501 if (rad != NULL && fback == PFR_FB_NONE) 502 printf("\t nomatch"); 503 if (dns && ad->pfra_net == hostnet) { 504 char host[NI_MAXHOST]; 505 struct sockaddr_storage ss; 506 507 strlcpy(host, "?", sizeof(host)); 508 bzero(&ss, sizeof(ss)); 509 ss.ss_family = ad->pfra_af; 510 if (ss.ss_family == AF_INET) { 511 struct sockaddr_in *sin = (struct sockaddr_in *)&ss; 512 513 sin->sin_len = sizeof(*sin); 514 sin->sin_addr = ad->pfra_ip4addr; 515 } else { 516 struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss; 517 518 sin6->sin6_len = sizeof(*sin6); 519 sin6->sin6_addr = ad->pfra_ip6addr; 520 } 521 if (getnameinfo((struct sockaddr *)&ss, ss.ss_len, host, 522 sizeof(host), NULL, 0, NI_NAMEREQD) == 0) 523 printf("\t(%s)", host); 524 } 525 printf("\n"); 526 } 527 528 int 529 nonzero_astats(struct pfr_astats *as) 530 { 531 uint64_t s = 0; 532 533 for (int dir = 0; dir < PFR_DIR_MAX; dir++) 534 for (int op = 0; op < PFR_OP_ADDR_MAX; op++) 535 s |= as->pfras_packets[dir][op] | 536 as->pfras_bytes[dir][op]; 537 538 return (!!s); 539 } 540 541 void 542 print_astats(struct pfr_astats *as, int dns) 543 { 544 time_t time = as->pfras_tzero; 545 int dir, op; 546 547 print_addrx(&as->pfras_a, NULL, dns); 548 printf("\tCleared: %s", ctime(&time)); 549 if (as->pfras_a.pfra_fback == PFR_FB_NOCOUNT) 550 return; 551 for (dir = 0; dir < PFR_DIR_MAX; dir++) 552 for (op = 0; op < PFR_OP_ADDR_MAX; op++) 553 printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", 554 stats_text[dir][op], 555 (unsigned long long)as->pfras_packets[dir][op], 556 (unsigned long long)as->pfras_bytes[dir][op]); 557 } 558 559 void 560 radix_perror(void) 561 { 562 extern char *__progname; 563 fprintf(stderr, "%s: %s.\n", __progname, pfr_strerror(errno)); 564 } 565 566 int 567 pfctl_define_table(char *name, int flags, int addrs, const char *anchor, 568 struct pfr_buffer *ab, u_int32_t ticket) 569 { 570 struct pfr_table tbl; 571 572 bzero(&tbl, sizeof(tbl)); 573 if (strlcpy(tbl.pfrt_name, name, sizeof(tbl.pfrt_name)) >= 574 sizeof(tbl.pfrt_name) || strlcpy(tbl.pfrt_anchor, anchor, 575 sizeof(tbl.pfrt_anchor)) >= sizeof(tbl.pfrt_anchor)) 576 errx(1, "pfctl_define_table: strlcpy"); 577 tbl.pfrt_flags = flags; 578 579 return pfr_ina_define(&tbl, ab->pfrb_caddr, ab->pfrb_size, NULL, 580 NULL, ticket, addrs ? PFR_FLAG_ADDRSTOO : 0); 581 } 582 583 void 584 warn_namespace_collision(const char *filter) 585 { 586 struct pfr_buffer b; 587 struct pfr_table *t; 588 const char *name = NULL, *lastcoll; 589 int coll = 0; 590 591 bzero(&b, sizeof(b)); 592 b.pfrb_type = PFRB_TABLES; 593 for (;;) { 594 pfr_buf_grow(&b, b.pfrb_size); 595 b.pfrb_size = b.pfrb_msize; 596 if (pfr_get_tables(NULL, b.pfrb_caddr, 597 &b.pfrb_size, PFR_FLAG_ALLRSETS)) 598 err(1, "pfr_get_tables"); 599 if (b.pfrb_size <= b.pfrb_msize) 600 break; 601 } 602 PFRB_FOREACH(t, &b) { 603 if (!(t->pfrt_flags & PFR_TFLAG_ACTIVE)) 604 continue; 605 if (filter != NULL && strcmp(filter, t->pfrt_name)) 606 continue; 607 if (!t->pfrt_anchor[0]) 608 name = t->pfrt_name; 609 else if (name != NULL && !strcmp(name, t->pfrt_name)) { 610 coll++; 611 lastcoll = name; 612 name = NULL; 613 } 614 } 615 if (coll == 1) 616 warnx("warning: namespace collision with <%s> global table.", 617 lastcoll); 618 else if (coll > 1) 619 warnx("warning: namespace collisions with %d global tables.", 620 coll); 621 pfr_buf_clear(&b); 622 } 623 624 void 625 xprintf(int opts, const char *fmt, ...) 626 { 627 va_list args; 628 629 if (opts & PF_OPT_QUIET) 630 return; 631 632 va_start(args, fmt); 633 vfprintf(stderr, fmt, args); 634 va_end(args); 635 636 if (opts & PF_OPT_DUMMYACTION) 637 fprintf(stderr, " (dummy).\n"); 638 else if (opts & PF_OPT_NOACTION) 639 fprintf(stderr, " (syntax only).\n"); 640 else 641 fprintf(stderr, ".\n"); 642 } 643 644 645 /* interface stuff */ 646 647 int 648 pfctl_show_ifaces(const char *filter, int opts) 649 { 650 struct pfr_buffer b; 651 struct pfi_kif *p; 652 653 bzero(&b, sizeof(b)); 654 b.pfrb_type = PFRB_IFACES; 655 for (;;) { 656 pfr_buf_grow(&b, b.pfrb_size); 657 b.pfrb_size = b.pfrb_msize; 658 if (pfi_get_ifaces(filter, b.pfrb_caddr, &b.pfrb_size)) { 659 radix_perror(); 660 return (1); 661 } 662 if (b.pfrb_size <= b.pfrb_msize) 663 break; 664 } 665 if (opts & PF_OPT_SHOWALL) 666 pfctl_print_title("INTERFACES:"); 667 PFRB_FOREACH(p, &b) 668 print_iface(p, opts); 669 return (0); 670 } 671 672 void 673 print_iface(struct pfi_kif *p, int opts) 674 { 675 time_t tzero = p->pfik_tzero; 676 int i, af, dir, act; 677 678 printf("%s", p->pfik_name); 679 if (opts & PF_OPT_VERBOSE) { 680 if (p->pfik_flags & PFI_IFLAG_SKIP) 681 printf(" (skip)"); 682 } 683 printf("\n"); 684 685 if (!(opts & PF_OPT_VERBOSE2)) 686 return; 687 printf("\tCleared: %s", ctime(&tzero)); 688 printf("\tReferences: %-18d\n", p->pfik_rulerefs); 689 for (i = 0; i < 8; i++) { 690 af = (i>>2) & 1; 691 dir = (i>>1) &1; 692 act = i & 1; 693 printf("\t%-12s [ Packets: %-18llu Bytes: %-18llu ]\n", 694 istats_text[af][dir][act], 695 (unsigned long long)p->pfik_packets[af][dir][act], 696 (unsigned long long)p->pfik_bytes[af][dir][act]); 697 } 698 } 699