Deleted Added
full compact
pfctl.c (126354) pfctl.c (126355)
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}