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