| 1/* $FreeBSD: head/contrib/pf/pfctl/pfctl.c 126355 2004-02-28 17:32:53Z mlaier $ */
|
1/* $OpenBSD: pfctl.c,v 1.188 2003/08/29 21:47:36 cedric Exp $ */ 2 3/* 4 * Copyright (c) 2001 Daniel Hartmeier 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * - Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * - Redistributions in binary form must reproduce the above 14 * copyright notice, this list of conditions and the following 15 * disclaimer in the documentation and/or other materials provided 16 * with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 22 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 26 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 28 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 * 31 */ 32 33#include <sys/types.h> 34#include <sys/ioctl.h> 35#include <sys/socket.h> 36 37#include <net/if.h> 38#include <netinet/in.h>
| 2/* $OpenBSD: pfctl.c,v 1.188 2003/08/29 21:47:36 cedric Exp $ */ 3 4/* 5 * Copyright (c) 2001 Daniel Hartmeier 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * - Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * - Redistributions in binary form must reproduce the above 15 * copyright notice, this list of conditions and the following 16 * disclaimer in the documentation and/or other materials provided 17 * with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 23 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 24 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 25 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 26 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 29 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 * 32 */ 33 34#include <sys/types.h> 35#include <sys/ioctl.h> 36#include <sys/socket.h> 37 38#include <net/if.h> 39#include <netinet/in.h>
|
| 40#if defined(__FreeBSD__) 41#include <inttypes.h> 42#include <net/route.h> 43#else 44#define PRIu64 "llu" 45#endif
|
39#include <net/pfvar.h> 40#include <arpa/inet.h> 41#include <altq/altq.h> 42 43#include <err.h> 44#include <errno.h> 45#include <fcntl.h> 46#include <limits.h> 47#include <netdb.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h> 51#include <unistd.h> 52 53#include "pfctl_parser.h" 54#include "pfctl.h" 55 56void usage(void); 57int pfctl_enable(int, int); 58int pfctl_disable(int, int); 59int pfctl_clear_stats(int, int); 60int pfctl_clear_rules(int, int, char *, char *); 61int pfctl_clear_nat(int, int, char *, char *); 62int pfctl_clear_altq(int, int); 63int pfctl_clear_states(int, int); 64int pfctl_kill_states(int, int); 65int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int, 66 char *, char *); 67void pfctl_print_rule_counters(struct pf_rule *, int); 68int pfctl_show_rules(int, int, int, char *, char *); 69int pfctl_show_nat(int, int, char *, char *); 70int pfctl_show_states(int, u_int8_t, int); 71int pfctl_show_status(int); 72int pfctl_show_timeouts(int); 73int pfctl_show_limits(int); 74int pfctl_debug(int, u_int32_t, int); 75int pfctl_clear_rule_counters(int, int); 76int pfctl_test_altqsupport(int, int); 77int pfctl_show_anchors(int, int, char *); 78const char *pfctl_lookup_option(char *, const char **); 79 80const char *clearopt; 81char *rulesopt; 82const char *showopt; 83const char *debugopt; 84char *anchoropt; 85char *tableopt; 86const char *tblcmdopt; 87int state_killers; 88char *state_kill[2]; 89int loadopt; 90int altqsupport; 91 92int dev = -1; 93 94const char *infile; 95 96static const struct { 97 const char *name; 98 int index; 99} pf_limits[] = { 100 { "states", PF_LIMIT_STATES }, 101 { "frags", PF_LIMIT_FRAGS }, 102 { NULL, 0 } 103}; 104 105struct pf_hint { 106 const char *name; 107 int timeout; 108}; 109static const struct pf_hint pf_hint_normal[] = { 110 { "tcp.first", 2 * 60 }, 111 { "tcp.opening", 30 }, 112 { "tcp.established", 24 * 60 * 60 }, 113 { "tcp.closing", 15 * 60 }, 114 { "tcp.finwait", 45 }, 115 { "tcp.closed", 90 }, 116 { NULL, 0 } 117}; 118static const struct pf_hint pf_hint_satellite[] = { 119 { "tcp.first", 3 * 60 }, 120 { "tcp.opening", 30 + 5 }, 121 { "tcp.established", 24 * 60 * 60 }, 122 { "tcp.closing", 15 * 60 + 5 }, 123 { "tcp.finwait", 45 + 5 }, 124 { "tcp.closed", 90 + 5 }, 125 { NULL, 0 } 126}; 127static const struct pf_hint pf_hint_conservative[] = { 128 { "tcp.first", 60 * 60 }, 129 { "tcp.opening", 15 * 60 }, 130 { "tcp.established", 5 * 24 * 60 * 60 }, 131 { "tcp.closing", 60 * 60 }, 132 { "tcp.finwait", 10 * 60 }, 133 { "tcp.closed", 3 * 60 }, 134 { NULL, 0 } 135}; 136static const struct pf_hint pf_hint_aggressive[] = { 137 { "tcp.first", 30 }, 138 { "tcp.opening", 5 }, 139 { "tcp.established", 5 * 60 * 60 }, 140 { "tcp.closing", 60 }, 141 { "tcp.finwait", 30 }, 142 { "tcp.closed", 30 }, 143 { NULL, 0 } 144}; 145 146static const struct { 147 const char *name; 148 const struct pf_hint *hint; 149} pf_hints[] = { 150 { "normal", pf_hint_normal }, 151 { "satellite", pf_hint_satellite }, 152 { "high-latency", pf_hint_satellite }, 153 { "conservative", pf_hint_conservative }, 154 { "aggressive", pf_hint_aggressive }, 155 { NULL, NULL } 156}; 157 158static const char *clearopt_list[] = { 159 "nat", "queue", "rules", "state", "info", "Tables", "osfp", "all", NULL 160}; 161 162static const char *showopt_list[] = { 163 "nat", "queue", "rules", "Anchors", "state", "info", "labels", 164 "timeouts", "memory", "Tables", "osfp", "all", NULL 165}; 166 167static const char *tblcmdopt_list[] = { 168 "kill", "flush", "add", "delete", "load", "replace", "show", 169 "test", "zero", NULL 170}; 171 172static const char *debugopt_list[] = { 173 "none", "urgent", "misc", "loud", NULL 174}; 175 176 177void 178usage(void) 179{ 180 extern char *__progname; 181 182 fprintf(stderr, "usage: %s [-AdeghnNqrROvz] ", __progname); 183 fprintf(stderr, "[-a anchor[:ruleset]] [-D macro=value]\n"); 184 fprintf(stderr, " "); 185 fprintf(stderr, "[-f file] [-F modifier] [-k host] [-s modifier]\n"); 186 fprintf(stderr, " "); 187 fprintf(stderr, "[-t table] [-T command [address ...]] [-x level]\n"); 188 exit(1); 189} 190 191int 192pfctl_enable(int dev, int opts) 193{ 194 if (ioctl(dev, DIOCSTART)) { 195 if (errno == EEXIST) 196 errx(1, "pf already enabled");
| 46#include <net/pfvar.h> 47#include <arpa/inet.h> 48#include <altq/altq.h> 49 50#include <err.h> 51#include <errno.h> 52#include <fcntl.h> 53#include <limits.h> 54#include <netdb.h> 55#include <stdio.h> 56#include <stdlib.h> 57#include <string.h> 58#include <unistd.h> 59 60#include "pfctl_parser.h" 61#include "pfctl.h" 62 63void usage(void); 64int pfctl_enable(int, int); 65int pfctl_disable(int, int); 66int pfctl_clear_stats(int, int); 67int pfctl_clear_rules(int, int, char *, char *); 68int pfctl_clear_nat(int, int, char *, char *); 69int pfctl_clear_altq(int, int); 70int pfctl_clear_states(int, int); 71int pfctl_kill_states(int, int); 72int pfctl_get_pool(int, struct pf_pool *, u_int32_t, u_int32_t, int, 73 char *, char *); 74void pfctl_print_rule_counters(struct pf_rule *, int); 75int pfctl_show_rules(int, int, int, char *, char *); 76int pfctl_show_nat(int, int, char *, char *); 77int pfctl_show_states(int, u_int8_t, int); 78int pfctl_show_status(int); 79int pfctl_show_timeouts(int); 80int pfctl_show_limits(int); 81int pfctl_debug(int, u_int32_t, int); 82int pfctl_clear_rule_counters(int, int); 83int pfctl_test_altqsupport(int, int); 84int pfctl_show_anchors(int, int, char *); 85const char *pfctl_lookup_option(char *, const char **); 86 87const char *clearopt; 88char *rulesopt; 89const char *showopt; 90const char *debugopt; 91char *anchoropt; 92char *tableopt; 93const char *tblcmdopt; 94int state_killers; 95char *state_kill[2]; 96int loadopt; 97int altqsupport; 98 99int dev = -1; 100 101const char *infile; 102 103static const struct { 104 const char *name; 105 int index; 106} pf_limits[] = { 107 { "states", PF_LIMIT_STATES }, 108 { "frags", PF_LIMIT_FRAGS }, 109 { NULL, 0 } 110}; 111 112struct pf_hint { 113 const char *name; 114 int timeout; 115}; 116static const struct pf_hint pf_hint_normal[] = { 117 { "tcp.first", 2 * 60 }, 118 { "tcp.opening", 30 }, 119 { "tcp.established", 24 * 60 * 60 }, 120 { "tcp.closing", 15 * 60 }, 121 { "tcp.finwait", 45 }, 122 { "tcp.closed", 90 }, 123 { NULL, 0 } 124}; 125static const struct pf_hint pf_hint_satellite[] = { 126 { "tcp.first", 3 * 60 }, 127 { "tcp.opening", 30 + 5 }, 128 { "tcp.established", 24 * 60 * 60 }, 129 { "tcp.closing", 15 * 60 + 5 }, 130 { "tcp.finwait", 45 + 5 }, 131 { "tcp.closed", 90 + 5 }, 132 { NULL, 0 } 133}; 134static const struct pf_hint pf_hint_conservative[] = { 135 { "tcp.first", 60 * 60 }, 136 { "tcp.opening", 15 * 60 }, 137 { "tcp.established", 5 * 24 * 60 * 60 }, 138 { "tcp.closing", 60 * 60 }, 139 { "tcp.finwait", 10 * 60 }, 140 { "tcp.closed", 3 * 60 }, 141 { NULL, 0 } 142}; 143static const struct pf_hint pf_hint_aggressive[] = { 144 { "tcp.first", 30 }, 145 { "tcp.opening", 5 }, 146 { "tcp.established", 5 * 60 * 60 }, 147 { "tcp.closing", 60 }, 148 { "tcp.finwait", 30 }, 149 { "tcp.closed", 30 }, 150 { NULL, 0 } 151}; 152 153static const struct { 154 const char *name; 155 const struct pf_hint *hint; 156} pf_hints[] = { 157 { "normal", pf_hint_normal }, 158 { "satellite", pf_hint_satellite }, 159 { "high-latency", pf_hint_satellite }, 160 { "conservative", pf_hint_conservative }, 161 { "aggressive", pf_hint_aggressive }, 162 { NULL, NULL } 163}; 164 165static const char *clearopt_list[] = { 166 "nat", "queue", "rules", "state", "info", "Tables", "osfp", "all", NULL 167}; 168 169static const char *showopt_list[] = { 170 "nat", "queue", "rules", "Anchors", "state", "info", "labels", 171 "timeouts", "memory", "Tables", "osfp", "all", NULL 172}; 173 174static const char *tblcmdopt_list[] = { 175 "kill", "flush", "add", "delete", "load", "replace", "show", 176 "test", "zero", NULL 177}; 178 179static const char *debugopt_list[] = { 180 "none", "urgent", "misc", "loud", NULL 181}; 182 183 184void 185usage(void) 186{ 187 extern char *__progname; 188 189 fprintf(stderr, "usage: %s [-AdeghnNqrROvz] ", __progname); 190 fprintf(stderr, "[-a anchor[:ruleset]] [-D macro=value]\n"); 191 fprintf(stderr, " "); 192 fprintf(stderr, "[-f file] [-F modifier] [-k host] [-s modifier]\n"); 193 fprintf(stderr, " "); 194 fprintf(stderr, "[-t table] [-T command [address ...]] [-x level]\n"); 195 exit(1); 196} 197 198int 199pfctl_enable(int dev, int opts) 200{ 201 if (ioctl(dev, DIOCSTART)) { 202 if (errno == EEXIST) 203 errx(1, "pf already enabled");
|
| 204#if defined(__FreeBSD__) 205 else if (errno == ESRCH) 206 errx(1, "pfil registeration failed"); 207#endif
|
197 else 198 err(1, "DIOCSTART"); 199 } 200 if ((opts & PF_OPT_QUIET) == 0) 201 fprintf(stderr, "pf enabled\n"); 202 203 if (altqsupport && ioctl(dev, DIOCSTARTALTQ)) 204 if (errno != EEXIST) 205 err(1, "DIOCSTARTALTQ"); 206 207 return (0); 208} 209 210int 211pfctl_disable(int dev, int opts) 212{ 213 if (ioctl(dev, DIOCSTOP)) { 214 if (errno == ENOENT) 215 errx(1, "pf not enabled"); 216 else 217 err(1, "DIOCSTOP"); 218 } 219 if ((opts & PF_OPT_QUIET) == 0) 220 fprintf(stderr, "pf disabled\n"); 221 222 if (altqsupport && ioctl(dev, DIOCSTOPALTQ)) 223 if (errno != ENOENT) 224 err(1, "DIOCSTOPALTQ"); 225 226 return (0); 227} 228 229int 230pfctl_clear_stats(int dev, int opts) 231{ 232 if (ioctl(dev, DIOCCLRSTATUS)) 233 err(1, "DIOCCLRSTATUS"); 234 if ((opts & PF_OPT_QUIET) == 0) 235 fprintf(stderr, "pf: statistics cleared\n"); 236 return (0); 237} 238 239int 240pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname) 241{ 242 struct pfioc_rule pr; 243 244 if (*anchorname && !*rulesetname) { 245 struct pfioc_ruleset pr; 246 int mnr, nr, r; 247 248 memset(&pr, 0, sizeof(pr)); 249 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 250 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 251 if (errno == EINVAL) 252 fprintf(stderr, "No rulesets in anchor '%s'.\n", 253 anchorname); 254 else 255 err(1, "DIOCGETRULESETS"); 256 return (-1); 257 } 258 mnr = pr.nr; 259 for (nr = mnr - 1; nr >= 0; --nr) { 260 pr.nr = nr; 261 if (ioctl(dev, DIOCGETRULESET, &pr)) 262 err(1, "DIOCGETRULESET"); 263 r = pfctl_clear_rules(dev, opts | PF_OPT_QUIET, 264 anchorname, pr.name); 265 if (r) 266 return (r); 267 } 268 if ((opts & PF_OPT_QUIET) == 0) 269 fprintf(stderr, "rules cleared\n"); 270 return (0); 271 } 272 memset(&pr, 0, sizeof(pr)); 273 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 274 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 275 pr.rule.action = PF_SCRUB; 276 if (ioctl(dev, DIOCBEGINRULES, &pr)) 277 err(1, "DIOCBEGINRULES"); 278 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 279 err(1, "DIOCCOMMITRULES"); 280 pr.rule.action = PF_PASS; 281 if (ioctl(dev, DIOCBEGINRULES, &pr)) 282 err(1, "DIOCBEGINRULES"); 283 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 284 err(1, "DIOCCOMMITRULES"); 285 if ((opts & PF_OPT_QUIET) == 0) 286 fprintf(stderr, "rules cleared\n"); 287 return (0); 288} 289 290int 291pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname) 292{ 293 struct pfioc_rule pr; 294 295 if (*anchorname && !*rulesetname) { 296 struct pfioc_ruleset pr; 297 int mnr, nr, r; 298 299 memset(&pr, 0, sizeof(pr)); 300 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 301 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 302 if (errno == EINVAL) 303 fprintf(stderr, "No rulesets in anchor '%s'.\n", 304 anchorname); 305 else 306 err(1, "DIOCGETRULESETS"); 307 return (-1); 308 } 309 mnr = pr.nr; 310 for (nr = mnr - 1; nr >= 0; --nr) { 311 pr.nr = nr; 312 if (ioctl(dev, DIOCGETRULESET, &pr)) 313 err(1, "DIOCGETRULESET"); 314 r = pfctl_clear_nat(dev, opts | PF_OPT_QUIET, 315 anchorname, pr.name); 316 if (r) 317 return (r); 318 } 319 if ((opts & PF_OPT_QUIET) == 0) 320 fprintf(stderr, "nat cleared\n"); 321 return (0); 322 } 323 memset(&pr, 0, sizeof(pr)); 324 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 325 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 326 pr.rule.action = PF_NAT; 327 if (ioctl(dev, DIOCBEGINRULES, &pr)) 328 err(1, "DIOCBEGINRULES"); 329 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 330 err(1, "DIOCCOMMITRULES"); 331 pr.rule.action = PF_BINAT; 332 if (ioctl(dev, DIOCBEGINRULES, &pr)) 333 err(1, "DIOCBEGINRULES"); 334 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 335 err(1, "DIOCCOMMITRULES"); 336 pr.rule.action = PF_RDR; 337 if (ioctl(dev, DIOCBEGINRULES, &pr)) 338 err(1, "DIOCBEGINRULES"); 339 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 340 err(1, "DIOCCOMMITRULES"); 341 if ((opts & PF_OPT_QUIET) == 0) 342 fprintf(stderr, "nat cleared\n"); 343 return (0); 344} 345 346int 347pfctl_clear_altq(int dev, int opts) 348{ 349 struct pfioc_altq pa; 350 351 if (!altqsupport) 352 return (-1); 353 memset(&pa, 0, sizeof(pa)); 354 if (ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) 355 err(1, "DIOCBEGINALTQS"); 356 else if (ioctl(dev, DIOCCOMMITALTQS, &pa.ticket)) 357 err(1, "DIOCCOMMITALTQS"); 358 if ((opts & PF_OPT_QUIET) == 0) 359 fprintf(stderr, "altq cleared\n"); 360 return (0); 361} 362 363int 364pfctl_clear_states(int dev, int opts) 365{ 366 if (ioctl(dev, DIOCCLRSTATES)) 367 err(1, "DIOCCLRSTATES"); 368 if ((opts & PF_OPT_QUIET) == 0) 369 fprintf(stderr, "states cleared\n"); 370 return (0); 371} 372 373int 374pfctl_kill_states(int dev, int opts) 375{ 376 struct pfioc_state_kill psk; 377 struct addrinfo *res[2], *resp[2]; 378 struct sockaddr last_src, last_dst; 379 int killed, sources, dests; 380 int ret_ga; 381 382 killed = sources = dests = 0; 383 384 memset(&psk, 0, sizeof(psk)); 385 memset(&psk.psk_src.addr.v.a.mask, 0xff, 386 sizeof(psk.psk_src.addr.v.a.mask)); 387 memset(&last_src, 0xff, sizeof(last_src)); 388 memset(&last_dst, 0xff, sizeof(last_dst)); 389 390 if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { 391 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 392 /* NOTREACHED */ 393 } 394 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { 395 if (resp[0]->ai_addr == NULL) 396 continue; 397 /* We get lots of duplicates. Catch the easy ones */ 398 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) 399 continue; 400 last_src = *(struct sockaddr *)resp[0]->ai_addr; 401 402 psk.psk_af = resp[0]->ai_family; 403 sources++; 404 405 if (psk.psk_af == AF_INET) 406 psk.psk_src.addr.v.a.addr.v4 = 407 ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; 408 else if (psk.psk_af == AF_INET6) 409 psk.psk_src.addr.v.a.addr.v6 = 410 ((struct sockaddr_in6 *)resp[0]->ai_addr)-> 411 sin6_addr; 412 else 413 errx(1, "Unknown address family %d", psk.psk_af); 414 415 if (state_killers > 1) { 416 dests = 0; 417 memset(&psk.psk_dst.addr.v.a.mask, 0xff, 418 sizeof(psk.psk_dst.addr.v.a.mask)); 419 memset(&last_dst, 0xff, sizeof(last_dst)); 420 if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, 421 &res[1]))) { 422 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 423 /* NOTREACHED */ 424 } 425 for (resp[1] = res[1]; resp[1]; 426 resp[1] = resp[1]->ai_next) { 427 if (resp[1]->ai_addr == NULL) 428 continue; 429 if (psk.psk_af != resp[1]->ai_family) 430 continue; 431 432 if (memcmp(&last_dst, resp[1]->ai_addr, 433 sizeof(last_dst)) == 0) 434 continue; 435 last_dst = *(struct sockaddr *)resp[1]->ai_addr; 436 437 dests++; 438 439 if (psk.psk_af == AF_INET) 440 psk.psk_dst.addr.v.a.addr.v4 = 441 ((struct sockaddr_in *)resp[1]-> 442 ai_addr)->sin_addr; 443 else if (psk.psk_af == AF_INET6) 444 psk.psk_dst.addr.v.a.addr.v6 = 445 ((struct sockaddr_in6 *)resp[1]-> 446 ai_addr)->sin6_addr; 447 else 448 errx(1, "Unknown address family %d", 449 psk.psk_af); 450 451 if (ioctl(dev, DIOCKILLSTATES, &psk)) 452 err(1, "DIOCKILLSTATES"); 453 killed += psk.psk_af; 454 /* fixup psk.psk_af */ 455 psk.psk_af = resp[1]->ai_family; 456 } 457 freeaddrinfo(res[1]); 458 } else { 459 if (ioctl(dev, DIOCKILLSTATES, &psk)) 460 err(1, "DIOCKILLSTATES"); 461 killed += psk.psk_af; 462 /* fixup psk.psk_af */ 463 psk.psk_af = res[0]->ai_family; 464 } 465 } 466 467 freeaddrinfo(res[0]); 468 469 if ((opts & PF_OPT_QUIET) == 0) 470 fprintf(stderr, "killed %d states from %d sources and %d " 471 "destinations\n", killed, sources, dests); 472 return (0); 473} 474 475int 476pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, 477 u_int32_t ticket, int r_action, char *anchorname, char *rulesetname) 478{ 479 struct pfioc_pooladdr pp; 480 struct pf_pooladdr *pa; 481 u_int32_t pnr, mpnr; 482 483 memset(&pp, 0, sizeof(pp)); 484 memcpy(pp.anchor, anchorname, sizeof(pp.anchor)); 485 memcpy(pp.ruleset, rulesetname, sizeof(pp.ruleset)); 486 pp.r_action = r_action; 487 pp.r_num = nr; 488 pp.ticket = ticket; 489 if (ioctl(dev, DIOCGETADDRS, &pp)) { 490 warn("DIOCGETADDRS"); 491 return (-1); 492 } 493 mpnr = pp.nr; 494 TAILQ_INIT(&pool->list); 495 for (pnr = 0; pnr < mpnr; ++pnr) { 496 pp.nr = pnr; 497 if (ioctl(dev, DIOCGETADDR, &pp)) { 498 warn("DIOCGETADDR"); 499 return (-1); 500 } 501 pa = calloc(1, sizeof(struct pf_pooladdr)); 502 if (pa == NULL) 503 err(1, "calloc"); 504 bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr)); 505 TAILQ_INSERT_TAIL(&pool->list, pa, entries); 506 } 507 508 return (0); 509} 510 511void 512pfctl_clear_pool(struct pf_pool *pool) 513{ 514 struct pf_pooladdr *pa; 515 516 while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { 517 TAILQ_REMOVE(&pool->list, pa, entries); 518 free(pa); 519 } 520} 521 522void 523pfctl_print_rule_counters(struct pf_rule *rule, int opts) 524{ 525 if (opts & PF_OPT_DEBUG) { 526 const char *t[PF_SKIP_COUNT] = { "i", "d", "f", 527 "p", "sa", "sp", "da", "dp" }; 528 int i; 529 530 printf(" [ Skip steps: "); 531 for (i = 0; i < PF_SKIP_COUNT; ++i) { 532 if (rule->skip[i].nr == rule->nr + 1) 533 continue; 534 printf("%s=", t[i]); 535 if (rule->skip[i].nr == -1) 536 printf("end "); 537 else 538 printf("%u ", rule->skip[i].nr); 539 } 540 printf("]\n"); 541 542 printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", 543 rule->qname, rule->qid, rule->pqname, rule->pqid); 544 } 545 if (opts & PF_OPT_VERBOSE)
| 208 else 209 err(1, "DIOCSTART"); 210 } 211 if ((opts & PF_OPT_QUIET) == 0) 212 fprintf(stderr, "pf enabled\n"); 213 214 if (altqsupport && ioctl(dev, DIOCSTARTALTQ)) 215 if (errno != EEXIST) 216 err(1, "DIOCSTARTALTQ"); 217 218 return (0); 219} 220 221int 222pfctl_disable(int dev, int opts) 223{ 224 if (ioctl(dev, DIOCSTOP)) { 225 if (errno == ENOENT) 226 errx(1, "pf not enabled"); 227 else 228 err(1, "DIOCSTOP"); 229 } 230 if ((opts & PF_OPT_QUIET) == 0) 231 fprintf(stderr, "pf disabled\n"); 232 233 if (altqsupport && ioctl(dev, DIOCSTOPALTQ)) 234 if (errno != ENOENT) 235 err(1, "DIOCSTOPALTQ"); 236 237 return (0); 238} 239 240int 241pfctl_clear_stats(int dev, int opts) 242{ 243 if (ioctl(dev, DIOCCLRSTATUS)) 244 err(1, "DIOCCLRSTATUS"); 245 if ((opts & PF_OPT_QUIET) == 0) 246 fprintf(stderr, "pf: statistics cleared\n"); 247 return (0); 248} 249 250int 251pfctl_clear_rules(int dev, int opts, char *anchorname, char *rulesetname) 252{ 253 struct pfioc_rule pr; 254 255 if (*anchorname && !*rulesetname) { 256 struct pfioc_ruleset pr; 257 int mnr, nr, r; 258 259 memset(&pr, 0, sizeof(pr)); 260 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 261 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 262 if (errno == EINVAL) 263 fprintf(stderr, "No rulesets in anchor '%s'.\n", 264 anchorname); 265 else 266 err(1, "DIOCGETRULESETS"); 267 return (-1); 268 } 269 mnr = pr.nr; 270 for (nr = mnr - 1; nr >= 0; --nr) { 271 pr.nr = nr; 272 if (ioctl(dev, DIOCGETRULESET, &pr)) 273 err(1, "DIOCGETRULESET"); 274 r = pfctl_clear_rules(dev, opts | PF_OPT_QUIET, 275 anchorname, pr.name); 276 if (r) 277 return (r); 278 } 279 if ((opts & PF_OPT_QUIET) == 0) 280 fprintf(stderr, "rules cleared\n"); 281 return (0); 282 } 283 memset(&pr, 0, sizeof(pr)); 284 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 285 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 286 pr.rule.action = PF_SCRUB; 287 if (ioctl(dev, DIOCBEGINRULES, &pr)) 288 err(1, "DIOCBEGINRULES"); 289 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 290 err(1, "DIOCCOMMITRULES"); 291 pr.rule.action = PF_PASS; 292 if (ioctl(dev, DIOCBEGINRULES, &pr)) 293 err(1, "DIOCBEGINRULES"); 294 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 295 err(1, "DIOCCOMMITRULES"); 296 if ((opts & PF_OPT_QUIET) == 0) 297 fprintf(stderr, "rules cleared\n"); 298 return (0); 299} 300 301int 302pfctl_clear_nat(int dev, int opts, char *anchorname, char *rulesetname) 303{ 304 struct pfioc_rule pr; 305 306 if (*anchorname && !*rulesetname) { 307 struct pfioc_ruleset pr; 308 int mnr, nr, r; 309 310 memset(&pr, 0, sizeof(pr)); 311 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 312 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 313 if (errno == EINVAL) 314 fprintf(stderr, "No rulesets in anchor '%s'.\n", 315 anchorname); 316 else 317 err(1, "DIOCGETRULESETS"); 318 return (-1); 319 } 320 mnr = pr.nr; 321 for (nr = mnr - 1; nr >= 0; --nr) { 322 pr.nr = nr; 323 if (ioctl(dev, DIOCGETRULESET, &pr)) 324 err(1, "DIOCGETRULESET"); 325 r = pfctl_clear_nat(dev, opts | PF_OPT_QUIET, 326 anchorname, pr.name); 327 if (r) 328 return (r); 329 } 330 if ((opts & PF_OPT_QUIET) == 0) 331 fprintf(stderr, "nat cleared\n"); 332 return (0); 333 } 334 memset(&pr, 0, sizeof(pr)); 335 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 336 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 337 pr.rule.action = PF_NAT; 338 if (ioctl(dev, DIOCBEGINRULES, &pr)) 339 err(1, "DIOCBEGINRULES"); 340 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 341 err(1, "DIOCCOMMITRULES"); 342 pr.rule.action = PF_BINAT; 343 if (ioctl(dev, DIOCBEGINRULES, &pr)) 344 err(1, "DIOCBEGINRULES"); 345 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 346 err(1, "DIOCCOMMITRULES"); 347 pr.rule.action = PF_RDR; 348 if (ioctl(dev, DIOCBEGINRULES, &pr)) 349 err(1, "DIOCBEGINRULES"); 350 else if (ioctl(dev, DIOCCOMMITRULES, &pr)) 351 err(1, "DIOCCOMMITRULES"); 352 if ((opts & PF_OPT_QUIET) == 0) 353 fprintf(stderr, "nat cleared\n"); 354 return (0); 355} 356 357int 358pfctl_clear_altq(int dev, int opts) 359{ 360 struct pfioc_altq pa; 361 362 if (!altqsupport) 363 return (-1); 364 memset(&pa, 0, sizeof(pa)); 365 if (ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) 366 err(1, "DIOCBEGINALTQS"); 367 else if (ioctl(dev, DIOCCOMMITALTQS, &pa.ticket)) 368 err(1, "DIOCCOMMITALTQS"); 369 if ((opts & PF_OPT_QUIET) == 0) 370 fprintf(stderr, "altq cleared\n"); 371 return (0); 372} 373 374int 375pfctl_clear_states(int dev, int opts) 376{ 377 if (ioctl(dev, DIOCCLRSTATES)) 378 err(1, "DIOCCLRSTATES"); 379 if ((opts & PF_OPT_QUIET) == 0) 380 fprintf(stderr, "states cleared\n"); 381 return (0); 382} 383 384int 385pfctl_kill_states(int dev, int opts) 386{ 387 struct pfioc_state_kill psk; 388 struct addrinfo *res[2], *resp[2]; 389 struct sockaddr last_src, last_dst; 390 int killed, sources, dests; 391 int ret_ga; 392 393 killed = sources = dests = 0; 394 395 memset(&psk, 0, sizeof(psk)); 396 memset(&psk.psk_src.addr.v.a.mask, 0xff, 397 sizeof(psk.psk_src.addr.v.a.mask)); 398 memset(&last_src, 0xff, sizeof(last_src)); 399 memset(&last_dst, 0xff, sizeof(last_dst)); 400 401 if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { 402 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 403 /* NOTREACHED */ 404 } 405 for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { 406 if (resp[0]->ai_addr == NULL) 407 continue; 408 /* We get lots of duplicates. Catch the easy ones */ 409 if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) 410 continue; 411 last_src = *(struct sockaddr *)resp[0]->ai_addr; 412 413 psk.psk_af = resp[0]->ai_family; 414 sources++; 415 416 if (psk.psk_af == AF_INET) 417 psk.psk_src.addr.v.a.addr.v4 = 418 ((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; 419 else if (psk.psk_af == AF_INET6) 420 psk.psk_src.addr.v.a.addr.v6 = 421 ((struct sockaddr_in6 *)resp[0]->ai_addr)-> 422 sin6_addr; 423 else 424 errx(1, "Unknown address family %d", psk.psk_af); 425 426 if (state_killers > 1) { 427 dests = 0; 428 memset(&psk.psk_dst.addr.v.a.mask, 0xff, 429 sizeof(psk.psk_dst.addr.v.a.mask)); 430 memset(&last_dst, 0xff, sizeof(last_dst)); 431 if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, 432 &res[1]))) { 433 errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); 434 /* NOTREACHED */ 435 } 436 for (resp[1] = res[1]; resp[1]; 437 resp[1] = resp[1]->ai_next) { 438 if (resp[1]->ai_addr == NULL) 439 continue; 440 if (psk.psk_af != resp[1]->ai_family) 441 continue; 442 443 if (memcmp(&last_dst, resp[1]->ai_addr, 444 sizeof(last_dst)) == 0) 445 continue; 446 last_dst = *(struct sockaddr *)resp[1]->ai_addr; 447 448 dests++; 449 450 if (psk.psk_af == AF_INET) 451 psk.psk_dst.addr.v.a.addr.v4 = 452 ((struct sockaddr_in *)resp[1]-> 453 ai_addr)->sin_addr; 454 else if (psk.psk_af == AF_INET6) 455 psk.psk_dst.addr.v.a.addr.v6 = 456 ((struct sockaddr_in6 *)resp[1]-> 457 ai_addr)->sin6_addr; 458 else 459 errx(1, "Unknown address family %d", 460 psk.psk_af); 461 462 if (ioctl(dev, DIOCKILLSTATES, &psk)) 463 err(1, "DIOCKILLSTATES"); 464 killed += psk.psk_af; 465 /* fixup psk.psk_af */ 466 psk.psk_af = resp[1]->ai_family; 467 } 468 freeaddrinfo(res[1]); 469 } else { 470 if (ioctl(dev, DIOCKILLSTATES, &psk)) 471 err(1, "DIOCKILLSTATES"); 472 killed += psk.psk_af; 473 /* fixup psk.psk_af */ 474 psk.psk_af = res[0]->ai_family; 475 } 476 } 477 478 freeaddrinfo(res[0]); 479 480 if ((opts & PF_OPT_QUIET) == 0) 481 fprintf(stderr, "killed %d states from %d sources and %d " 482 "destinations\n", killed, sources, dests); 483 return (0); 484} 485 486int 487pfctl_get_pool(int dev, struct pf_pool *pool, u_int32_t nr, 488 u_int32_t ticket, int r_action, char *anchorname, char *rulesetname) 489{ 490 struct pfioc_pooladdr pp; 491 struct pf_pooladdr *pa; 492 u_int32_t pnr, mpnr; 493 494 memset(&pp, 0, sizeof(pp)); 495 memcpy(pp.anchor, anchorname, sizeof(pp.anchor)); 496 memcpy(pp.ruleset, rulesetname, sizeof(pp.ruleset)); 497 pp.r_action = r_action; 498 pp.r_num = nr; 499 pp.ticket = ticket; 500 if (ioctl(dev, DIOCGETADDRS, &pp)) { 501 warn("DIOCGETADDRS"); 502 return (-1); 503 } 504 mpnr = pp.nr; 505 TAILQ_INIT(&pool->list); 506 for (pnr = 0; pnr < mpnr; ++pnr) { 507 pp.nr = pnr; 508 if (ioctl(dev, DIOCGETADDR, &pp)) { 509 warn("DIOCGETADDR"); 510 return (-1); 511 } 512 pa = calloc(1, sizeof(struct pf_pooladdr)); 513 if (pa == NULL) 514 err(1, "calloc"); 515 bcopy(&pp.addr, pa, sizeof(struct pf_pooladdr)); 516 TAILQ_INSERT_TAIL(&pool->list, pa, entries); 517 } 518 519 return (0); 520} 521 522void 523pfctl_clear_pool(struct pf_pool *pool) 524{ 525 struct pf_pooladdr *pa; 526 527 while ((pa = TAILQ_FIRST(&pool->list)) != NULL) { 528 TAILQ_REMOVE(&pool->list, pa, entries); 529 free(pa); 530 } 531} 532 533void 534pfctl_print_rule_counters(struct pf_rule *rule, int opts) 535{ 536 if (opts & PF_OPT_DEBUG) { 537 const char *t[PF_SKIP_COUNT] = { "i", "d", "f", 538 "p", "sa", "sp", "da", "dp" }; 539 int i; 540 541 printf(" [ Skip steps: "); 542 for (i = 0; i < PF_SKIP_COUNT; ++i) { 543 if (rule->skip[i].nr == rule->nr + 1) 544 continue; 545 printf("%s=", t[i]); 546 if (rule->skip[i].nr == -1) 547 printf("end "); 548 else 549 printf("%u ", rule->skip[i].nr); 550 } 551 printf("]\n"); 552 553 printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", 554 rule->qname, rule->qid, rule->pqname, rule->pqid); 555 } 556 if (opts & PF_OPT_VERBOSE)
|
546 printf(" [ Evaluations: %-8llu Packets: %-8llu " 547 "Bytes: %-10llu States: %-6u]\n",
| 557 printf(" [ Evaluations: %-8"PRIu64" Packets: %-8"PRIu64" " 558 "Bytes: %-10"PRIu64" States: %-6u]\n",
|
548 rule->evaluations, rule->packets, 549 rule->bytes, rule->states); 550} 551 552int 553pfctl_show_rules(int dev, int opts, int format, char *anchorname, 554 char *rulesetname) 555{ 556 struct pfioc_rule pr; 557 u_int32_t nr, mnr; 558 int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); 559 560 if (*anchorname && !*rulesetname) { 561 struct pfioc_ruleset pr; 562 int r; 563 564 memset(&pr, 0, sizeof(pr)); 565 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 566 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 567 if (errno == EINVAL) 568 fprintf(stderr, "No rulesets in anchor '%s'.\n", 569 anchorname); 570 else 571 err(1, "DIOCGETRULESETS"); 572 return (-1); 573 } 574 mnr = pr.nr; 575 for (nr = 0; nr < mnr; ++nr) { 576 pr.nr = nr; 577 if (ioctl(dev, DIOCGETRULESET, &pr)) 578 err(1, "DIOCGETRULESET"); 579 r = pfctl_show_rules(dev, opts, format, anchorname, 580 pr.name); 581 if (r) 582 return (r); 583 } 584 return (0); 585 } 586 587 memset(&pr, 0, sizeof(pr)); 588 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 589 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 590 pr.rule.action = PF_SCRUB; 591 if (ioctl(dev, DIOCGETRULES, &pr)) { 592 warn("DIOCGETRULES"); 593 return (-1); 594 } 595 mnr = pr.nr; 596 for (nr = 0; nr < mnr; ++nr) { 597 pr.nr = nr; 598 if (ioctl(dev, DIOCGETRULE, &pr)) { 599 warn("DIOCGETRULE"); 600 return (-1); 601 } 602 603 if (pfctl_get_pool(dev, &pr.rule.rpool, 604 nr, pr.ticket, PF_SCRUB, anchorname, rulesetname) != 0) 605 return (-1); 606 607 switch (format) { 608 case 1: 609 if (pr.rule.label[0]) { 610 printf("%s ", pr.rule.label);
| 559 rule->evaluations, rule->packets, 560 rule->bytes, rule->states); 561} 562 563int 564pfctl_show_rules(int dev, int opts, int format, char *anchorname, 565 char *rulesetname) 566{ 567 struct pfioc_rule pr; 568 u_int32_t nr, mnr; 569 int rule_numbers = opts & (PF_OPT_VERBOSE2 | PF_OPT_DEBUG); 570 571 if (*anchorname && !*rulesetname) { 572 struct pfioc_ruleset pr; 573 int r; 574 575 memset(&pr, 0, sizeof(pr)); 576 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 577 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 578 if (errno == EINVAL) 579 fprintf(stderr, "No rulesets in anchor '%s'.\n", 580 anchorname); 581 else 582 err(1, "DIOCGETRULESETS"); 583 return (-1); 584 } 585 mnr = pr.nr; 586 for (nr = 0; nr < mnr; ++nr) { 587 pr.nr = nr; 588 if (ioctl(dev, DIOCGETRULESET, &pr)) 589 err(1, "DIOCGETRULESET"); 590 r = pfctl_show_rules(dev, opts, format, anchorname, 591 pr.name); 592 if (r) 593 return (r); 594 } 595 return (0); 596 } 597 598 memset(&pr, 0, sizeof(pr)); 599 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 600 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 601 pr.rule.action = PF_SCRUB; 602 if (ioctl(dev, DIOCGETRULES, &pr)) { 603 warn("DIOCGETRULES"); 604 return (-1); 605 } 606 mnr = pr.nr; 607 for (nr = 0; nr < mnr; ++nr) { 608 pr.nr = nr; 609 if (ioctl(dev, DIOCGETRULE, &pr)) { 610 warn("DIOCGETRULE"); 611 return (-1); 612 } 613 614 if (pfctl_get_pool(dev, &pr.rule.rpool, 615 nr, pr.ticket, PF_SCRUB, anchorname, rulesetname) != 0) 616 return (-1); 617 618 switch (format) { 619 case 1: 620 if (pr.rule.label[0]) { 621 printf("%s ", pr.rule.label);
|
611 printf("%llu %llu %llu\n",
| 622 printf("%"PRIu64" %"PRIu64" %"PRIu64"\n",
|
612 pr.rule.evaluations, pr.rule.packets, 613 pr.rule.bytes); 614 } 615 break; 616 default: 617 print_rule(&pr.rule, rule_numbers); 618 pfctl_print_rule_counters(&pr.rule, opts); 619 } 620 pfctl_clear_pool(&pr.rule.rpool); 621 } 622 pr.rule.action = PF_PASS; 623 if (ioctl(dev, DIOCGETRULES, &pr)) { 624 warn("DIOCGETRULES"); 625 return (-1); 626 } 627 mnr = pr.nr; 628 for (nr = 0; nr < mnr; ++nr) { 629 pr.nr = nr; 630 if (ioctl(dev, DIOCGETRULE, &pr)) { 631 warn("DIOCGETRULE"); 632 return (-1); 633 } 634 635 if (pfctl_get_pool(dev, &pr.rule.rpool, 636 nr, pr.ticket, PF_PASS, anchorname, rulesetname) != 0) 637 return (-1); 638 639 switch (format) { 640 case 1: 641 if (pr.rule.label[0]) { 642 printf("%s ", pr.rule.label);
| 623 pr.rule.evaluations, pr.rule.packets, 624 pr.rule.bytes); 625 } 626 break; 627 default: 628 print_rule(&pr.rule, rule_numbers); 629 pfctl_print_rule_counters(&pr.rule, opts); 630 } 631 pfctl_clear_pool(&pr.rule.rpool); 632 } 633 pr.rule.action = PF_PASS; 634 if (ioctl(dev, DIOCGETRULES, &pr)) { 635 warn("DIOCGETRULES"); 636 return (-1); 637 } 638 mnr = pr.nr; 639 for (nr = 0; nr < mnr; ++nr) { 640 pr.nr = nr; 641 if (ioctl(dev, DIOCGETRULE, &pr)) { 642 warn("DIOCGETRULE"); 643 return (-1); 644 } 645 646 if (pfctl_get_pool(dev, &pr.rule.rpool, 647 nr, pr.ticket, PF_PASS, anchorname, rulesetname) != 0) 648 return (-1); 649 650 switch (format) { 651 case 1: 652 if (pr.rule.label[0]) { 653 printf("%s ", pr.rule.label);
|
643 printf("%llu %llu %llu\n",
| 654 printf("%"PRIu64" %"PRIu64" %"PRIu64"\n",
|
644 pr.rule.evaluations, pr.rule.packets, 645 pr.rule.bytes); 646 } 647 break; 648 default: 649 print_rule(&pr.rule, rule_numbers); 650 pfctl_print_rule_counters(&pr.rule, opts); 651 } 652 pfctl_clear_pool(&pr.rule.rpool); 653 } 654 return (0); 655} 656 657int 658pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname) 659{ 660 struct pfioc_rule pr; 661 u_int32_t mnr, nr; 662 static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; 663 int i; 664 665 if (*anchorname && !*rulesetname) { 666 struct pfioc_ruleset pr; 667 int r; 668 669 memset(&pr, 0, sizeof(pr)); 670 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 671 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 672 if (errno == EINVAL) 673 fprintf(stderr, "No rulesets in anchor '%s'.\n", 674 anchorname); 675 else 676 err(1, "DIOCGETRULESETS"); 677 return (-1); 678 } 679 mnr = pr.nr; 680 for (nr = 0; nr < mnr; ++nr) { 681 pr.nr = nr; 682 if (ioctl(dev, DIOCGETRULESET, &pr)) 683 err(1, "DIOCGETRULESET"); 684 r = pfctl_show_nat(dev, opts, anchorname, pr.name); 685 if (r) 686 return (r); 687 } 688 return (0); 689 } 690 691 memset(&pr, 0, sizeof(pr)); 692 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 693 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 694 for (i = 0; i < 3; i++) { 695 pr.rule.action = nattype[i]; 696 if (ioctl(dev, DIOCGETRULES, &pr)) { 697 warn("DIOCGETRULES"); 698 return (-1); 699 } 700 mnr = pr.nr; 701 for (nr = 0; nr < mnr; ++nr) { 702 pr.nr = nr; 703 if (ioctl(dev, DIOCGETRULE, &pr)) { 704 warn("DIOCGETRULE"); 705 return (-1); 706 } 707 if (pfctl_get_pool(dev, &pr.rule.rpool, nr, 708 pr.ticket, nattype[i], anchorname, 709 rulesetname) != 0) 710 return (-1); 711 print_rule(&pr.rule, opts & PF_OPT_VERBOSE2); 712 pfctl_print_rule_counters(&pr.rule, opts); 713 pfctl_clear_pool(&pr.rule.rpool); 714 } 715 } 716 return (0); 717} 718 719int 720pfctl_show_states(int dev, u_int8_t proto, int opts) 721{ 722 struct pfioc_states ps; 723 struct pf_state *p; 724 char *inbuf = NULL; 725 unsigned len = 0; 726 int i; 727 728 memset(&ps, 0, sizeof(ps)); 729 for (;;) { 730 ps.ps_len = len; 731 if (len) { 732 ps.ps_buf = inbuf = realloc(inbuf, len); 733 if (inbuf == NULL) 734 err(1, "realloc"); 735 } 736 if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { 737 warn("DIOCGETSTATES"); 738 return (-1); 739 } 740 if (ps.ps_len + sizeof(struct pfioc_states) < len) 741 break; 742 if (len == 0 && ps.ps_len == 0) 743 return (0); 744 if (len == 0 && ps.ps_len != 0) 745 len = ps.ps_len; 746 if (ps.ps_len == 0) 747 return (0); /* no states */ 748 len *= 2; 749 } 750 p = ps.ps_states; 751 for (i = 0; i < ps.ps_len; i += sizeof(*p)) { 752 if (!proto || (p->proto == proto)) 753 print_state(p, opts); 754 p++; 755 } 756 return (0); 757} 758 759int 760pfctl_show_status(int dev) 761{ 762 struct pf_status status; 763 764 if (ioctl(dev, DIOCGETSTATUS, &status)) { 765 warn("DIOCGETSTATUS"); 766 return (-1); 767 } 768 print_status(&status); 769 return (0); 770} 771 772int 773pfctl_show_timeouts(int dev) 774{ 775 struct pfioc_tm pt; 776 int i; 777 778 memset(&pt, 0, sizeof(pt)); 779 for (i = 0; pf_timeouts[i].name; i++) { 780 pt.timeout = pf_timeouts[i].timeout; 781 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) 782 err(1, "DIOCGETTIMEOUT"); 783 printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); 784 if (i >= PFTM_ADAPTIVE_START && i <= PFTM_ADAPTIVE_END) 785 printf(" states"); 786 else 787 printf("s"); 788 printf("\n"); 789 } 790 return (0); 791 792} 793 794int 795pfctl_show_limits(int dev) 796{ 797 struct pfioc_limit pl; 798 int i; 799 800 memset(&pl, 0, sizeof(pl)); 801 for (i = 0; pf_limits[i].name; i++) { 802 pl.index = i; 803 if (ioctl(dev, DIOCGETLIMIT, &pl)) 804 err(1, "DIOCGETLIMIT"); 805 printf("%-10s ", pf_limits[i].name); 806 if (pl.limit == UINT_MAX) 807 printf("unlimited\n"); 808 else 809 printf("hard limit %6u\n", pl.limit); 810 } 811 return (0); 812} 813 814/* callbacks for rule/nat/rdr/addr */ 815int 816pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) 817{ 818 struct pf_pooladdr *pa; 819 820 if ((pf->opts & PF_OPT_NOACTION) == 0) { 821 if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) 822 err(1, "DIOCBEGINADDRS"); 823 } 824 825 pf->paddr.af = af; 826 TAILQ_FOREACH(pa, &p->list, entries) { 827 memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); 828 if ((pf->opts & PF_OPT_NOACTION) == 0) { 829 if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) 830 err(1, "DIOCADDADDR"); 831 } 832 } 833 return (0); 834} 835 836int 837pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) 838{ 839 u_int8_t rs_num; 840 841 switch (r->action) { 842 case PF_SCRUB: 843 if ((loadopt & PFCTL_FLAG_FILTER) == 0) 844 return (0); 845 rs_num = PF_RULESET_SCRUB; 846 break; 847 case PF_DROP: 848 case PF_PASS: 849 if ((loadopt & PFCTL_FLAG_FILTER) == 0) 850 return (0); 851 rs_num = PF_RULESET_FILTER; 852 break; 853 case PF_NAT: 854 case PF_NONAT: 855 if ((loadopt & PFCTL_FLAG_NAT) == 0) 856 return (0); 857 rs_num = PF_RULESET_NAT; 858 break; 859 case PF_RDR: 860 case PF_NORDR: 861 if ((loadopt & PFCTL_FLAG_NAT) == 0) 862 return (0); 863 rs_num = PF_RULESET_RDR; 864 break; 865 case PF_BINAT: 866 case PF_NOBINAT: 867 if ((loadopt & PFCTL_FLAG_NAT) == 0) 868 return (0); 869 rs_num = PF_RULESET_BINAT; 870 break; 871 default: 872 errx(1, "Invalid rule type"); 873 break; 874 } 875 876 if ((pf->opts & PF_OPT_NOACTION) == 0) { 877 if (pfctl_add_pool(pf, &r->rpool, r->af)) 878 return (1); 879 memcpy(&pf->prule[rs_num]->rule, r, 880 sizeof(pf->prule[rs_num]->rule)); 881 pf->prule[rs_num]->pool_ticket = pf->paddr.ticket; 882 if (ioctl(pf->dev, DIOCADDRULE, pf->prule[rs_num])) 883 err(1, "DIOCADDRULE"); 884 } 885 if (pf->opts & PF_OPT_VERBOSE) 886 print_rule(r, pf->opts & PF_OPT_VERBOSE2); 887 pfctl_clear_pool(&r->rpool); 888 return (0); 889} 890 891int 892pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) 893{ 894 if (altqsupport && 895 (loadopt & PFCTL_FLAG_ALTQ) != 0) { 896 memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq)); 897 if ((pf->opts & PF_OPT_NOACTION) == 0) { 898 if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) { 899 if (errno == ENXIO) 900 errx(1, "qtype not configured"); 901 else if (errno == ENODEV) 902 errx(1, "%s: driver does not support " 903 "altq", a->ifname); 904 else 905 err(1, "DIOCADDALTQ"); 906 } 907 } 908 pfaltq_store(&pf->paltq->altq); 909 } 910 return (0); 911} 912 913int 914pfctl_rules(int dev, char *filename, int opts, char *anchorname, 915 char *rulesetname) 916{ 917#define ERR(x) do { warn(x); goto _error; } while(0) 918#define ERRX(x) do { warnx(x); goto _error; } while(0) 919 920 FILE *fin; 921 struct pfioc_rule pr[PF_RULESET_MAX]; 922 struct pfioc_altq pa; 923 struct pfctl pf; 924 struct pfr_table trs; 925 int i; 926 927 memset(&pa, 0, sizeof(pa)); 928 memset(&pf, 0, sizeof(pf)); 929 memset(&trs, 0, sizeof(trs)); 930 for (i = 0; i < PF_RULESET_MAX; i++) { 931 memset(&pr[i], 0, sizeof(pr[i])); 932 memcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor)); 933 memcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset)); 934 } 935 if (strlcpy(trs.pfrt_anchor, anchorname, 936 sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) || 937 strlcpy(trs.pfrt_ruleset, rulesetname, 938 sizeof(trs.pfrt_ruleset)) >= sizeof(trs.pfrt_ruleset)) 939 ERRX("pfctl_rules: strlcpy"); 940 if (strcmp(filename, "-") == 0) { 941 fin = stdin; 942 infile = "stdin"; 943 } else { 944 if ((fin = fopen(filename, "r")) == NULL) { 945 warn("%s", filename); 946 return (1); 947 } 948 infile = filename; 949 } 950 if ((opts & PF_OPT_NOACTION) == 0) { 951 if ((loadopt & PFCTL_FLAG_NAT) != 0) { 952 pr[PF_RULESET_NAT].rule.action = PF_NAT; 953 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_NAT])) 954 ERR("DIOCBEGINRULES"); 955 pr[PF_RULESET_RDR].rule.action = PF_RDR; 956 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_RDR])) 957 ERR("DIOCBEGINRULES"); 958 pr[PF_RULESET_BINAT].rule.action = PF_BINAT; 959 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_BINAT])) 960 ERR("DIOCBEGINRULES"); 961 } 962 if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) && 963 ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) { 964 ERR("DIOCBEGINALTQS"); 965 } 966 if ((loadopt & PFCTL_FLAG_FILTER) != 0) { 967 pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB; 968 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_SCRUB])) 969 ERR("DIOCBEGINRULES"); 970 pr[PF_RULESET_FILTER].rule.action = PF_PASS; 971 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_FILTER])) 972 ERR("DIOCBEGINRULES"); 973 } 974 if (loadopt & PFCTL_FLAG_TABLE) { 975 if (pfr_ina_begin(&trs, &pf.tticket, NULL, 0) != 0) 976 ERR("begin table"); 977 } 978 } 979 /* fill in callback data */ 980 pf.dev = dev; 981 pf.opts = opts; 982 pf.loadopt = loadopt; 983 pf.paltq = &pa; 984 for (i = 0; i < PF_RULESET_MAX; i++) { 985 pf.prule[i] = &pr[i]; 986 } 987 pf.rule_nr = 0; 988 pf.anchor = anchorname; 989 pf.ruleset = rulesetname; 990 if (parse_rules(fin, &pf) < 0) { 991 if ((opts & PF_OPT_NOACTION) == 0) 992 ERRX("Syntax error in config file: " 993 "pf rules not loaded"); 994 else 995 goto _error; 996 } 997 if ((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) 998 if (check_commit_altq(dev, opts) != 0) 999 ERRX("errors in altq config"); 1000 if ((opts & PF_OPT_NOACTION) == 0) { 1001 if ((loadopt & PFCTL_FLAG_NAT) != 0) { 1002 pr[PF_RULESET_NAT].rule.action = PF_NAT; 1003 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_NAT]) && 1004 (errno != EINVAL || pf.rule_nr)) 1005 ERR("DIOCCOMMITRULES NAT"); 1006 pr[PF_RULESET_RDR].rule.action = PF_RDR; 1007 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_RDR]) && 1008 (errno != EINVAL || pf.rule_nr)) 1009 ERR("DIOCCOMMITRULES RDR"); 1010 pr[PF_RULESET_BINAT].rule.action = PF_BINAT; 1011 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_BINAT]) && 1012 (errno != EINVAL || pf.rule_nr)) 1013 ERR("DIOCCOMMITRULES BINAT"); 1014 } 1015 if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) && 1016 ioctl(dev, DIOCCOMMITALTQS, &pa.ticket)) 1017 ERR("DIOCCOMMITALTQS"); 1018 if ((loadopt & PFCTL_FLAG_FILTER) != 0) { 1019 pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB; 1020 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_SCRUB]) && 1021 (errno != EINVAL || pf.rule_nr)) 1022 ERR("DIOCCOMMITRULES SCRUB"); 1023 pr[PF_RULESET_FILTER].rule.action = PF_PASS; 1024 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_FILTER]) && 1025 (errno != EINVAL || pf.rule_nr)) 1026 ERR("DIOCCOMMITRULES FILTER"); 1027 } 1028 if (loadopt & PFCTL_FLAG_TABLE) { 1029 if (pfr_ina_commit(&trs, pf.tticket, NULL, NULL, 0)) 1030 ERR("commit table"); 1031 pf.tdirty = 0; 1032 } 1033 } 1034 if (fin != stdin) 1035 fclose(fin); 1036 1037 /* process "load anchor" directives */ 1038 if (!anchorname[0] && !rulesetname[0]) 1039 if (pfctl_load_anchors(dev, opts) == -1) 1040 ERRX("load anchors"); 1041 1042 return (0); 1043 1044_error: 1045 if (pf.tdirty) /* cleanup kernel leftover */ 1046 pfr_ina_begin(&trs, NULL, NULL, 0); 1047 exit(1); 1048 1049#undef ERR 1050#undef ERRX 1051} 1052 1053int 1054pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) 1055{ 1056 struct pfioc_limit pl; 1057 int i; 1058 1059 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1060 return (0); 1061 1062 memset(&pl, 0, sizeof(pl)); 1063 for (i = 0; pf_limits[i].name; i++) { 1064 if (strcasecmp(opt, pf_limits[i].name) == 0) { 1065 pl.index = i; 1066 pl.limit = limit; 1067 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1068 if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { 1069 if (errno == EBUSY) { 1070 warnx("Current pool " 1071 "size exceeds requested " 1072 "hard limit"); 1073 return (1); 1074 } else 1075 err(1, "DIOCSETLIMIT"); 1076 } 1077 } 1078 break; 1079 } 1080 } 1081 if (pf_limits[i].name == NULL) { 1082 warnx("Bad pool name."); 1083 return (1); 1084 } 1085 1086 if (pf->opts & PF_OPT_VERBOSE) 1087 printf("set limit %s %d\n", opt, limit); 1088 1089 return (0); 1090} 1091 1092int 1093pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) 1094{ 1095 struct pfioc_tm pt; 1096 int i; 1097 1098 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1099 return (0); 1100 1101 memset(&pt, 0, sizeof(pt)); 1102 for (i = 0; pf_timeouts[i].name; i++) { 1103 if (strcasecmp(opt, pf_timeouts[i].name) == 0) { 1104 pt.timeout = pf_timeouts[i].timeout; 1105 break; 1106 } 1107 } 1108 1109 if (pf_timeouts[i].name == NULL) { 1110 warnx("Bad timeout name."); 1111 return (1); 1112 } 1113 1114 pt.seconds = seconds; 1115 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1116 if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) 1117 err(1, "DIOCSETTIMEOUT"); 1118 } 1119 1120 if (pf->opts & PF_OPT_VERBOSE && ! quiet) 1121 printf("set timeout %s %d\n", opt, seconds); 1122 1123 return (0); 1124} 1125 1126int 1127pfctl_set_optimization(struct pfctl *pf, const char *opt) 1128{ 1129 const struct pf_hint *hint; 1130 int i, r; 1131 1132 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1133 return (0); 1134 1135 for (i = 0; pf_hints[i].name; i++) 1136 if (strcasecmp(opt, pf_hints[i].name) == 0) 1137 break; 1138 1139 hint = pf_hints[i].hint; 1140 if (hint == NULL) { 1141 warnx("Bad hint name."); 1142 return (1); 1143 } 1144 1145 for (i = 0; hint[i].name; i++) 1146 if ((r = pfctl_set_timeout(pf, hint[i].name, 1147 hint[i].timeout, 1))) 1148 return (r); 1149 1150 if (pf->opts & PF_OPT_VERBOSE) 1151 printf("set optimization %s\n", opt); 1152 1153 return (0); 1154} 1155 1156int 1157pfctl_set_logif(struct pfctl *pf, char *ifname) 1158{ 1159 struct pfioc_if pi; 1160 1161 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1162 return (0); 1163 1164 memset(&pi, 0, sizeof(pi)); 1165 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1166 if (!strcmp(ifname, "none")) 1167 bzero(pi.ifname, sizeof(pi.ifname)); 1168 else { 1169 if (strlcpy(pi.ifname, ifname, 1170 sizeof(pi.ifname)) >= sizeof(pi.ifname)) 1171 errx(1, "pfctl_set_logif: strlcpy"); 1172 } 1173 if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) 1174 err(1, "DIOCSETSTATUSIF"); 1175 } 1176 1177 if (pf->opts & PF_OPT_VERBOSE) 1178 printf("set loginterface %s\n", ifname); 1179 1180 return (0); 1181} 1182 1183int 1184pfctl_debug(int dev, u_int32_t level, int opts) 1185{ 1186 if (ioctl(dev, DIOCSETDEBUG, &level)) 1187 err(1, "DIOCSETDEBUG"); 1188 if ((opts & PF_OPT_QUIET) == 0) { 1189 fprintf(stderr, "debug level set to '"); 1190 switch (level) { 1191 case PF_DEBUG_NONE: 1192 fprintf(stderr, "none"); 1193 break; 1194 case PF_DEBUG_URGENT: 1195 fprintf(stderr, "urgent"); 1196 break; 1197 case PF_DEBUG_MISC: 1198 fprintf(stderr, "misc"); 1199 break; 1200 case PF_DEBUG_NOISY: 1201 fprintf(stderr, "loud"); 1202 break; 1203 default: 1204 fprintf(stderr, "<invalid>"); 1205 break; 1206 } 1207 fprintf(stderr, "'\n"); 1208 } 1209 return (0); 1210} 1211 1212int 1213pfctl_clear_rule_counters(int dev, int opts) 1214{ 1215 if (ioctl(dev, DIOCCLRRULECTRS)) 1216 err(1, "DIOCCLRRULECTRS"); 1217 if ((opts & PF_OPT_QUIET) == 0) 1218 fprintf(stderr, "pf: rule counters cleared\n"); 1219 return (0); 1220} 1221 1222int 1223pfctl_test_altqsupport(int dev, int opts) 1224{
| 655 pr.rule.evaluations, pr.rule.packets, 656 pr.rule.bytes); 657 } 658 break; 659 default: 660 print_rule(&pr.rule, rule_numbers); 661 pfctl_print_rule_counters(&pr.rule, opts); 662 } 663 pfctl_clear_pool(&pr.rule.rpool); 664 } 665 return (0); 666} 667 668int 669pfctl_show_nat(int dev, int opts, char *anchorname, char *rulesetname) 670{ 671 struct pfioc_rule pr; 672 u_int32_t mnr, nr; 673 static int nattype[3] = { PF_NAT, PF_RDR, PF_BINAT }; 674 int i; 675 676 if (*anchorname && !*rulesetname) { 677 struct pfioc_ruleset pr; 678 int r; 679 680 memset(&pr, 0, sizeof(pr)); 681 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 682 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 683 if (errno == EINVAL) 684 fprintf(stderr, "No rulesets in anchor '%s'.\n", 685 anchorname); 686 else 687 err(1, "DIOCGETRULESETS"); 688 return (-1); 689 } 690 mnr = pr.nr; 691 for (nr = 0; nr < mnr; ++nr) { 692 pr.nr = nr; 693 if (ioctl(dev, DIOCGETRULESET, &pr)) 694 err(1, "DIOCGETRULESET"); 695 r = pfctl_show_nat(dev, opts, anchorname, pr.name); 696 if (r) 697 return (r); 698 } 699 return (0); 700 } 701 702 memset(&pr, 0, sizeof(pr)); 703 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 704 memcpy(pr.ruleset, rulesetname, sizeof(pr.ruleset)); 705 for (i = 0; i < 3; i++) { 706 pr.rule.action = nattype[i]; 707 if (ioctl(dev, DIOCGETRULES, &pr)) { 708 warn("DIOCGETRULES"); 709 return (-1); 710 } 711 mnr = pr.nr; 712 for (nr = 0; nr < mnr; ++nr) { 713 pr.nr = nr; 714 if (ioctl(dev, DIOCGETRULE, &pr)) { 715 warn("DIOCGETRULE"); 716 return (-1); 717 } 718 if (pfctl_get_pool(dev, &pr.rule.rpool, nr, 719 pr.ticket, nattype[i], anchorname, 720 rulesetname) != 0) 721 return (-1); 722 print_rule(&pr.rule, opts & PF_OPT_VERBOSE2); 723 pfctl_print_rule_counters(&pr.rule, opts); 724 pfctl_clear_pool(&pr.rule.rpool); 725 } 726 } 727 return (0); 728} 729 730int 731pfctl_show_states(int dev, u_int8_t proto, int opts) 732{ 733 struct pfioc_states ps; 734 struct pf_state *p; 735 char *inbuf = NULL; 736 unsigned len = 0; 737 int i; 738 739 memset(&ps, 0, sizeof(ps)); 740 for (;;) { 741 ps.ps_len = len; 742 if (len) { 743 ps.ps_buf = inbuf = realloc(inbuf, len); 744 if (inbuf == NULL) 745 err(1, "realloc"); 746 } 747 if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { 748 warn("DIOCGETSTATES"); 749 return (-1); 750 } 751 if (ps.ps_len + sizeof(struct pfioc_states) < len) 752 break; 753 if (len == 0 && ps.ps_len == 0) 754 return (0); 755 if (len == 0 && ps.ps_len != 0) 756 len = ps.ps_len; 757 if (ps.ps_len == 0) 758 return (0); /* no states */ 759 len *= 2; 760 } 761 p = ps.ps_states; 762 for (i = 0; i < ps.ps_len; i += sizeof(*p)) { 763 if (!proto || (p->proto == proto)) 764 print_state(p, opts); 765 p++; 766 } 767 return (0); 768} 769 770int 771pfctl_show_status(int dev) 772{ 773 struct pf_status status; 774 775 if (ioctl(dev, DIOCGETSTATUS, &status)) { 776 warn("DIOCGETSTATUS"); 777 return (-1); 778 } 779 print_status(&status); 780 return (0); 781} 782 783int 784pfctl_show_timeouts(int dev) 785{ 786 struct pfioc_tm pt; 787 int i; 788 789 memset(&pt, 0, sizeof(pt)); 790 for (i = 0; pf_timeouts[i].name; i++) { 791 pt.timeout = pf_timeouts[i].timeout; 792 if (ioctl(dev, DIOCGETTIMEOUT, &pt)) 793 err(1, "DIOCGETTIMEOUT"); 794 printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); 795 if (i >= PFTM_ADAPTIVE_START && i <= PFTM_ADAPTIVE_END) 796 printf(" states"); 797 else 798 printf("s"); 799 printf("\n"); 800 } 801 return (0); 802 803} 804 805int 806pfctl_show_limits(int dev) 807{ 808 struct pfioc_limit pl; 809 int i; 810 811 memset(&pl, 0, sizeof(pl)); 812 for (i = 0; pf_limits[i].name; i++) { 813 pl.index = i; 814 if (ioctl(dev, DIOCGETLIMIT, &pl)) 815 err(1, "DIOCGETLIMIT"); 816 printf("%-10s ", pf_limits[i].name); 817 if (pl.limit == UINT_MAX) 818 printf("unlimited\n"); 819 else 820 printf("hard limit %6u\n", pl.limit); 821 } 822 return (0); 823} 824 825/* callbacks for rule/nat/rdr/addr */ 826int 827pfctl_add_pool(struct pfctl *pf, struct pf_pool *p, sa_family_t af) 828{ 829 struct pf_pooladdr *pa; 830 831 if ((pf->opts & PF_OPT_NOACTION) == 0) { 832 if (ioctl(pf->dev, DIOCBEGINADDRS, &pf->paddr)) 833 err(1, "DIOCBEGINADDRS"); 834 } 835 836 pf->paddr.af = af; 837 TAILQ_FOREACH(pa, &p->list, entries) { 838 memcpy(&pf->paddr.addr, pa, sizeof(struct pf_pooladdr)); 839 if ((pf->opts & PF_OPT_NOACTION) == 0) { 840 if (ioctl(pf->dev, DIOCADDADDR, &pf->paddr)) 841 err(1, "DIOCADDADDR"); 842 } 843 } 844 return (0); 845} 846 847int 848pfctl_add_rule(struct pfctl *pf, struct pf_rule *r) 849{ 850 u_int8_t rs_num; 851 852 switch (r->action) { 853 case PF_SCRUB: 854 if ((loadopt & PFCTL_FLAG_FILTER) == 0) 855 return (0); 856 rs_num = PF_RULESET_SCRUB; 857 break; 858 case PF_DROP: 859 case PF_PASS: 860 if ((loadopt & PFCTL_FLAG_FILTER) == 0) 861 return (0); 862 rs_num = PF_RULESET_FILTER; 863 break; 864 case PF_NAT: 865 case PF_NONAT: 866 if ((loadopt & PFCTL_FLAG_NAT) == 0) 867 return (0); 868 rs_num = PF_RULESET_NAT; 869 break; 870 case PF_RDR: 871 case PF_NORDR: 872 if ((loadopt & PFCTL_FLAG_NAT) == 0) 873 return (0); 874 rs_num = PF_RULESET_RDR; 875 break; 876 case PF_BINAT: 877 case PF_NOBINAT: 878 if ((loadopt & PFCTL_FLAG_NAT) == 0) 879 return (0); 880 rs_num = PF_RULESET_BINAT; 881 break; 882 default: 883 errx(1, "Invalid rule type"); 884 break; 885 } 886 887 if ((pf->opts & PF_OPT_NOACTION) == 0) { 888 if (pfctl_add_pool(pf, &r->rpool, r->af)) 889 return (1); 890 memcpy(&pf->prule[rs_num]->rule, r, 891 sizeof(pf->prule[rs_num]->rule)); 892 pf->prule[rs_num]->pool_ticket = pf->paddr.ticket; 893 if (ioctl(pf->dev, DIOCADDRULE, pf->prule[rs_num])) 894 err(1, "DIOCADDRULE"); 895 } 896 if (pf->opts & PF_OPT_VERBOSE) 897 print_rule(r, pf->opts & PF_OPT_VERBOSE2); 898 pfctl_clear_pool(&r->rpool); 899 return (0); 900} 901 902int 903pfctl_add_altq(struct pfctl *pf, struct pf_altq *a) 904{ 905 if (altqsupport && 906 (loadopt & PFCTL_FLAG_ALTQ) != 0) { 907 memcpy(&pf->paltq->altq, a, sizeof(struct pf_altq)); 908 if ((pf->opts & PF_OPT_NOACTION) == 0) { 909 if (ioctl(pf->dev, DIOCADDALTQ, pf->paltq)) { 910 if (errno == ENXIO) 911 errx(1, "qtype not configured"); 912 else if (errno == ENODEV) 913 errx(1, "%s: driver does not support " 914 "altq", a->ifname); 915 else 916 err(1, "DIOCADDALTQ"); 917 } 918 } 919 pfaltq_store(&pf->paltq->altq); 920 } 921 return (0); 922} 923 924int 925pfctl_rules(int dev, char *filename, int opts, char *anchorname, 926 char *rulesetname) 927{ 928#define ERR(x) do { warn(x); goto _error; } while(0) 929#define ERRX(x) do { warnx(x); goto _error; } while(0) 930 931 FILE *fin; 932 struct pfioc_rule pr[PF_RULESET_MAX]; 933 struct pfioc_altq pa; 934 struct pfctl pf; 935 struct pfr_table trs; 936 int i; 937 938 memset(&pa, 0, sizeof(pa)); 939 memset(&pf, 0, sizeof(pf)); 940 memset(&trs, 0, sizeof(trs)); 941 for (i = 0; i < PF_RULESET_MAX; i++) { 942 memset(&pr[i], 0, sizeof(pr[i])); 943 memcpy(pr[i].anchor, anchorname, sizeof(pr[i].anchor)); 944 memcpy(pr[i].ruleset, rulesetname, sizeof(pr[i].ruleset)); 945 } 946 if (strlcpy(trs.pfrt_anchor, anchorname, 947 sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor) || 948 strlcpy(trs.pfrt_ruleset, rulesetname, 949 sizeof(trs.pfrt_ruleset)) >= sizeof(trs.pfrt_ruleset)) 950 ERRX("pfctl_rules: strlcpy"); 951 if (strcmp(filename, "-") == 0) { 952 fin = stdin; 953 infile = "stdin"; 954 } else { 955 if ((fin = fopen(filename, "r")) == NULL) { 956 warn("%s", filename); 957 return (1); 958 } 959 infile = filename; 960 } 961 if ((opts & PF_OPT_NOACTION) == 0) { 962 if ((loadopt & PFCTL_FLAG_NAT) != 0) { 963 pr[PF_RULESET_NAT].rule.action = PF_NAT; 964 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_NAT])) 965 ERR("DIOCBEGINRULES"); 966 pr[PF_RULESET_RDR].rule.action = PF_RDR; 967 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_RDR])) 968 ERR("DIOCBEGINRULES"); 969 pr[PF_RULESET_BINAT].rule.action = PF_BINAT; 970 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_BINAT])) 971 ERR("DIOCBEGINRULES"); 972 } 973 if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) && 974 ioctl(dev, DIOCBEGINALTQS, &pa.ticket)) { 975 ERR("DIOCBEGINALTQS"); 976 } 977 if ((loadopt & PFCTL_FLAG_FILTER) != 0) { 978 pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB; 979 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_SCRUB])) 980 ERR("DIOCBEGINRULES"); 981 pr[PF_RULESET_FILTER].rule.action = PF_PASS; 982 if (ioctl(dev, DIOCBEGINRULES, &pr[PF_RULESET_FILTER])) 983 ERR("DIOCBEGINRULES"); 984 } 985 if (loadopt & PFCTL_FLAG_TABLE) { 986 if (pfr_ina_begin(&trs, &pf.tticket, NULL, 0) != 0) 987 ERR("begin table"); 988 } 989 } 990 /* fill in callback data */ 991 pf.dev = dev; 992 pf.opts = opts; 993 pf.loadopt = loadopt; 994 pf.paltq = &pa; 995 for (i = 0; i < PF_RULESET_MAX; i++) { 996 pf.prule[i] = &pr[i]; 997 } 998 pf.rule_nr = 0; 999 pf.anchor = anchorname; 1000 pf.ruleset = rulesetname; 1001 if (parse_rules(fin, &pf) < 0) { 1002 if ((opts & PF_OPT_NOACTION) == 0) 1003 ERRX("Syntax error in config file: " 1004 "pf rules not loaded"); 1005 else 1006 goto _error; 1007 } 1008 if ((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) 1009 if (check_commit_altq(dev, opts) != 0) 1010 ERRX("errors in altq config"); 1011 if ((opts & PF_OPT_NOACTION) == 0) { 1012 if ((loadopt & PFCTL_FLAG_NAT) != 0) { 1013 pr[PF_RULESET_NAT].rule.action = PF_NAT; 1014 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_NAT]) && 1015 (errno != EINVAL || pf.rule_nr)) 1016 ERR("DIOCCOMMITRULES NAT"); 1017 pr[PF_RULESET_RDR].rule.action = PF_RDR; 1018 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_RDR]) && 1019 (errno != EINVAL || pf.rule_nr)) 1020 ERR("DIOCCOMMITRULES RDR"); 1021 pr[PF_RULESET_BINAT].rule.action = PF_BINAT; 1022 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_BINAT]) && 1023 (errno != EINVAL || pf.rule_nr)) 1024 ERR("DIOCCOMMITRULES BINAT"); 1025 } 1026 if (((altqsupport && (loadopt & PFCTL_FLAG_ALTQ) != 0)) && 1027 ioctl(dev, DIOCCOMMITALTQS, &pa.ticket)) 1028 ERR("DIOCCOMMITALTQS"); 1029 if ((loadopt & PFCTL_FLAG_FILTER) != 0) { 1030 pr[PF_RULESET_SCRUB].rule.action = PF_SCRUB; 1031 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_SCRUB]) && 1032 (errno != EINVAL || pf.rule_nr)) 1033 ERR("DIOCCOMMITRULES SCRUB"); 1034 pr[PF_RULESET_FILTER].rule.action = PF_PASS; 1035 if (ioctl(dev, DIOCCOMMITRULES, &pr[PF_RULESET_FILTER]) && 1036 (errno != EINVAL || pf.rule_nr)) 1037 ERR("DIOCCOMMITRULES FILTER"); 1038 } 1039 if (loadopt & PFCTL_FLAG_TABLE) { 1040 if (pfr_ina_commit(&trs, pf.tticket, NULL, NULL, 0)) 1041 ERR("commit table"); 1042 pf.tdirty = 0; 1043 } 1044 } 1045 if (fin != stdin) 1046 fclose(fin); 1047 1048 /* process "load anchor" directives */ 1049 if (!anchorname[0] && !rulesetname[0]) 1050 if (pfctl_load_anchors(dev, opts) == -1) 1051 ERRX("load anchors"); 1052 1053 return (0); 1054 1055_error: 1056 if (pf.tdirty) /* cleanup kernel leftover */ 1057 pfr_ina_begin(&trs, NULL, NULL, 0); 1058 exit(1); 1059 1060#undef ERR 1061#undef ERRX 1062} 1063 1064int 1065pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) 1066{ 1067 struct pfioc_limit pl; 1068 int i; 1069 1070 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1071 return (0); 1072 1073 memset(&pl, 0, sizeof(pl)); 1074 for (i = 0; pf_limits[i].name; i++) { 1075 if (strcasecmp(opt, pf_limits[i].name) == 0) { 1076 pl.index = i; 1077 pl.limit = limit; 1078 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1079 if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { 1080 if (errno == EBUSY) { 1081 warnx("Current pool " 1082 "size exceeds requested " 1083 "hard limit"); 1084 return (1); 1085 } else 1086 err(1, "DIOCSETLIMIT"); 1087 } 1088 } 1089 break; 1090 } 1091 } 1092 if (pf_limits[i].name == NULL) { 1093 warnx("Bad pool name."); 1094 return (1); 1095 } 1096 1097 if (pf->opts & PF_OPT_VERBOSE) 1098 printf("set limit %s %d\n", opt, limit); 1099 1100 return (0); 1101} 1102 1103int 1104pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) 1105{ 1106 struct pfioc_tm pt; 1107 int i; 1108 1109 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1110 return (0); 1111 1112 memset(&pt, 0, sizeof(pt)); 1113 for (i = 0; pf_timeouts[i].name; i++) { 1114 if (strcasecmp(opt, pf_timeouts[i].name) == 0) { 1115 pt.timeout = pf_timeouts[i].timeout; 1116 break; 1117 } 1118 } 1119 1120 if (pf_timeouts[i].name == NULL) { 1121 warnx("Bad timeout name."); 1122 return (1); 1123 } 1124 1125 pt.seconds = seconds; 1126 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1127 if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) 1128 err(1, "DIOCSETTIMEOUT"); 1129 } 1130 1131 if (pf->opts & PF_OPT_VERBOSE && ! quiet) 1132 printf("set timeout %s %d\n", opt, seconds); 1133 1134 return (0); 1135} 1136 1137int 1138pfctl_set_optimization(struct pfctl *pf, const char *opt) 1139{ 1140 const struct pf_hint *hint; 1141 int i, r; 1142 1143 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1144 return (0); 1145 1146 for (i = 0; pf_hints[i].name; i++) 1147 if (strcasecmp(opt, pf_hints[i].name) == 0) 1148 break; 1149 1150 hint = pf_hints[i].hint; 1151 if (hint == NULL) { 1152 warnx("Bad hint name."); 1153 return (1); 1154 } 1155 1156 for (i = 0; hint[i].name; i++) 1157 if ((r = pfctl_set_timeout(pf, hint[i].name, 1158 hint[i].timeout, 1))) 1159 return (r); 1160 1161 if (pf->opts & PF_OPT_VERBOSE) 1162 printf("set optimization %s\n", opt); 1163 1164 return (0); 1165} 1166 1167int 1168pfctl_set_logif(struct pfctl *pf, char *ifname) 1169{ 1170 struct pfioc_if pi; 1171 1172 if ((loadopt & PFCTL_FLAG_OPTION) == 0) 1173 return (0); 1174 1175 memset(&pi, 0, sizeof(pi)); 1176 if ((pf->opts & PF_OPT_NOACTION) == 0) { 1177 if (!strcmp(ifname, "none")) 1178 bzero(pi.ifname, sizeof(pi.ifname)); 1179 else { 1180 if (strlcpy(pi.ifname, ifname, 1181 sizeof(pi.ifname)) >= sizeof(pi.ifname)) 1182 errx(1, "pfctl_set_logif: strlcpy"); 1183 } 1184 if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) 1185 err(1, "DIOCSETSTATUSIF"); 1186 } 1187 1188 if (pf->opts & PF_OPT_VERBOSE) 1189 printf("set loginterface %s\n", ifname); 1190 1191 return (0); 1192} 1193 1194int 1195pfctl_debug(int dev, u_int32_t level, int opts) 1196{ 1197 if (ioctl(dev, DIOCSETDEBUG, &level)) 1198 err(1, "DIOCSETDEBUG"); 1199 if ((opts & PF_OPT_QUIET) == 0) { 1200 fprintf(stderr, "debug level set to '"); 1201 switch (level) { 1202 case PF_DEBUG_NONE: 1203 fprintf(stderr, "none"); 1204 break; 1205 case PF_DEBUG_URGENT: 1206 fprintf(stderr, "urgent"); 1207 break; 1208 case PF_DEBUG_MISC: 1209 fprintf(stderr, "misc"); 1210 break; 1211 case PF_DEBUG_NOISY: 1212 fprintf(stderr, "loud"); 1213 break; 1214 default: 1215 fprintf(stderr, "<invalid>"); 1216 break; 1217 } 1218 fprintf(stderr, "'\n"); 1219 } 1220 return (0); 1221} 1222 1223int 1224pfctl_clear_rule_counters(int dev, int opts) 1225{ 1226 if (ioctl(dev, DIOCCLRRULECTRS)) 1227 err(1, "DIOCCLRRULECTRS"); 1228 if ((opts & PF_OPT_QUIET) == 0) 1229 fprintf(stderr, "pf: rule counters cleared\n"); 1230 return (0); 1231} 1232 1233int 1234pfctl_test_altqsupport(int dev, int opts) 1235{
|
| 1236#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ) 1237 return (0); 1238#else
|
1225 struct pfioc_altq pa; 1226 1227 if (ioctl(dev, DIOCGETALTQS, &pa)) { 1228 if (errno == ENODEV) { 1229 if (!(opts & PF_OPT_QUIET)) 1230 fprintf(stderr, "No ALTQ support in kernel\n" 1231 "ALTQ related functions disabled\n"); 1232 return (0); 1233 } else 1234 err(1, "DIOCGETALTQS"); 1235 } 1236 return (1);
| 1239 struct pfioc_altq pa; 1240 1241 if (ioctl(dev, DIOCGETALTQS, &pa)) { 1242 if (errno == ENODEV) { 1243 if (!(opts & PF_OPT_QUIET)) 1244 fprintf(stderr, "No ALTQ support in kernel\n" 1245 "ALTQ related functions disabled\n"); 1246 return (0); 1247 } else 1248 err(1, "DIOCGETALTQS"); 1249 } 1250 return (1);
|
| 1251#endif
|
1237} 1238 1239int 1240pfctl_show_anchors(int dev, int opts, char *anchorname) 1241{ 1242 u_int32_t nr, mnr; 1243 1244 if (!*anchorname) { 1245 struct pfioc_anchor pa; 1246 1247 memset(&pa, 0, sizeof(pa)); 1248 if (ioctl(dev, DIOCGETANCHORS, &pa)) { 1249 warn("DIOCGETANCHORS"); 1250 return (-1); 1251 } 1252 mnr = pa.nr; 1253 if (!(opts & PF_OPT_QUIET)) 1254 printf("%u anchors:\n", mnr); 1255 for (nr = 0; nr < mnr; ++nr) { 1256 pa.nr = nr; 1257 if (ioctl(dev, DIOCGETANCHOR, &pa)) { 1258 warn("DIOCGETANCHOR"); 1259 return (-1); 1260 } 1261 printf(" %s\n", pa.name); 1262 } 1263 } else { 1264 struct pfioc_ruleset pr; 1265 1266 memset(&pr, 0, sizeof(pr)); 1267 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 1268 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 1269 if (errno == EINVAL) 1270 fprintf(stderr, "No rulesets in anchor '%s'.\n", 1271 anchorname); 1272 else 1273 err(1, "DIOCGETRULESETS"); 1274 return (-1); 1275 } 1276 mnr = pr.nr; 1277 if (!(opts & PF_OPT_QUIET)) 1278 printf("%u rulesets in anchor %s:\n", mnr, anchorname); 1279 for (nr = 0; nr < mnr; ++nr) { 1280 pr.nr = nr; 1281 if (ioctl(dev, DIOCGETRULESET, &pr)) 1282 err(1, "DIOCGETRULESET"); 1283 printf(" %s:%s\n", pr.anchor, pr.name); 1284 } 1285 } 1286 return (0); 1287} 1288 1289const char * 1290pfctl_lookup_option(char *cmd, const char **list) 1291{ 1292 if (cmd != NULL && *cmd) 1293 for (; *list; list++) 1294 if (!strncmp(cmd, *list, strlen(cmd))) 1295 return (*list); 1296 return (NULL); 1297} 1298 1299int 1300main(int argc, char *argv[]) 1301{ 1302 int error = 0; 1303 int ch; 1304 int mode = O_RDONLY; 1305 int opts = 0; 1306 char anchorname[PF_ANCHOR_NAME_SIZE]; 1307 char rulesetname[PF_RULESET_NAME_SIZE]; 1308 1309 if (argc < 2) 1310 usage(); 1311 1312 while ((ch = getopt(argc, argv, "a:AdD:eqf:F:ghk:nNOrRs:t:T:vx:z")) != 1313 -1) { 1314 switch (ch) { 1315 case 'a': 1316 anchoropt = optarg; 1317 break; 1318 case 'd': 1319 opts |= PF_OPT_DISABLE; 1320 mode = O_RDWR; 1321 break; 1322 case 'D': 1323 if (pfctl_cmdline_symset(optarg) < 0) 1324 warnx("could not parse macro definition %s", 1325 optarg); 1326 break; 1327 case 'e': 1328 opts |= PF_OPT_ENABLE; 1329 mode = O_RDWR; 1330 break; 1331 case 'q': 1332 opts |= PF_OPT_QUIET; 1333 break; 1334 case 'F': 1335 clearopt = pfctl_lookup_option(optarg, clearopt_list); 1336 if (clearopt == NULL) { 1337 warnx("Unknown flush modifier '%s'", optarg); 1338 usage(); 1339 } 1340 mode = O_RDWR; 1341 break; 1342 case 'k': 1343 if (state_killers >= 2) { 1344 warnx("can only specify -k twice"); 1345 usage(); 1346 /* NOTREACHED */ 1347 } 1348 state_kill[state_killers++] = optarg; 1349 mode = O_RDWR; 1350 break; 1351 case 'n': 1352 opts |= PF_OPT_NOACTION; 1353 break; 1354 case 'N': 1355 loadopt |= PFCTL_FLAG_NAT; 1356 break; 1357 case 'r': 1358 opts |= PF_OPT_USEDNS; 1359 break; 1360 case 'f': 1361 rulesopt = optarg; 1362 mode = O_RDWR; 1363 break; 1364 case 'g': 1365 opts |= PF_OPT_DEBUG; 1366 break; 1367 case 'A': 1368 loadopt |= PFCTL_FLAG_ALTQ; 1369 break; 1370 case 'R': 1371 loadopt |= PFCTL_FLAG_FILTER; 1372 break; 1373 case 'O': 1374 loadopt |= PFCTL_FLAG_OPTION; 1375 break; 1376 case 's': 1377 showopt = pfctl_lookup_option(optarg, showopt_list); 1378 if (showopt == NULL) { 1379 warnx("Unknown show modifier '%s'", optarg); 1380 usage(); 1381 } 1382 break; 1383 case 't': 1384 tableopt = optarg; 1385 break; 1386 case 'T': 1387 tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); 1388 if (tblcmdopt == NULL) { 1389 warnx("Unknown table command '%s'", optarg); 1390 usage(); 1391 } 1392 break; 1393 case 'v': 1394 if (opts & PF_OPT_VERBOSE) 1395 opts |= PF_OPT_VERBOSE2; 1396 opts |= PF_OPT_VERBOSE; 1397 break; 1398 case 'x': 1399 debugopt = pfctl_lookup_option(optarg, debugopt_list); 1400 if (debugopt == NULL) { 1401 warnx("Unknown debug level '%s'", optarg); 1402 usage(); 1403 } 1404 mode = O_RDWR; 1405 break; 1406 case 'z': 1407 opts |= PF_OPT_CLRRULECTRS; 1408 mode = O_RDWR; 1409 break; 1410 case 'h': 1411 /* FALLTHROUGH */ 1412 default: 1413 usage(); 1414 /* NOTREACHED */ 1415 } 1416 } 1417 1418 if (tblcmdopt != NULL) { 1419 argc -= optind; 1420 argv += optind; 1421 ch = *tblcmdopt; 1422 if (ch == 'l') { 1423 loadopt |= PFCTL_FLAG_TABLE; 1424 tblcmdopt = NULL; 1425 } else { 1426 mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY; 1427 if (opts & PF_OPT_NOACTION) { 1428 dev = open("/dev/pf", mode); 1429 if (dev >= 0) 1430 opts |= PF_OPT_DUMMYACTION; 1431 } 1432 } 1433 } else if (argc != optind) { 1434 warnx("unknown command line argument: %s ...", argv[optind]); 1435 usage(); 1436 /* NOTREACHED */ 1437 } 1438 if (loadopt == 0) 1439 loadopt = ~0; 1440 1441 memset(anchorname, 0, sizeof(anchorname)); 1442 memset(rulesetname, 0, sizeof(rulesetname)); 1443 if (anchoropt != NULL) { 1444 char *t; 1445 1446 if ((t = strchr(anchoropt, ':')) == NULL) { 1447 if (strlcpy(anchorname, anchoropt, 1448 sizeof(anchorname)) >= sizeof(anchorname)) 1449 errx(1, "anchor name '%s' too long", 1450 anchoropt); 1451 } else { 1452 char *p; 1453 1454 if ((p = strdup(anchoropt)) == NULL) 1455 err(1, "anchoropt: strdup"); 1456 t = strsep(&p, ":"); 1457 if (*t == '\0' || *p == '\0') 1458 errx(1, "anchor '%s' invalid", anchoropt); 1459 if (strlcpy(anchorname, t, sizeof(anchorname)) >= 1460 sizeof(anchorname)) 1461 errx(1, "anchor name '%s' too long", t); 1462 if (strlcpy(rulesetname, p, sizeof(rulesetname)) >= 1463 sizeof(rulesetname)) 1464 errx(1, "ruleset name '%s' too long", p); 1465 free(t); /* not p */ 1466 } 1467 loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE; 1468 } 1469 1470 if ((opts & PF_OPT_NOACTION) == 0) { 1471 dev = open("/dev/pf", mode); 1472 if (dev == -1) 1473 err(1, "/dev/pf"); 1474 altqsupport = pfctl_test_altqsupport(dev, opts); 1475 } else { 1476 /* turn off options */ 1477 opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); 1478 clearopt = showopt = debugopt = NULL;
| 1252} 1253 1254int 1255pfctl_show_anchors(int dev, int opts, char *anchorname) 1256{ 1257 u_int32_t nr, mnr; 1258 1259 if (!*anchorname) { 1260 struct pfioc_anchor pa; 1261 1262 memset(&pa, 0, sizeof(pa)); 1263 if (ioctl(dev, DIOCGETANCHORS, &pa)) { 1264 warn("DIOCGETANCHORS"); 1265 return (-1); 1266 } 1267 mnr = pa.nr; 1268 if (!(opts & PF_OPT_QUIET)) 1269 printf("%u anchors:\n", mnr); 1270 for (nr = 0; nr < mnr; ++nr) { 1271 pa.nr = nr; 1272 if (ioctl(dev, DIOCGETANCHOR, &pa)) { 1273 warn("DIOCGETANCHOR"); 1274 return (-1); 1275 } 1276 printf(" %s\n", pa.name); 1277 } 1278 } else { 1279 struct pfioc_ruleset pr; 1280 1281 memset(&pr, 0, sizeof(pr)); 1282 memcpy(pr.anchor, anchorname, sizeof(pr.anchor)); 1283 if (ioctl(dev, DIOCGETRULESETS, &pr)) { 1284 if (errno == EINVAL) 1285 fprintf(stderr, "No rulesets in anchor '%s'.\n", 1286 anchorname); 1287 else 1288 err(1, "DIOCGETRULESETS"); 1289 return (-1); 1290 } 1291 mnr = pr.nr; 1292 if (!(opts & PF_OPT_QUIET)) 1293 printf("%u rulesets in anchor %s:\n", mnr, anchorname); 1294 for (nr = 0; nr < mnr; ++nr) { 1295 pr.nr = nr; 1296 if (ioctl(dev, DIOCGETRULESET, &pr)) 1297 err(1, "DIOCGETRULESET"); 1298 printf(" %s:%s\n", pr.anchor, pr.name); 1299 } 1300 } 1301 return (0); 1302} 1303 1304const char * 1305pfctl_lookup_option(char *cmd, const char **list) 1306{ 1307 if (cmd != NULL && *cmd) 1308 for (; *list; list++) 1309 if (!strncmp(cmd, *list, strlen(cmd))) 1310 return (*list); 1311 return (NULL); 1312} 1313 1314int 1315main(int argc, char *argv[]) 1316{ 1317 int error = 0; 1318 int ch; 1319 int mode = O_RDONLY; 1320 int opts = 0; 1321 char anchorname[PF_ANCHOR_NAME_SIZE]; 1322 char rulesetname[PF_RULESET_NAME_SIZE]; 1323 1324 if (argc < 2) 1325 usage(); 1326 1327 while ((ch = getopt(argc, argv, "a:AdD:eqf:F:ghk:nNOrRs:t:T:vx:z")) != 1328 -1) { 1329 switch (ch) { 1330 case 'a': 1331 anchoropt = optarg; 1332 break; 1333 case 'd': 1334 opts |= PF_OPT_DISABLE; 1335 mode = O_RDWR; 1336 break; 1337 case 'D': 1338 if (pfctl_cmdline_symset(optarg) < 0) 1339 warnx("could not parse macro definition %s", 1340 optarg); 1341 break; 1342 case 'e': 1343 opts |= PF_OPT_ENABLE; 1344 mode = O_RDWR; 1345 break; 1346 case 'q': 1347 opts |= PF_OPT_QUIET; 1348 break; 1349 case 'F': 1350 clearopt = pfctl_lookup_option(optarg, clearopt_list); 1351 if (clearopt == NULL) { 1352 warnx("Unknown flush modifier '%s'", optarg); 1353 usage(); 1354 } 1355 mode = O_RDWR; 1356 break; 1357 case 'k': 1358 if (state_killers >= 2) { 1359 warnx("can only specify -k twice"); 1360 usage(); 1361 /* NOTREACHED */ 1362 } 1363 state_kill[state_killers++] = optarg; 1364 mode = O_RDWR; 1365 break; 1366 case 'n': 1367 opts |= PF_OPT_NOACTION; 1368 break; 1369 case 'N': 1370 loadopt |= PFCTL_FLAG_NAT; 1371 break; 1372 case 'r': 1373 opts |= PF_OPT_USEDNS; 1374 break; 1375 case 'f': 1376 rulesopt = optarg; 1377 mode = O_RDWR; 1378 break; 1379 case 'g': 1380 opts |= PF_OPT_DEBUG; 1381 break; 1382 case 'A': 1383 loadopt |= PFCTL_FLAG_ALTQ; 1384 break; 1385 case 'R': 1386 loadopt |= PFCTL_FLAG_FILTER; 1387 break; 1388 case 'O': 1389 loadopt |= PFCTL_FLAG_OPTION; 1390 break; 1391 case 's': 1392 showopt = pfctl_lookup_option(optarg, showopt_list); 1393 if (showopt == NULL) { 1394 warnx("Unknown show modifier '%s'", optarg); 1395 usage(); 1396 } 1397 break; 1398 case 't': 1399 tableopt = optarg; 1400 break; 1401 case 'T': 1402 tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); 1403 if (tblcmdopt == NULL) { 1404 warnx("Unknown table command '%s'", optarg); 1405 usage(); 1406 } 1407 break; 1408 case 'v': 1409 if (opts & PF_OPT_VERBOSE) 1410 opts |= PF_OPT_VERBOSE2; 1411 opts |= PF_OPT_VERBOSE; 1412 break; 1413 case 'x': 1414 debugopt = pfctl_lookup_option(optarg, debugopt_list); 1415 if (debugopt == NULL) { 1416 warnx("Unknown debug level '%s'", optarg); 1417 usage(); 1418 } 1419 mode = O_RDWR; 1420 break; 1421 case 'z': 1422 opts |= PF_OPT_CLRRULECTRS; 1423 mode = O_RDWR; 1424 break; 1425 case 'h': 1426 /* FALLTHROUGH */ 1427 default: 1428 usage(); 1429 /* NOTREACHED */ 1430 } 1431 } 1432 1433 if (tblcmdopt != NULL) { 1434 argc -= optind; 1435 argv += optind; 1436 ch = *tblcmdopt; 1437 if (ch == 'l') { 1438 loadopt |= PFCTL_FLAG_TABLE; 1439 tblcmdopt = NULL; 1440 } else { 1441 mode = strchr("acdfkrz", ch) ? O_RDWR : O_RDONLY; 1442 if (opts & PF_OPT_NOACTION) { 1443 dev = open("/dev/pf", mode); 1444 if (dev >= 0) 1445 opts |= PF_OPT_DUMMYACTION; 1446 } 1447 } 1448 } else if (argc != optind) { 1449 warnx("unknown command line argument: %s ...", argv[optind]); 1450 usage(); 1451 /* NOTREACHED */ 1452 } 1453 if (loadopt == 0) 1454 loadopt = ~0; 1455 1456 memset(anchorname, 0, sizeof(anchorname)); 1457 memset(rulesetname, 0, sizeof(rulesetname)); 1458 if (anchoropt != NULL) { 1459 char *t; 1460 1461 if ((t = strchr(anchoropt, ':')) == NULL) { 1462 if (strlcpy(anchorname, anchoropt, 1463 sizeof(anchorname)) >= sizeof(anchorname)) 1464 errx(1, "anchor name '%s' too long", 1465 anchoropt); 1466 } else { 1467 char *p; 1468 1469 if ((p = strdup(anchoropt)) == NULL) 1470 err(1, "anchoropt: strdup"); 1471 t = strsep(&p, ":"); 1472 if (*t == '\0' || *p == '\0') 1473 errx(1, "anchor '%s' invalid", anchoropt); 1474 if (strlcpy(anchorname, t, sizeof(anchorname)) >= 1475 sizeof(anchorname)) 1476 errx(1, "anchor name '%s' too long", t); 1477 if (strlcpy(rulesetname, p, sizeof(rulesetname)) >= 1478 sizeof(rulesetname)) 1479 errx(1, "ruleset name '%s' too long", p); 1480 free(t); /* not p */ 1481 } 1482 loadopt &= PFCTL_FLAG_FILTER|PFCTL_FLAG_NAT|PFCTL_FLAG_TABLE; 1483 } 1484 1485 if ((opts & PF_OPT_NOACTION) == 0) { 1486 dev = open("/dev/pf", mode); 1487 if (dev == -1) 1488 err(1, "/dev/pf"); 1489 altqsupport = pfctl_test_altqsupport(dev, opts); 1490 } else { 1491 /* turn off options */ 1492 opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); 1493 clearopt = showopt = debugopt = NULL;
|
| 1494#if defined(__FreeBSD__) && !defined(ENABLE_ALTQ) 1495 altqsupport = 0; 1496#else
|
1479 altqsupport = 1;
| 1497 altqsupport = 1;
|
| 1498#endif
|
1480 } 1481 1482 if (opts & PF_OPT_DISABLE) 1483 if (pfctl_disable(dev, opts)) 1484 error = 1; 1485 1486 if (showopt != NULL) { 1487 switch (*showopt) { 1488 case 'A': 1489 pfctl_show_anchors(dev, opts, anchorname); 1490 break; 1491 case 'r': 1492 pfctl_load_fingerprints(dev, opts); 1493 pfctl_show_rules(dev, opts, 0, anchorname, 1494 rulesetname); 1495 break; 1496 case 'l': 1497 pfctl_load_fingerprints(dev, opts); 1498 pfctl_show_rules(dev, opts, 1, anchorname, 1499 rulesetname); 1500 break; 1501 case 'n': 1502 pfctl_load_fingerprints(dev, opts); 1503 pfctl_show_nat(dev, opts, anchorname, rulesetname); 1504 break; 1505 case 'q': 1506 pfctl_show_altq(dev, opts, opts & PF_OPT_VERBOSE2); 1507 break; 1508 case 's': 1509 pfctl_show_states(dev, 0, opts); 1510 break; 1511 case 'i': 1512 pfctl_show_status(dev); 1513 break; 1514 case 't': 1515 pfctl_show_timeouts(dev); 1516 break; 1517 case 'm': 1518 pfctl_show_limits(dev); 1519 break; 1520 case 'a': 1521 pfctl_load_fingerprints(dev, opts); 1522 1523 pfctl_show_rules(dev, opts, 0, anchorname, 1524 rulesetname); 1525 pfctl_show_nat(dev, opts, anchorname, rulesetname); 1526 pfctl_show_altq(dev, opts, 0); 1527 pfctl_show_states(dev, 0, opts); 1528 pfctl_show_status(dev); 1529 pfctl_show_rules(dev, opts, 1, anchorname, rulesetname); 1530 pfctl_show_timeouts(dev); 1531 pfctl_show_limits(dev); 1532 pfctl_show_tables(anchorname, rulesetname, opts); 1533 pfctl_show_fingerprints(opts); 1534 break; 1535 case 'T': 1536 pfctl_show_tables(anchorname, rulesetname, opts); 1537 break; 1538 case 'o': 1539 pfctl_load_fingerprints(dev, opts); 1540 pfctl_show_fingerprints(opts); 1541 break; 1542 } 1543 } 1544 1545 if (clearopt != NULL) { 1546 switch (*clearopt) { 1547 case 'r': 1548 pfctl_clear_rules(dev, opts, anchorname, rulesetname); 1549 break; 1550 case 'n': 1551 pfctl_clear_nat(dev, opts, anchorname, rulesetname); 1552 break; 1553 case 'q': 1554 pfctl_clear_altq(dev, opts); 1555 break; 1556 case 's': 1557 pfctl_clear_states(dev, opts); 1558 break; 1559 case 'i': 1560 pfctl_clear_stats(dev, opts); 1561 break; 1562 case 'a': 1563 pfctl_clear_rules(dev, opts, anchorname, rulesetname); 1564 pfctl_clear_nat(dev, opts, anchorname, rulesetname); 1565 pfctl_clear_altq(dev, opts); 1566 pfctl_clear_states(dev, opts); 1567 pfctl_clear_stats(dev, opts); 1568 pfctl_clear_tables(anchorname, rulesetname, opts); 1569 pfctl_clear_fingerprints(dev, opts); 1570 break; 1571 case 'o': 1572 pfctl_clear_fingerprints(dev, opts); 1573 break; 1574 case 'T': 1575 pfctl_clear_tables(anchorname, rulesetname, opts); 1576 break; 1577 } 1578 } 1579 if (state_killers) 1580 pfctl_kill_states(dev, opts); 1581 1582 if (tblcmdopt != NULL) { 1583 error = pfctl_command_tables(argc, argv, tableopt, 1584 tblcmdopt, rulesopt, anchorname, rulesetname, opts); 1585 rulesopt = NULL; 1586 } 1587 1588 if (rulesopt != NULL) 1589 if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) 1590 error = 1; 1591 1592 if (rulesopt != NULL) { 1593 if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname)) 1594 error = 1; 1595 else if (!(opts & PF_OPT_NOACTION) && 1596 (loadopt & PFCTL_FLAG_TABLE)) 1597 warn_namespace_collision(NULL); 1598 } 1599 1600 if (opts & PF_OPT_ENABLE) 1601 if (pfctl_enable(dev, opts)) 1602 error = 1; 1603 1604 if (debugopt != NULL) { 1605 switch (*debugopt) { 1606 case 'n': 1607 pfctl_debug(dev, PF_DEBUG_NONE, opts); 1608 break; 1609 case 'u': 1610 pfctl_debug(dev, PF_DEBUG_URGENT, opts); 1611 break; 1612 case 'm': 1613 pfctl_debug(dev, PF_DEBUG_MISC, opts); 1614 break; 1615 case 'l': 1616 pfctl_debug(dev, PF_DEBUG_NOISY, opts); 1617 break; 1618 } 1619 } 1620 1621 if (opts & PF_OPT_CLRRULECTRS) { 1622 if (pfctl_clear_rule_counters(dev, opts)) 1623 error = 1; 1624 } 1625 exit(error); 1626}
| 1499 } 1500 1501 if (opts & PF_OPT_DISABLE) 1502 if (pfctl_disable(dev, opts)) 1503 error = 1; 1504 1505 if (showopt != NULL) { 1506 switch (*showopt) { 1507 case 'A': 1508 pfctl_show_anchors(dev, opts, anchorname); 1509 break; 1510 case 'r': 1511 pfctl_load_fingerprints(dev, opts); 1512 pfctl_show_rules(dev, opts, 0, anchorname, 1513 rulesetname); 1514 break; 1515 case 'l': 1516 pfctl_load_fingerprints(dev, opts); 1517 pfctl_show_rules(dev, opts, 1, anchorname, 1518 rulesetname); 1519 break; 1520 case 'n': 1521 pfctl_load_fingerprints(dev, opts); 1522 pfctl_show_nat(dev, opts, anchorname, rulesetname); 1523 break; 1524 case 'q': 1525 pfctl_show_altq(dev, opts, opts & PF_OPT_VERBOSE2); 1526 break; 1527 case 's': 1528 pfctl_show_states(dev, 0, opts); 1529 break; 1530 case 'i': 1531 pfctl_show_status(dev); 1532 break; 1533 case 't': 1534 pfctl_show_timeouts(dev); 1535 break; 1536 case 'm': 1537 pfctl_show_limits(dev); 1538 break; 1539 case 'a': 1540 pfctl_load_fingerprints(dev, opts); 1541 1542 pfctl_show_rules(dev, opts, 0, anchorname, 1543 rulesetname); 1544 pfctl_show_nat(dev, opts, anchorname, rulesetname); 1545 pfctl_show_altq(dev, opts, 0); 1546 pfctl_show_states(dev, 0, opts); 1547 pfctl_show_status(dev); 1548 pfctl_show_rules(dev, opts, 1, anchorname, rulesetname); 1549 pfctl_show_timeouts(dev); 1550 pfctl_show_limits(dev); 1551 pfctl_show_tables(anchorname, rulesetname, opts); 1552 pfctl_show_fingerprints(opts); 1553 break; 1554 case 'T': 1555 pfctl_show_tables(anchorname, rulesetname, opts); 1556 break; 1557 case 'o': 1558 pfctl_load_fingerprints(dev, opts); 1559 pfctl_show_fingerprints(opts); 1560 break; 1561 } 1562 } 1563 1564 if (clearopt != NULL) { 1565 switch (*clearopt) { 1566 case 'r': 1567 pfctl_clear_rules(dev, opts, anchorname, rulesetname); 1568 break; 1569 case 'n': 1570 pfctl_clear_nat(dev, opts, anchorname, rulesetname); 1571 break; 1572 case 'q': 1573 pfctl_clear_altq(dev, opts); 1574 break; 1575 case 's': 1576 pfctl_clear_states(dev, opts); 1577 break; 1578 case 'i': 1579 pfctl_clear_stats(dev, opts); 1580 break; 1581 case 'a': 1582 pfctl_clear_rules(dev, opts, anchorname, rulesetname); 1583 pfctl_clear_nat(dev, opts, anchorname, rulesetname); 1584 pfctl_clear_altq(dev, opts); 1585 pfctl_clear_states(dev, opts); 1586 pfctl_clear_stats(dev, opts); 1587 pfctl_clear_tables(anchorname, rulesetname, opts); 1588 pfctl_clear_fingerprints(dev, opts); 1589 break; 1590 case 'o': 1591 pfctl_clear_fingerprints(dev, opts); 1592 break; 1593 case 'T': 1594 pfctl_clear_tables(anchorname, rulesetname, opts); 1595 break; 1596 } 1597 } 1598 if (state_killers) 1599 pfctl_kill_states(dev, opts); 1600 1601 if (tblcmdopt != NULL) { 1602 error = pfctl_command_tables(argc, argv, tableopt, 1603 tblcmdopt, rulesopt, anchorname, rulesetname, opts); 1604 rulesopt = NULL; 1605 } 1606 1607 if (rulesopt != NULL) 1608 if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) 1609 error = 1; 1610 1611 if (rulesopt != NULL) { 1612 if (pfctl_rules(dev, rulesopt, opts, anchorname, rulesetname)) 1613 error = 1; 1614 else if (!(opts & PF_OPT_NOACTION) && 1615 (loadopt & PFCTL_FLAG_TABLE)) 1616 warn_namespace_collision(NULL); 1617 } 1618 1619 if (opts & PF_OPT_ENABLE) 1620 if (pfctl_enable(dev, opts)) 1621 error = 1; 1622 1623 if (debugopt != NULL) { 1624 switch (*debugopt) { 1625 case 'n': 1626 pfctl_debug(dev, PF_DEBUG_NONE, opts); 1627 break; 1628 case 'u': 1629 pfctl_debug(dev, PF_DEBUG_URGENT, opts); 1630 break; 1631 case 'm': 1632 pfctl_debug(dev, PF_DEBUG_MISC, opts); 1633 break; 1634 case 'l': 1635 pfctl_debug(dev, PF_DEBUG_NOISY, opts); 1636 break; 1637 } 1638 } 1639 1640 if (opts & PF_OPT_CLRRULECTRS) { 1641 if (pfctl_clear_rule_counters(dev, opts)) 1642 error = 1; 1643 } 1644 exit(error); 1645}
|