1 |
|
|
/* $OpenBSD: pfctl.c,v 1.334 2016/01/14 12:05:51 henning Exp $ */ |
2 |
|
|
|
3 |
|
|
/* |
4 |
|
|
* Copyright (c) 2001 Daniel Hartmeier |
5 |
|
|
* Copyright (c) 2002 - 2013 Henning Brauer <henning@openbsd.org> |
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 |
|
|
#include <sys/stat.h> |
38 |
|
|
|
39 |
|
|
#include <net/if.h> |
40 |
|
|
#include <netinet/in.h> |
41 |
|
|
#include <net/pfvar.h> |
42 |
|
|
#include <arpa/inet.h> |
43 |
|
|
#include <net/hfsc.h> |
44 |
|
|
#include <sys/sysctl.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 <syslog.h> |
57 |
|
|
|
58 |
|
|
#include "pfctl_parser.h" |
59 |
|
|
#include "pfctl.h" |
60 |
|
|
|
61 |
|
|
void usage(void); |
62 |
|
|
int pfctl_enable(int, int); |
63 |
|
|
int pfctl_disable(int, int); |
64 |
|
|
void pfctl_clear_queues(struct pf_qihead *); |
65 |
|
|
int pfctl_clear_stats(int, const char *, int); |
66 |
|
|
int pfctl_clear_interface_flags(int, int); |
67 |
|
|
int pfctl_clear_rules(int, int, char *); |
68 |
|
|
int pfctl_clear_src_nodes(int, int); |
69 |
|
|
int pfctl_clear_states(int, const char *, int); |
70 |
|
|
void pfctl_addrprefix(char *, struct pf_addr *); |
71 |
|
|
int pfctl_kill_src_nodes(int, const char *, int); |
72 |
|
|
int pfctl_net_kill_states(int, const char *, int); |
73 |
|
|
int pfctl_label_kill_states(int, const char *, int); |
74 |
|
|
int pfctl_id_kill_states(int, const char *, int); |
75 |
|
|
void pfctl_init_options(struct pfctl *); |
76 |
|
|
int pfctl_load_options(struct pfctl *); |
77 |
|
|
int pfctl_load_limit(struct pfctl *, unsigned int, unsigned int); |
78 |
|
|
int pfctl_load_timeout(struct pfctl *, unsigned int, unsigned int); |
79 |
|
|
int pfctl_load_debug(struct pfctl *, unsigned int); |
80 |
|
|
int pfctl_load_logif(struct pfctl *, char *); |
81 |
|
|
int pfctl_load_hostid(struct pfctl *, unsigned int); |
82 |
|
|
int pfctl_load_reassembly(struct pfctl *, u_int32_t); |
83 |
|
|
void pfctl_print_rule_counters(struct pf_rule *, int); |
84 |
|
|
int pfctl_show_rules(int, char *, int, enum pfctl_show, char *, int, int, |
85 |
|
|
long); |
86 |
|
|
int pfctl_show_src_nodes(int, int); |
87 |
|
|
int pfctl_show_states(int, const char *, int, long); |
88 |
|
|
int pfctl_show_status(int, int); |
89 |
|
|
int pfctl_show_timeouts(int, int); |
90 |
|
|
int pfctl_show_limits(int, int); |
91 |
|
|
void pfctl_debug(int, u_int32_t, int); |
92 |
|
|
int pfctl_show_anchors(int, int, char *); |
93 |
|
|
int pfctl_ruleset_trans(struct pfctl *, char *, struct pf_anchor *); |
94 |
|
|
u_int pfctl_find_childqs(struct pfctl_qsitem *); |
95 |
|
|
void pfctl_load_queue(struct pfctl *, u_int32_t, struct pfctl_qsitem *); |
96 |
|
|
int pfctl_load_queues(struct pfctl *); |
97 |
|
|
u_int pfctl_leafqueue_check(char *); |
98 |
|
|
u_int pfctl_check_qassignments(struct pf_ruleset *); |
99 |
|
|
int pfctl_load_ruleset(struct pfctl *, char *, struct pf_ruleset *, int); |
100 |
|
|
int pfctl_load_rule(struct pfctl *, char *, struct pf_rule *, int); |
101 |
|
|
const char *pfctl_lookup_option(char *, const char **); |
102 |
|
|
void pfctl_state_store(int, const char *); |
103 |
|
|
void pfctl_state_load(int, const char *); |
104 |
|
|
|
105 |
|
|
struct pf_anchor_global pf_anchors; |
106 |
|
|
struct pf_anchor pf_main_anchor; |
107 |
|
|
|
108 |
|
|
const char *clearopt; |
109 |
|
|
char *rulesopt; |
110 |
|
|
const char *showopt; |
111 |
|
|
const char *debugopt; |
112 |
|
|
char *anchoropt; |
113 |
|
|
const char *optiopt = NULL; |
114 |
|
|
char *pf_device = "/dev/pf"; |
115 |
|
|
char *ifaceopt; |
116 |
|
|
char *tableopt; |
117 |
|
|
const char *tblcmdopt; |
118 |
|
|
int src_node_killers; |
119 |
|
|
char *src_node_kill[2]; |
120 |
|
|
int state_killers; |
121 |
|
|
char *state_kill[2]; |
122 |
|
|
|
123 |
|
|
int dev = -1; |
124 |
|
|
int first_title = 1; |
125 |
|
|
int labels = 0; |
126 |
|
|
|
127 |
|
|
#define INDENT(d, o) do { \ |
128 |
|
|
if (o) { \ |
129 |
|
|
int i; \ |
130 |
|
|
for (i=0; i < d; i++) \ |
131 |
|
|
printf(" "); \ |
132 |
|
|
} \ |
133 |
|
|
} while (0) \ |
134 |
|
|
|
135 |
|
|
|
136 |
|
|
static const struct { |
137 |
|
|
const char *name; |
138 |
|
|
int index; |
139 |
|
|
} pf_limits[] = { |
140 |
|
|
{ "states", PF_LIMIT_STATES }, |
141 |
|
|
{ "src-nodes", PF_LIMIT_SRC_NODES }, |
142 |
|
|
{ "frags", PF_LIMIT_FRAGS }, |
143 |
|
|
{ "tables", PF_LIMIT_TABLES }, |
144 |
|
|
{ "table-entries", PF_LIMIT_TABLE_ENTRIES }, |
145 |
|
|
{ NULL, 0 } |
146 |
|
|
}; |
147 |
|
|
|
148 |
|
|
struct pf_hint { |
149 |
|
|
const char *name; |
150 |
|
|
int timeout; |
151 |
|
|
}; |
152 |
|
|
static const struct pf_hint pf_hint_normal[] = { |
153 |
|
|
{ "tcp.first", 2 * 60 }, |
154 |
|
|
{ "tcp.opening", 30 }, |
155 |
|
|
{ "tcp.established", 24 * 60 * 60 }, |
156 |
|
|
{ "tcp.closing", 15 * 60 }, |
157 |
|
|
{ "tcp.finwait", 45 }, |
158 |
|
|
{ "tcp.closed", 90 }, |
159 |
|
|
{ "tcp.tsdiff", 30 }, |
160 |
|
|
{ NULL, 0 } |
161 |
|
|
}; |
162 |
|
|
static const struct pf_hint pf_hint_satellite[] = { |
163 |
|
|
{ "tcp.first", 3 * 60 }, |
164 |
|
|
{ "tcp.opening", 30 + 5 }, |
165 |
|
|
{ "tcp.established", 24 * 60 * 60 }, |
166 |
|
|
{ "tcp.closing", 15 * 60 + 5 }, |
167 |
|
|
{ "tcp.finwait", 45 + 5 }, |
168 |
|
|
{ "tcp.closed", 90 + 5 }, |
169 |
|
|
{ "tcp.tsdiff", 60 }, |
170 |
|
|
{ NULL, 0 } |
171 |
|
|
}; |
172 |
|
|
static const struct pf_hint pf_hint_conservative[] = { |
173 |
|
|
{ "tcp.first", 60 * 60 }, |
174 |
|
|
{ "tcp.opening", 15 * 60 }, |
175 |
|
|
{ "tcp.established", 5 * 24 * 60 * 60 }, |
176 |
|
|
{ "tcp.closing", 60 * 60 }, |
177 |
|
|
{ "tcp.finwait", 10 * 60 }, |
178 |
|
|
{ "tcp.closed", 3 * 60 }, |
179 |
|
|
{ "tcp.tsdiff", 60 }, |
180 |
|
|
{ NULL, 0 } |
181 |
|
|
}; |
182 |
|
|
static const struct pf_hint pf_hint_aggressive[] = { |
183 |
|
|
{ "tcp.first", 30 }, |
184 |
|
|
{ "tcp.opening", 5 }, |
185 |
|
|
{ "tcp.established", 5 * 60 * 60 }, |
186 |
|
|
{ "tcp.closing", 60 }, |
187 |
|
|
{ "tcp.finwait", 30 }, |
188 |
|
|
{ "tcp.closed", 30 }, |
189 |
|
|
{ "tcp.tsdiff", 10 }, |
190 |
|
|
{ NULL, 0 } |
191 |
|
|
}; |
192 |
|
|
|
193 |
|
|
static const struct { |
194 |
|
|
const char *name; |
195 |
|
|
const struct pf_hint *hint; |
196 |
|
|
} pf_hints[] = { |
197 |
|
|
{ "normal", pf_hint_normal }, |
198 |
|
|
{ "satellite", pf_hint_satellite }, |
199 |
|
|
{ "high-latency", pf_hint_satellite }, |
200 |
|
|
{ "conservative", pf_hint_conservative }, |
201 |
|
|
{ "aggressive", pf_hint_aggressive }, |
202 |
|
|
{ NULL, NULL } |
203 |
|
|
}; |
204 |
|
|
|
205 |
|
|
static const char *clearopt_list[] = { |
206 |
|
|
"rules", "Sources", "states", "info", "Tables", "osfp", "all", NULL |
207 |
|
|
}; |
208 |
|
|
|
209 |
|
|
static const char *showopt_list[] = { |
210 |
|
|
"queue", "rules", "Anchors", "Sources", "states", "info", |
211 |
|
|
"Interfaces", "labels", "timeouts", "memory", "Tables", "osfp", |
212 |
|
|
"all", NULL |
213 |
|
|
}; |
214 |
|
|
|
215 |
|
|
static const char *tblcmdopt_list[] = { |
216 |
|
|
"kill", "flush", "add", "delete", "replace", "show", |
217 |
|
|
"test", "zero", "expire", NULL |
218 |
|
|
}; |
219 |
|
|
|
220 |
|
|
static const char *debugopt_list[] = { |
221 |
|
|
"debug", "info", "notice", "warning", |
222 |
|
|
"error", "crit", "alert", "emerg", |
223 |
|
|
NULL |
224 |
|
|
}; |
225 |
|
|
|
226 |
|
|
static const char *optiopt_list[] = { |
227 |
|
|
"none", "basic", "profile", NULL |
228 |
|
|
}; |
229 |
|
|
|
230 |
|
|
struct pf_qihead qspecs = TAILQ_HEAD_INITIALIZER(qspecs); |
231 |
|
|
struct pf_qihead rootqs = TAILQ_HEAD_INITIALIZER(rootqs); |
232 |
|
|
|
233 |
|
|
|
234 |
|
|
void |
235 |
|
|
usage(void) |
236 |
|
|
{ |
237 |
|
|
extern char *__progname; |
238 |
|
|
|
239 |
|
|
fprintf(stderr, "usage: %s [-deghnPqrvz] ", __progname); |
240 |
|
|
fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n"); |
241 |
|
|
fprintf(stderr, "\t[-f file] [-i interface] [-K host | network]\n"); |
242 |
|
|
fprintf(stderr, "\t[-k host | network | label | id] "); |
243 |
|
|
fprintf(stderr, "[-L statefile] [-o level] [-p device]\n"); |
244 |
|
|
fprintf(stderr, "\t[-S statefile] [-s modifier [-R id]] "); |
245 |
|
|
fprintf(stderr, "[-t table -T command [address ...]]\n"); |
246 |
|
|
fprintf(stderr, "\t[-x level]\n"); |
247 |
|
|
exit(1); |
248 |
|
|
} |
249 |
|
|
|
250 |
|
|
int |
251 |
|
|
pfctl_enable(int dev, int opts) |
252 |
|
|
{ |
253 |
|
|
if (ioctl(dev, DIOCSTART)) { |
254 |
|
|
if (errno == EEXIST) |
255 |
|
|
errx(1, "pf already enabled"); |
256 |
|
|
else |
257 |
|
|
err(1, "DIOCSTART"); |
258 |
|
|
} |
259 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
260 |
|
|
fprintf(stderr, "pf enabled\n"); |
261 |
|
|
|
262 |
|
|
return (0); |
263 |
|
|
} |
264 |
|
|
|
265 |
|
|
int |
266 |
|
|
pfctl_disable(int dev, int opts) |
267 |
|
|
{ |
268 |
|
|
if (ioctl(dev, DIOCSTOP)) { |
269 |
|
|
if (errno == ENOENT) |
270 |
|
|
errx(1, "pf not enabled"); |
271 |
|
|
else |
272 |
|
|
err(1, "DIOCSTOP"); |
273 |
|
|
} |
274 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
275 |
|
|
fprintf(stderr, "pf disabled\n"); |
276 |
|
|
|
277 |
|
|
return (0); |
278 |
|
|
} |
279 |
|
|
|
280 |
|
|
int |
281 |
|
|
pfctl_clear_stats(int dev, const char *iface, int opts) |
282 |
|
|
{ |
283 |
|
|
struct pfioc_iface pi; |
284 |
|
|
|
285 |
|
|
memset(&pi, 0, sizeof(pi)); |
286 |
|
|
if (iface != NULL && strlcpy(pi.pfiio_name, iface, |
287 |
|
|
sizeof(pi.pfiio_name)) >= sizeof(pi.pfiio_name)) |
288 |
|
|
errx(1, "invalid interface: %s", iface); |
289 |
|
|
|
290 |
|
|
if (ioctl(dev, DIOCCLRSTATUS, &pi)) |
291 |
|
|
err(1, "DIOCCLRSTATUS"); |
292 |
|
|
if ((opts & PF_OPT_QUIET) == 0) { |
293 |
|
|
fprintf(stderr, "pf: statistics cleared"); |
294 |
|
|
if (iface != NULL) |
295 |
|
|
fprintf(stderr, " for interface %s", iface); |
296 |
|
|
fprintf(stderr, "\n"); |
297 |
|
|
} |
298 |
|
|
return (0); |
299 |
|
|
} |
300 |
|
|
|
301 |
|
|
int |
302 |
|
|
pfctl_clear_interface_flags(int dev, int opts) |
303 |
|
|
{ |
304 |
|
|
struct pfioc_iface pi; |
305 |
|
|
|
306 |
|
|
if ((opts & PF_OPT_NOACTION) == 0) { |
307 |
|
|
bzero(&pi, sizeof(pi)); |
308 |
|
|
pi.pfiio_flags = PFI_IFLAG_SKIP; |
309 |
|
|
|
310 |
|
|
if (ioctl(dev, DIOCCLRIFFLAG, &pi)) |
311 |
|
|
err(1, "DIOCCLRIFFLAG"); |
312 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
313 |
|
|
fprintf(stderr, "pf: interface flags reset\n"); |
314 |
|
|
} |
315 |
|
|
return (0); |
316 |
|
|
} |
317 |
|
|
|
318 |
|
|
int |
319 |
|
|
pfctl_clear_rules(int dev, int opts, char *anchorname) |
320 |
|
|
{ |
321 |
|
|
struct pfr_buffer t; |
322 |
|
|
|
323 |
|
|
memset(&t, 0, sizeof(t)); |
324 |
|
|
t.pfrb_type = PFRB_TRANS; |
325 |
|
|
if (pfctl_add_trans(&t, PF_TRANS_RULESET, anchorname) || |
326 |
|
|
pfctl_trans(dev, &t, DIOCXBEGIN, 0) || |
327 |
|
|
pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) |
328 |
|
|
err(1, "pfctl_clear_rules"); |
329 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
330 |
|
|
fprintf(stderr, "rules cleared\n"); |
331 |
|
|
return (0); |
332 |
|
|
} |
333 |
|
|
|
334 |
|
|
int |
335 |
|
|
pfctl_clear_src_nodes(int dev, int opts) |
336 |
|
|
{ |
337 |
|
|
if (ioctl(dev, DIOCCLRSRCNODES)) |
338 |
|
|
err(1, "DIOCCLRSRCNODES"); |
339 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
340 |
|
|
fprintf(stderr, "source tracking entries cleared\n"); |
341 |
|
|
return (0); |
342 |
|
|
} |
343 |
|
|
|
344 |
|
|
int |
345 |
|
|
pfctl_clear_states(int dev, const char *iface, int opts) |
346 |
|
|
{ |
347 |
|
|
struct pfioc_state_kill psk; |
348 |
|
|
|
349 |
|
|
memset(&psk, 0, sizeof(psk)); |
350 |
|
|
if (iface != NULL && strlcpy(psk.psk_ifname, iface, |
351 |
|
|
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) |
352 |
|
|
errx(1, "invalid interface: %s", iface); |
353 |
|
|
|
354 |
|
|
if (ioctl(dev, DIOCCLRSTATES, &psk)) |
355 |
|
|
err(1, "DIOCCLRSTATES"); |
356 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
357 |
|
|
fprintf(stderr, "%d states cleared\n", psk.psk_killed); |
358 |
|
|
return (0); |
359 |
|
|
} |
360 |
|
|
|
361 |
|
|
void |
362 |
|
|
pfctl_addrprefix(char *addr, struct pf_addr *mask) |
363 |
|
|
{ |
364 |
|
|
char *p; |
365 |
|
|
const char *errstr; |
366 |
|
|
int prefix, ret_ga, q, r; |
367 |
|
|
struct addrinfo hints, *res; |
368 |
|
|
|
369 |
|
|
if ((p = strchr(addr, '/')) == NULL) |
370 |
|
|
return; |
371 |
|
|
|
372 |
|
|
*p++ = '\0'; |
373 |
|
|
prefix = strtonum(p, 0, 128, &errstr); |
374 |
|
|
if (errstr) |
375 |
|
|
errx(1, "prefix is %s: %s", errstr, p); |
376 |
|
|
|
377 |
|
|
bzero(&hints, sizeof(hints)); |
378 |
|
|
/* prefix only with numeric addresses */ |
379 |
|
|
hints.ai_flags |= AI_NUMERICHOST; |
380 |
|
|
|
381 |
|
|
if ((ret_ga = getaddrinfo(addr, NULL, &hints, &res))) { |
382 |
|
|
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); |
383 |
|
|
/* NOTREACHED */ |
384 |
|
|
} |
385 |
|
|
|
386 |
|
|
if (res->ai_family == AF_INET && prefix > 32) |
387 |
|
|
errx(1, "prefix too long for AF_INET"); |
388 |
|
|
else if (res->ai_family == AF_INET6 && prefix > 128) |
389 |
|
|
errx(1, "prefix too long for AF_INET6"); |
390 |
|
|
|
391 |
|
|
q = prefix >> 3; |
392 |
|
|
r = prefix & 7; |
393 |
|
|
switch (res->ai_family) { |
394 |
|
|
case AF_INET: |
395 |
|
|
bzero(&mask->v4, sizeof(mask->v4)); |
396 |
|
|
mask->v4.s_addr = htonl((u_int32_t) |
397 |
|
|
(0xffffffffffULL << (32 - prefix))); |
398 |
|
|
break; |
399 |
|
|
case AF_INET6: |
400 |
|
|
bzero(&mask->v6, sizeof(mask->v6)); |
401 |
|
|
if (q > 0) |
402 |
|
|
memset((void *)&mask->v6, 0xff, q); |
403 |
|
|
if (r > 0) |
404 |
|
|
*((u_char *)&mask->v6 + q) = |
405 |
|
|
(0xff00 >> r) & 0xff; |
406 |
|
|
break; |
407 |
|
|
} |
408 |
|
|
freeaddrinfo(res); |
409 |
|
|
} |
410 |
|
|
|
411 |
|
|
int |
412 |
|
|
pfctl_kill_src_nodes(int dev, const char *iface, int opts) |
413 |
|
|
{ |
414 |
|
|
struct pfioc_src_node_kill psnk; |
415 |
|
|
struct addrinfo *res[2], *resp[2]; |
416 |
|
|
struct sockaddr last_src, last_dst; |
417 |
|
|
int killed, sources, dests; |
418 |
|
|
int ret_ga; |
419 |
|
|
|
420 |
|
|
killed = sources = dests = 0; |
421 |
|
|
|
422 |
|
|
memset(&psnk, 0, sizeof(psnk)); |
423 |
|
|
memset(&psnk.psnk_src.addr.v.a.mask, 0xff, |
424 |
|
|
sizeof(psnk.psnk_src.addr.v.a.mask)); |
425 |
|
|
memset(&last_src, 0xff, sizeof(last_src)); |
426 |
|
|
memset(&last_dst, 0xff, sizeof(last_dst)); |
427 |
|
|
|
428 |
|
|
pfctl_addrprefix(src_node_kill[0], &psnk.psnk_src.addr.v.a.mask); |
429 |
|
|
|
430 |
|
|
if ((ret_ga = getaddrinfo(src_node_kill[0], NULL, NULL, &res[0]))) { |
431 |
|
|
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); |
432 |
|
|
/* NOTREACHED */ |
433 |
|
|
} |
434 |
|
|
for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { |
435 |
|
|
if (resp[0]->ai_addr == NULL) |
436 |
|
|
continue; |
437 |
|
|
/* We get lots of duplicates. Catch the easy ones */ |
438 |
|
|
if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) |
439 |
|
|
continue; |
440 |
|
|
last_src = *(struct sockaddr *)resp[0]->ai_addr; |
441 |
|
|
|
442 |
|
|
psnk.psnk_af = resp[0]->ai_family; |
443 |
|
|
sources++; |
444 |
|
|
|
445 |
|
|
if (psnk.psnk_af == AF_INET) |
446 |
|
|
psnk.psnk_src.addr.v.a.addr.v4 = |
447 |
|
|
((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; |
448 |
|
|
else if (psnk.psnk_af == AF_INET6) |
449 |
|
|
psnk.psnk_src.addr.v.a.addr.v6 = |
450 |
|
|
((struct sockaddr_in6 *)resp[0]->ai_addr)-> |
451 |
|
|
sin6_addr; |
452 |
|
|
else |
453 |
|
|
errx(1, "Unknown address family %d", psnk.psnk_af); |
454 |
|
|
|
455 |
|
|
if (src_node_killers > 1) { |
456 |
|
|
dests = 0; |
457 |
|
|
memset(&psnk.psnk_dst.addr.v.a.mask, 0xff, |
458 |
|
|
sizeof(psnk.psnk_dst.addr.v.a.mask)); |
459 |
|
|
memset(&last_dst, 0xff, sizeof(last_dst)); |
460 |
|
|
pfctl_addrprefix(src_node_kill[1], |
461 |
|
|
&psnk.psnk_dst.addr.v.a.mask); |
462 |
|
|
if ((ret_ga = getaddrinfo(src_node_kill[1], NULL, NULL, |
463 |
|
|
&res[1]))) { |
464 |
|
|
errx(1, "getaddrinfo: %s", |
465 |
|
|
gai_strerror(ret_ga)); |
466 |
|
|
/* NOTREACHED */ |
467 |
|
|
} |
468 |
|
|
for (resp[1] = res[1]; resp[1]; |
469 |
|
|
resp[1] = resp[1]->ai_next) { |
470 |
|
|
if (resp[1]->ai_addr == NULL) |
471 |
|
|
continue; |
472 |
|
|
if (psnk.psnk_af != resp[1]->ai_family) |
473 |
|
|
continue; |
474 |
|
|
|
475 |
|
|
if (memcmp(&last_dst, resp[1]->ai_addr, |
476 |
|
|
sizeof(last_dst)) == 0) |
477 |
|
|
continue; |
478 |
|
|
last_dst = *(struct sockaddr *)resp[1]->ai_addr; |
479 |
|
|
|
480 |
|
|
dests++; |
481 |
|
|
|
482 |
|
|
if (psnk.psnk_af == AF_INET) |
483 |
|
|
psnk.psnk_dst.addr.v.a.addr.v4 = |
484 |
|
|
((struct sockaddr_in *)resp[1]-> |
485 |
|
|
ai_addr)->sin_addr; |
486 |
|
|
else if (psnk.psnk_af == AF_INET6) |
487 |
|
|
psnk.psnk_dst.addr.v.a.addr.v6 = |
488 |
|
|
((struct sockaddr_in6 *)resp[1]-> |
489 |
|
|
ai_addr)->sin6_addr; |
490 |
|
|
else |
491 |
|
|
errx(1, "Unknown address family %d", |
492 |
|
|
psnk.psnk_af); |
493 |
|
|
|
494 |
|
|
if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) |
495 |
|
|
err(1, "DIOCKILLSRCNODES"); |
496 |
|
|
killed += psnk.psnk_killed; |
497 |
|
|
} |
498 |
|
|
freeaddrinfo(res[1]); |
499 |
|
|
} else { |
500 |
|
|
if (ioctl(dev, DIOCKILLSRCNODES, &psnk)) |
501 |
|
|
err(1, "DIOCKILLSRCNODES"); |
502 |
|
|
killed += psnk.psnk_killed; |
503 |
|
|
} |
504 |
|
|
} |
505 |
|
|
|
506 |
|
|
freeaddrinfo(res[0]); |
507 |
|
|
|
508 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
509 |
|
|
fprintf(stderr, "killed %d src nodes from %d sources and %d " |
510 |
|
|
"destinations\n", killed, sources, dests); |
511 |
|
|
return (0); |
512 |
|
|
} |
513 |
|
|
|
514 |
|
|
int |
515 |
|
|
pfctl_net_kill_states(int dev, const char *iface, int opts) |
516 |
|
|
{ |
517 |
|
|
struct pfioc_state_kill psk; |
518 |
|
|
struct addrinfo *res[2], *resp[2]; |
519 |
|
|
struct sockaddr last_src, last_dst; |
520 |
|
|
int killed, sources, dests; |
521 |
|
|
int ret_ga; |
522 |
|
|
|
523 |
|
|
killed = sources = dests = 0; |
524 |
|
|
|
525 |
|
|
memset(&psk, 0, sizeof(psk)); |
526 |
|
|
memset(&psk.psk_src.addr.v.a.mask, 0xff, |
527 |
|
|
sizeof(psk.psk_src.addr.v.a.mask)); |
528 |
|
|
memset(&last_src, 0xff, sizeof(last_src)); |
529 |
|
|
memset(&last_dst, 0xff, sizeof(last_dst)); |
530 |
|
|
if (iface != NULL && strlcpy(psk.psk_ifname, iface, |
531 |
|
|
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) |
532 |
|
|
errx(1, "invalid interface: %s", iface); |
533 |
|
|
|
534 |
|
|
pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask); |
535 |
|
|
|
536 |
|
|
if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { |
537 |
|
|
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); |
538 |
|
|
/* NOTREACHED */ |
539 |
|
|
} |
540 |
|
|
for (resp[0] = res[0]; resp[0]; resp[0] = resp[0]->ai_next) { |
541 |
|
|
if (resp[0]->ai_addr == NULL) |
542 |
|
|
continue; |
543 |
|
|
/* We get lots of duplicates. Catch the easy ones */ |
544 |
|
|
if (memcmp(&last_src, resp[0]->ai_addr, sizeof(last_src)) == 0) |
545 |
|
|
continue; |
546 |
|
|
last_src = *(struct sockaddr *)resp[0]->ai_addr; |
547 |
|
|
|
548 |
|
|
psk.psk_af = resp[0]->ai_family; |
549 |
|
|
sources++; |
550 |
|
|
|
551 |
|
|
if (psk.psk_af == AF_INET) |
552 |
|
|
psk.psk_src.addr.v.a.addr.v4 = |
553 |
|
|
((struct sockaddr_in *)resp[0]->ai_addr)->sin_addr; |
554 |
|
|
else if (psk.psk_af == AF_INET6) |
555 |
|
|
psk.psk_src.addr.v.a.addr.v6 = |
556 |
|
|
((struct sockaddr_in6 *)resp[0]->ai_addr)-> |
557 |
|
|
sin6_addr; |
558 |
|
|
else |
559 |
|
|
errx(1, "Unknown address family %d", psk.psk_af); |
560 |
|
|
|
561 |
|
|
if (state_killers > 1) { |
562 |
|
|
dests = 0; |
563 |
|
|
memset(&psk.psk_dst.addr.v.a.mask, 0xff, |
564 |
|
|
sizeof(psk.psk_dst.addr.v.a.mask)); |
565 |
|
|
memset(&last_dst, 0xff, sizeof(last_dst)); |
566 |
|
|
pfctl_addrprefix(state_kill[1], |
567 |
|
|
&psk.psk_dst.addr.v.a.mask); |
568 |
|
|
if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, |
569 |
|
|
&res[1]))) { |
570 |
|
|
errx(1, "getaddrinfo: %s", |
571 |
|
|
gai_strerror(ret_ga)); |
572 |
|
|
/* NOTREACHED */ |
573 |
|
|
} |
574 |
|
|
for (resp[1] = res[1]; resp[1]; |
575 |
|
|
resp[1] = resp[1]->ai_next) { |
576 |
|
|
if (resp[1]->ai_addr == NULL) |
577 |
|
|
continue; |
578 |
|
|
if (psk.psk_af != resp[1]->ai_family) |
579 |
|
|
continue; |
580 |
|
|
|
581 |
|
|
if (memcmp(&last_dst, resp[1]->ai_addr, |
582 |
|
|
sizeof(last_dst)) == 0) |
583 |
|
|
continue; |
584 |
|
|
last_dst = *(struct sockaddr *)resp[1]->ai_addr; |
585 |
|
|
|
586 |
|
|
dests++; |
587 |
|
|
|
588 |
|
|
if (psk.psk_af == AF_INET) |
589 |
|
|
psk.psk_dst.addr.v.a.addr.v4 = |
590 |
|
|
((struct sockaddr_in *)resp[1]-> |
591 |
|
|
ai_addr)->sin_addr; |
592 |
|
|
else if (psk.psk_af == AF_INET6) |
593 |
|
|
psk.psk_dst.addr.v.a.addr.v6 = |
594 |
|
|
((struct sockaddr_in6 *)resp[1]-> |
595 |
|
|
ai_addr)->sin6_addr; |
596 |
|
|
else |
597 |
|
|
errx(1, "Unknown address family %d", |
598 |
|
|
psk.psk_af); |
599 |
|
|
|
600 |
|
|
if (ioctl(dev, DIOCKILLSTATES, &psk)) |
601 |
|
|
err(1, "DIOCKILLSTATES"); |
602 |
|
|
killed += psk.psk_killed; |
603 |
|
|
} |
604 |
|
|
freeaddrinfo(res[1]); |
605 |
|
|
} else { |
606 |
|
|
if (ioctl(dev, DIOCKILLSTATES, &psk)) |
607 |
|
|
err(1, "DIOCKILLSTATES"); |
608 |
|
|
killed += psk.psk_killed; |
609 |
|
|
} |
610 |
|
|
} |
611 |
|
|
|
612 |
|
|
freeaddrinfo(res[0]); |
613 |
|
|
|
614 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
615 |
|
|
fprintf(stderr, "killed %d states from %d sources and %d " |
616 |
|
|
"destinations\n", killed, sources, dests); |
617 |
|
|
return (0); |
618 |
|
|
} |
619 |
|
|
|
620 |
|
|
int |
621 |
|
|
pfctl_label_kill_states(int dev, const char *iface, int opts) |
622 |
|
|
{ |
623 |
|
|
struct pfioc_state_kill psk; |
624 |
|
|
|
625 |
|
|
if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { |
626 |
|
|
warnx("no label specified"); |
627 |
|
|
usage(); |
628 |
|
|
} |
629 |
|
|
memset(&psk, 0, sizeof(psk)); |
630 |
|
|
if (iface != NULL && strlcpy(psk.psk_ifname, iface, |
631 |
|
|
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) |
632 |
|
|
errx(1, "invalid interface: %s", iface); |
633 |
|
|
|
634 |
|
|
if (strlcpy(psk.psk_label, state_kill[1], sizeof(psk.psk_label)) >= |
635 |
|
|
sizeof(psk.psk_label)) |
636 |
|
|
errx(1, "label too long: %s", state_kill[1]); |
637 |
|
|
|
638 |
|
|
if (ioctl(dev, DIOCKILLSTATES, &psk)) |
639 |
|
|
err(1, "DIOCKILLSTATES"); |
640 |
|
|
|
641 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
642 |
|
|
fprintf(stderr, "killed %d states\n", psk.psk_killed); |
643 |
|
|
|
644 |
|
|
return (0); |
645 |
|
|
} |
646 |
|
|
|
647 |
|
|
int |
648 |
|
|
pfctl_id_kill_states(int dev, const char *iface, int opts) |
649 |
|
|
{ |
650 |
|
|
struct pfioc_state_kill psk; |
651 |
|
|
|
652 |
|
|
if (state_killers != 2 || (strlen(state_kill[1]) == 0)) { |
653 |
|
|
warnx("no id specified"); |
654 |
|
|
usage(); |
655 |
|
|
} |
656 |
|
|
|
657 |
|
|
memset(&psk, 0, sizeof(psk)); |
658 |
|
|
if ((sscanf(state_kill[1], "%llx/%x", |
659 |
|
|
&psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2) |
660 |
|
|
HTONL(psk.psk_pfcmp.creatorid); |
661 |
|
|
else if ((sscanf(state_kill[1], "%llx", &psk.psk_pfcmp.id)) == 1) { |
662 |
|
|
psk.psk_pfcmp.creatorid = 0; |
663 |
|
|
} else { |
664 |
|
|
warnx("wrong id format specified"); |
665 |
|
|
usage(); |
666 |
|
|
} |
667 |
|
|
if (psk.psk_pfcmp.id == 0) { |
668 |
|
|
warnx("cannot kill id 0"); |
669 |
|
|
usage(); |
670 |
|
|
} |
671 |
|
|
|
672 |
|
|
psk.psk_pfcmp.id = htobe64(psk.psk_pfcmp.id); |
673 |
|
|
if (ioctl(dev, DIOCKILLSTATES, &psk)) |
674 |
|
|
err(1, "DIOCKILLSTATES"); |
675 |
|
|
|
676 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
677 |
|
|
fprintf(stderr, "killed %d states\n", psk.psk_killed); |
678 |
|
|
|
679 |
|
|
return (0); |
680 |
|
|
} |
681 |
|
|
|
682 |
|
|
void |
683 |
|
|
pfctl_print_rule_counters(struct pf_rule *rule, int opts) |
684 |
|
|
{ |
685 |
|
|
if (opts & PF_OPT_DEBUG) { |
686 |
|
|
const char *t[PF_SKIP_COUNT] = { "i", "d", "r", "f", |
687 |
|
|
"p", "sa", "da", "sp", "dp" }; |
688 |
|
|
int i; |
689 |
|
|
|
690 |
|
|
printf(" [ Skip steps: "); |
691 |
|
|
for (i = 0; i < PF_SKIP_COUNT; ++i) { |
692 |
|
|
if (rule->skip[i].nr == rule->nr + 1) |
693 |
|
|
continue; |
694 |
|
|
printf("%s=", t[i]); |
695 |
|
|
if (rule->skip[i].nr == -1) |
696 |
|
|
printf("end "); |
697 |
|
|
else |
698 |
|
|
printf("%u ", rule->skip[i].nr); |
699 |
|
|
} |
700 |
|
|
printf("]\n"); |
701 |
|
|
|
702 |
|
|
printf(" [ queue: qname=%s qid=%u pqname=%s pqid=%u ]\n", |
703 |
|
|
rule->qname, rule->qid, rule->pqname, rule->pqid); |
704 |
|
|
} |
705 |
|
|
if (opts & PF_OPT_VERBOSE) { |
706 |
|
|
printf(" [ Evaluations: %-8llu Packets: %-8llu " |
707 |
|
|
"Bytes: %-10llu States: %-6u]\n", |
708 |
|
|
(unsigned long long)rule->evaluations, |
709 |
|
|
(unsigned long long)(rule->packets[0] + |
710 |
|
|
rule->packets[1]), |
711 |
|
|
(unsigned long long)(rule->bytes[0] + |
712 |
|
|
rule->bytes[1]), rule->states_cur); |
713 |
|
|
if (!(opts & PF_OPT_DEBUG)) |
714 |
|
|
printf(" [ Inserted: uid %lu pid %lu " |
715 |
|
|
"State Creations: %-6u]\n", |
716 |
|
|
(unsigned long)rule->cuid, (unsigned long)rule->cpid, |
717 |
|
|
rule->states_tot); |
718 |
|
|
} |
719 |
|
|
} |
720 |
|
|
|
721 |
|
|
void |
722 |
|
|
pfctl_print_title(char *title) |
723 |
|
|
{ |
724 |
|
|
if (!first_title) |
725 |
|
|
printf("\n"); |
726 |
|
|
first_title = 0; |
727 |
|
|
printf("%s\n", title); |
728 |
|
|
} |
729 |
|
|
|
730 |
|
|
int |
731 |
|
|
pfctl_show_rules(int dev, char *path, int opts, enum pfctl_show format, |
732 |
|
|
char *anchorname, int depth, int wildcard, long shownr) |
733 |
|
|
{ |
734 |
|
|
struct pfioc_rule pr; |
735 |
|
|
u_int32_t nr, mnr, header = 0; |
736 |
|
|
int len = strlen(path), ret = 0; |
737 |
|
|
char *npath, *p; |
738 |
|
|
|
739 |
|
|
/* |
740 |
|
|
* Truncate a trailing / and * on an anchorname before searching for |
741 |
|
|
* the ruleset, this is syntactic sugar that doesn't actually make it |
742 |
|
|
* to the kernel. |
743 |
|
|
*/ |
744 |
|
|
if ((p = strrchr(anchorname, '/')) != NULL && |
745 |
|
|
p[1] == '*' && p[2] == '\0') { |
746 |
|
|
p[0] = '\0'; |
747 |
|
|
} |
748 |
|
|
|
749 |
|
|
memset(&pr, 0, sizeof(pr)); |
750 |
|
|
if (anchorname[0] == '/') { |
751 |
|
|
if ((npath = calloc(1, PATH_MAX)) == NULL) |
752 |
|
|
errx(1, "pfctl_rules: calloc"); |
753 |
|
|
strlcpy(npath, anchorname, PATH_MAX); |
754 |
|
|
} else { |
755 |
|
|
if (path[0]) |
756 |
|
|
snprintf(&path[len], PATH_MAX - len, "/%s", anchorname); |
757 |
|
|
else |
758 |
|
|
snprintf(&path[len], PATH_MAX - len, "%s", anchorname); |
759 |
|
|
npath = path; |
760 |
|
|
} |
761 |
|
|
|
762 |
|
|
memcpy(pr.anchor, npath, sizeof(pr.anchor)); |
763 |
|
|
if (opts & PF_OPT_SHOWALL) { |
764 |
|
|
pr.rule.action = PF_PASS; |
765 |
|
|
if (ioctl(dev, DIOCGETRULES, &pr)) { |
766 |
|
|
warn("DIOCGETRULES"); |
767 |
|
|
ret = -1; |
768 |
|
|
goto error; |
769 |
|
|
} |
770 |
|
|
header++; |
771 |
|
|
if (format == PFCTL_SHOW_RULES && (pr.nr > 0 || header)) |
772 |
|
|
pfctl_print_title("FILTER RULES:"); |
773 |
|
|
else if (format == PFCTL_SHOW_LABELS && labels) |
774 |
|
|
pfctl_print_title("LABEL COUNTERS:"); |
775 |
|
|
} |
776 |
|
|
if (opts & PF_OPT_CLRRULECTRS) |
777 |
|
|
pr.action = PF_GET_CLR_CNTR; |
778 |
|
|
|
779 |
|
|
pr.rule.action = PF_PASS; |
780 |
|
|
if (ioctl(dev, DIOCGETRULES, &pr)) { |
781 |
|
|
warn("DIOCGETRULES"); |
782 |
|
|
ret = -1; |
783 |
|
|
goto error; |
784 |
|
|
} |
785 |
|
|
|
786 |
|
|
if (shownr < 0) { |
787 |
|
|
mnr = pr.nr; |
788 |
|
|
nr = 0; |
789 |
|
|
} else if (shownr < pr.nr) { |
790 |
|
|
nr = shownr; |
791 |
|
|
mnr = shownr + 1; |
792 |
|
|
} else { |
793 |
|
|
warnx("rule %ld not found", shownr); |
794 |
|
|
ret = -1; |
795 |
|
|
goto error; |
796 |
|
|
} |
797 |
|
|
for (; nr < mnr; ++nr) { |
798 |
|
|
pr.nr = nr; |
799 |
|
|
if (ioctl(dev, DIOCGETRULE, &pr)) { |
800 |
|
|
warn("DIOCGETRULE"); |
801 |
|
|
ret = -1; |
802 |
|
|
goto error; |
803 |
|
|
} |
804 |
|
|
|
805 |
|
|
/* anchor is the same for all rules in it */ |
806 |
|
|
if (pr.rule.anchor_wildcard == 0) |
807 |
|
|
wildcard = 0; |
808 |
|
|
|
809 |
|
|
switch (format) { |
810 |
|
|
case PFCTL_SHOW_LABELS: |
811 |
|
|
if (pr.rule.label[0]) { |
812 |
|
|
INDENT(depth, !(opts & PF_OPT_VERBOSE)); |
813 |
|
|
printf("%s %llu %llu %llu %llu" |
814 |
|
|
" %llu %llu %llu %llu\n", |
815 |
|
|
pr.rule.label, |
816 |
|
|
(unsigned long long)pr.rule.evaluations, |
817 |
|
|
(unsigned long long)(pr.rule.packets[0] + |
818 |
|
|
pr.rule.packets[1]), |
819 |
|
|
(unsigned long long)(pr.rule.bytes[0] + |
820 |
|
|
pr.rule.bytes[1]), |
821 |
|
|
(unsigned long long)pr.rule.packets[0], |
822 |
|
|
(unsigned long long)pr.rule.bytes[0], |
823 |
|
|
(unsigned long long)pr.rule.packets[1], |
824 |
|
|
(unsigned long long)pr.rule.bytes[1], |
825 |
|
|
(unsigned long long)pr.rule.states_tot); |
826 |
|
|
} |
827 |
|
|
break; |
828 |
|
|
case PFCTL_SHOW_RULES: |
829 |
|
|
if (pr.rule.label[0] && (opts & PF_OPT_SHOWALL)) |
830 |
|
|
labels = 1; |
831 |
|
|
INDENT(depth, !(opts & PF_OPT_VERBOSE)); |
832 |
|
|
print_rule(&pr.rule, pr.anchor_call, opts); |
833 |
|
|
|
834 |
|
|
/* |
835 |
|
|
* If this is an 'unnamed' brace notation anchor OR |
836 |
|
|
* the user has explicitly requested recursion, |
837 |
|
|
* print it recursively. |
838 |
|
|
*/ |
839 |
|
|
if (pr.anchor_call[0] && |
840 |
|
|
(((p = strrchr(pr.anchor_call, '/')) ? |
841 |
|
|
p[1] == '_' : pr.anchor_call[0] == '_') || |
842 |
|
|
opts & PF_OPT_RECURSE)) { |
843 |
|
|
printf(" {\n"); |
844 |
|
|
pfctl_print_rule_counters(&pr.rule, opts); |
845 |
|
|
pfctl_show_rules(dev, npath, opts, format, |
846 |
|
|
pr.anchor_call, depth + 1, |
847 |
|
|
pr.rule.anchor_wildcard, -1); |
848 |
|
|
INDENT(depth, !(opts & PF_OPT_VERBOSE)); |
849 |
|
|
printf("}\n"); |
850 |
|
|
} else { |
851 |
|
|
printf("\n"); |
852 |
|
|
pfctl_print_rule_counters(&pr.rule, opts); |
853 |
|
|
} |
854 |
|
|
break; |
855 |
|
|
case PFCTL_SHOW_NOTHING: |
856 |
|
|
break; |
857 |
|
|
} |
858 |
|
|
} |
859 |
|
|
|
860 |
|
|
/* |
861 |
|
|
* If this anchor was called with a wildcard path, go through |
862 |
|
|
* the rulesets in the anchor rather than the rules. |
863 |
|
|
*/ |
864 |
|
|
if (wildcard && (opts & PF_OPT_RECURSE)) { |
865 |
|
|
struct pfioc_ruleset prs; |
866 |
|
|
u_int32_t mnr, nr; |
867 |
|
|
|
868 |
|
|
memset(&prs, 0, sizeof(prs)); |
869 |
|
|
memcpy(prs.path, npath, sizeof(prs.path)); |
870 |
|
|
if (ioctl(dev, DIOCGETRULESETS, &prs)) { |
871 |
|
|
if (errno == EINVAL) |
872 |
|
|
fprintf(stderr, "Anchor '%s' " |
873 |
|
|
"not found.\n", anchorname); |
874 |
|
|
else |
875 |
|
|
err(1, "DIOCGETRULESETS"); |
876 |
|
|
} |
877 |
|
|
mnr = prs.nr; |
878 |
|
|
|
879 |
|
|
for (nr = 0; nr < mnr; ++nr) { |
880 |
|
|
prs.nr = nr; |
881 |
|
|
if (ioctl(dev, DIOCGETRULESET, &prs)) |
882 |
|
|
err(1, "DIOCGETRULESET"); |
883 |
|
|
INDENT(depth, !(opts & PF_OPT_VERBOSE)); |
884 |
|
|
printf("anchor \"%s\" all {\n", prs.name); |
885 |
|
|
pfctl_show_rules(dev, npath, opts, |
886 |
|
|
format, prs.name, depth + 1, 0, shownr); |
887 |
|
|
INDENT(depth, !(opts & PF_OPT_VERBOSE)); |
888 |
|
|
printf("}\n"); |
889 |
|
|
} |
890 |
|
|
path[len] = '\0'; |
891 |
|
|
return (0); |
892 |
|
|
} |
893 |
|
|
|
894 |
|
|
error: |
895 |
|
|
if (path != npath) |
896 |
|
|
free(npath); |
897 |
|
|
path[len] = '\0'; |
898 |
|
|
return (ret); |
899 |
|
|
} |
900 |
|
|
|
901 |
|
|
int |
902 |
|
|
pfctl_show_src_nodes(int dev, int opts) |
903 |
|
|
{ |
904 |
|
|
struct pfioc_src_nodes psn; |
905 |
|
|
struct pf_src_node *p; |
906 |
|
|
char *inbuf = NULL, *newinbuf = NULL; |
907 |
|
|
unsigned int len = 0; |
908 |
|
|
int i; |
909 |
|
|
|
910 |
|
|
memset(&psn, 0, sizeof(psn)); |
911 |
|
|
for (;;) { |
912 |
|
|
psn.psn_len = len; |
913 |
|
|
if (len) { |
914 |
|
|
newinbuf = realloc(inbuf, len); |
915 |
|
|
if (newinbuf == NULL) |
916 |
|
|
err(1, "realloc"); |
917 |
|
|
psn.psn_buf = inbuf = newinbuf; |
918 |
|
|
} |
919 |
|
|
if (ioctl(dev, DIOCGETSRCNODES, &psn) < 0) { |
920 |
|
|
warn("DIOCGETSRCNODES"); |
921 |
|
|
free(inbuf); |
922 |
|
|
return (-1); |
923 |
|
|
} |
924 |
|
|
if (psn.psn_len + sizeof(struct pfioc_src_nodes) < len) |
925 |
|
|
break; |
926 |
|
|
if (len == 0 && psn.psn_len == 0) |
927 |
|
|
goto done; |
928 |
|
|
if (len == 0 && psn.psn_len != 0) |
929 |
|
|
len = psn.psn_len; |
930 |
|
|
if (psn.psn_len == 0) |
931 |
|
|
goto done; /* no src_nodes */ |
932 |
|
|
len *= 2; |
933 |
|
|
} |
934 |
|
|
p = psn.psn_src_nodes; |
935 |
|
|
if (psn.psn_len > 0 && (opts & PF_OPT_SHOWALL)) |
936 |
|
|
pfctl_print_title("SOURCE TRACKING NODES:"); |
937 |
|
|
for (i = 0; i < psn.psn_len; i += sizeof(*p)) { |
938 |
|
|
print_src_node(p, opts); |
939 |
|
|
p++; |
940 |
|
|
} |
941 |
|
|
done: |
942 |
|
|
free(inbuf); |
943 |
|
|
return (0); |
944 |
|
|
} |
945 |
|
|
|
946 |
|
|
int |
947 |
|
|
pfctl_show_states(int dev, const char *iface, int opts, long shownr) |
948 |
|
|
{ |
949 |
|
|
struct pfioc_states ps; |
950 |
|
|
struct pfsync_state *p; |
951 |
|
|
char *inbuf = NULL, *newinbuf = NULL; |
952 |
|
|
unsigned int len = 0; |
953 |
|
|
int i, dotitle = (opts & PF_OPT_SHOWALL); |
954 |
|
|
|
955 |
|
|
memset(&ps, 0, sizeof(ps)); |
956 |
|
|
for (;;) { |
957 |
|
|
ps.ps_len = len; |
958 |
|
|
if (len) { |
959 |
|
|
newinbuf = realloc(inbuf, len); |
960 |
|
|
if (newinbuf == NULL) |
961 |
|
|
err(1, "realloc"); |
962 |
|
|
ps.ps_buf = inbuf = newinbuf; |
963 |
|
|
} |
964 |
|
|
if (ioctl(dev, DIOCGETSTATES, &ps) < 0) { |
965 |
|
|
warn("DIOCGETSTATES"); |
966 |
|
|
free(inbuf); |
967 |
|
|
return (-1); |
968 |
|
|
} |
969 |
|
|
if (ps.ps_len + sizeof(struct pfioc_states) < len) |
970 |
|
|
break; |
971 |
|
|
if (len == 0 && ps.ps_len == 0) |
972 |
|
|
goto done; |
973 |
|
|
if (len == 0 && ps.ps_len != 0) |
974 |
|
|
len = ps.ps_len; |
975 |
|
|
if (ps.ps_len == 0) |
976 |
|
|
goto done; /* no states */ |
977 |
|
|
len *= 2; |
978 |
|
|
} |
979 |
|
|
p = ps.ps_states; |
980 |
|
|
for (i = 0; i < ps.ps_len; i += sizeof(*p), p++) { |
981 |
|
|
if (iface != NULL && strcmp(p->ifname, iface)) |
982 |
|
|
continue; |
983 |
|
|
if (dotitle) { |
984 |
|
|
pfctl_print_title("STATES:"); |
985 |
|
|
dotitle = 0; |
986 |
|
|
} |
987 |
|
|
if (shownr < 0 || ntohl(p->rule) == shownr) |
988 |
|
|
print_state(p, opts); |
989 |
|
|
} |
990 |
|
|
done: |
991 |
|
|
free(inbuf); |
992 |
|
|
return (0); |
993 |
|
|
} |
994 |
|
|
|
995 |
|
|
int |
996 |
|
|
pfctl_show_status(int dev, int opts) |
997 |
|
|
{ |
998 |
|
|
struct pf_status status; |
999 |
|
|
|
1000 |
|
|
if (ioctl(dev, DIOCGETSTATUS, &status)) { |
1001 |
|
|
warn("DIOCGETSTATUS"); |
1002 |
|
|
return (-1); |
1003 |
|
|
} |
1004 |
|
|
if (opts & PF_OPT_SHOWALL) |
1005 |
|
|
pfctl_print_title("INFO:"); |
1006 |
|
|
print_status(&status, opts); |
1007 |
|
|
return (0); |
1008 |
|
|
} |
1009 |
|
|
|
1010 |
|
|
int |
1011 |
|
|
pfctl_show_timeouts(int dev, int opts) |
1012 |
|
|
{ |
1013 |
|
|
struct pfioc_tm pt; |
1014 |
|
|
int i; |
1015 |
|
|
|
1016 |
|
|
if (opts & PF_OPT_SHOWALL) |
1017 |
|
|
pfctl_print_title("TIMEOUTS:"); |
1018 |
|
|
memset(&pt, 0, sizeof(pt)); |
1019 |
|
|
for (i = 0; pf_timeouts[i].name; i++) { |
1020 |
|
|
pt.timeout = pf_timeouts[i].timeout; |
1021 |
|
|
if (ioctl(dev, DIOCGETTIMEOUT, &pt)) |
1022 |
|
|
err(1, "DIOCGETTIMEOUT"); |
1023 |
|
|
printf("%-20s %10d", pf_timeouts[i].name, pt.seconds); |
1024 |
|
|
if (pf_timeouts[i].timeout >= PFTM_ADAPTIVE_START && |
1025 |
|
|
pf_timeouts[i].timeout <= PFTM_ADAPTIVE_END) |
1026 |
|
|
printf(" states"); |
1027 |
|
|
else |
1028 |
|
|
printf("s"); |
1029 |
|
|
printf("\n"); |
1030 |
|
|
} |
1031 |
|
|
return (0); |
1032 |
|
|
|
1033 |
|
|
} |
1034 |
|
|
|
1035 |
|
|
int |
1036 |
|
|
pfctl_show_limits(int dev, int opts) |
1037 |
|
|
{ |
1038 |
|
|
struct pfioc_limit pl; |
1039 |
|
|
int i; |
1040 |
|
|
|
1041 |
|
|
if (opts & PF_OPT_SHOWALL) |
1042 |
|
|
pfctl_print_title("LIMITS:"); |
1043 |
|
|
memset(&pl, 0, sizeof(pl)); |
1044 |
|
|
for (i = 0; pf_limits[i].name; i++) { |
1045 |
|
|
pl.index = pf_limits[i].index; |
1046 |
|
|
if (ioctl(dev, DIOCGETLIMIT, &pl)) |
1047 |
|
|
err(1, "DIOCGETLIMIT"); |
1048 |
|
|
printf("%-13s ", pf_limits[i].name); |
1049 |
|
|
if (pl.limit == UINT_MAX) |
1050 |
|
|
printf("unlimited\n"); |
1051 |
|
|
else |
1052 |
|
|
printf("hard limit %8u\n", pl.limit); |
1053 |
|
|
} |
1054 |
|
|
return (0); |
1055 |
|
|
} |
1056 |
|
|
|
1057 |
|
|
/* callbacks for rule/nat/rdr/addr */ |
1058 |
|
|
int |
1059 |
|
|
pfctl_add_rule(struct pfctl *pf, struct pf_rule *r, const char *anchor_call) |
1060 |
|
|
{ |
1061 |
|
|
struct pf_rule *rule; |
1062 |
|
|
struct pf_ruleset *rs; |
1063 |
|
|
char *p; |
1064 |
|
|
|
1065 |
|
|
rs = &pf->anchor->ruleset; |
1066 |
|
|
if (anchor_call[0] && r->anchor == NULL) { |
1067 |
|
|
/* |
1068 |
|
|
* Don't make non-brace anchors part of the main anchor pool. |
1069 |
|
|
*/ |
1070 |
|
|
if ((r->anchor = calloc(1, sizeof(*r->anchor))) == NULL) |
1071 |
|
|
err(1, "pfctl_add_rule: calloc"); |
1072 |
|
|
|
1073 |
|
|
pf_init_ruleset(&r->anchor->ruleset); |
1074 |
|
|
r->anchor->ruleset.anchor = r->anchor; |
1075 |
|
|
if (strlcpy(r->anchor->path, anchor_call, |
1076 |
|
|
sizeof(rule->anchor->path)) >= sizeof(rule->anchor->path)) |
1077 |
|
|
errx(1, "pfctl_add_rule: strlcpy"); |
1078 |
|
|
if ((p = strrchr(anchor_call, '/')) != NULL) { |
1079 |
|
|
if (!strlen(p)) |
1080 |
|
|
err(1, "pfctl_add_rule: bad anchor name %s", |
1081 |
|
|
anchor_call); |
1082 |
|
|
} else |
1083 |
|
|
p = (char *)anchor_call; |
1084 |
|
|
if (strlcpy(r->anchor->name, p, |
1085 |
|
|
sizeof(rule->anchor->name)) >= sizeof(rule->anchor->name)) |
1086 |
|
|
errx(1, "pfctl_add_rule: strlcpy"); |
1087 |
|
|
} |
1088 |
|
|
|
1089 |
|
|
if ((rule = calloc(1, sizeof(*rule))) == NULL) |
1090 |
|
|
err(1, "calloc"); |
1091 |
|
|
bcopy(r, rule, sizeof(*rule)); |
1092 |
|
|
|
1093 |
|
|
TAILQ_INSERT_TAIL(rs->rules.active.ptr, rule, entries); |
1094 |
|
|
return (0); |
1095 |
|
|
} |
1096 |
|
|
|
1097 |
|
|
int |
1098 |
|
|
pfctl_ruleset_trans(struct pfctl *pf, char *path, struct pf_anchor *a) |
1099 |
|
|
{ |
1100 |
|
|
int osize = pf->trans->pfrb_size; |
1101 |
|
|
|
1102 |
|
|
if (pfctl_add_trans(pf->trans, PF_TRANS_RULESET, path)) |
1103 |
|
|
return (3); |
1104 |
|
|
if (pfctl_add_trans(pf->trans, PF_TRANS_TABLE, path)) |
1105 |
|
|
return (4); |
1106 |
|
|
if (pfctl_trans(pf->dev, pf->trans, DIOCXBEGIN, osize)) |
1107 |
|
|
return (5); |
1108 |
|
|
|
1109 |
|
|
return (0); |
1110 |
|
|
} |
1111 |
|
|
|
1112 |
|
|
int |
1113 |
|
|
pfctl_add_queue(struct pfctl *pf, struct pf_queuespec *q) |
1114 |
|
|
{ |
1115 |
|
|
struct pfctl_qsitem *qi; |
1116 |
|
|
|
1117 |
|
|
if (pf->anchor->name[0]) { |
1118 |
|
|
printf("must not have queue definitions in an anchor\n"); |
1119 |
|
|
return (1); |
1120 |
|
|
} |
1121 |
|
|
|
1122 |
|
|
if (q->parent[0] == '\0') { |
1123 |
|
|
TAILQ_FOREACH(qi, &rootqs, entries) { |
1124 |
|
|
if (strcmp(q->ifname, qi->qs.ifname)) |
1125 |
|
|
continue; |
1126 |
|
|
printf("A root queue is already defined on %s\n", |
1127 |
|
|
qi->qs.ifname); |
1128 |
|
|
return (1); |
1129 |
|
|
} |
1130 |
|
|
} |
1131 |
|
|
|
1132 |
|
|
if ((qi = calloc(1, sizeof(*qi))) == NULL) |
1133 |
|
|
err(1, "calloc"); |
1134 |
|
|
bcopy(q, &qi->qs, sizeof(qi->qs)); |
1135 |
|
|
TAILQ_INIT(&qi->children); |
1136 |
|
|
|
1137 |
|
|
if (qi->qs.parent[0]) |
1138 |
|
|
TAILQ_INSERT_TAIL(&qspecs, qi, entries); |
1139 |
|
|
else |
1140 |
|
|
TAILQ_INSERT_TAIL(&rootqs, qi, entries); |
1141 |
|
|
|
1142 |
|
|
return (0); |
1143 |
|
|
} |
1144 |
|
|
|
1145 |
|
|
struct pfctl_qsitem * |
1146 |
|
|
pfctl_find_queue(char *what, struct pf_qihead *where) |
1147 |
|
|
{ |
1148 |
|
|
struct pfctl_qsitem *q; |
1149 |
|
|
|
1150 |
|
|
TAILQ_FOREACH(q, where, entries) |
1151 |
|
|
if (strcmp(q->qs.qname, what) == 0) |
1152 |
|
|
return (q); |
1153 |
|
|
|
1154 |
|
|
return (NULL); |
1155 |
|
|
} |
1156 |
|
|
|
1157 |
|
|
u_int |
1158 |
|
|
pfctl_find_childqs(struct pfctl_qsitem *qi) |
1159 |
|
|
{ |
1160 |
|
|
struct pfctl_qsitem *n, *p, *q; |
1161 |
|
|
u_int flags = qi->qs.flags; |
1162 |
|
|
|
1163 |
|
|
TAILQ_FOREACH(p, &qspecs, entries) { |
1164 |
|
|
if (strcmp(p->qs.parent, qi->qs.qname)) |
1165 |
|
|
continue; |
1166 |
|
|
if (p->qs.ifname[0] && strcmp(p->qs.ifname, qi->qs.ifname)) |
1167 |
|
|
continue; |
1168 |
|
|
if (++p->matches > 10000) |
1169 |
|
|
errx(1, "pfctl_find_childqs: excessive matches, loop?"); |
1170 |
|
|
|
1171 |
|
|
if ((q = pfctl_find_queue(p->qs.qname, &qi->children)) == NULL) { |
1172 |
|
|
/* insert */ |
1173 |
|
|
if ((n = calloc(1, sizeof(*n))) == NULL) |
1174 |
|
|
err(1, "calloc"); |
1175 |
|
|
TAILQ_INIT(&n->children); |
1176 |
|
|
bcopy(&p->qs, &n->qs, sizeof(n->qs)); |
1177 |
|
|
TAILQ_INSERT_TAIL(&qi->children, n, entries); |
1178 |
|
|
} else { |
1179 |
|
|
if ((q->qs.ifname[0] && p->qs.ifname[0])) |
1180 |
|
|
errx(1, "queue %s on %s respecified", |
1181 |
|
|
q->qs.qname, q->qs.ifname); |
1182 |
|
|
if (!q->qs.ifname[0] && !p->qs.ifname[0]) |
1183 |
|
|
errx(1, "queue %s respecified", |
1184 |
|
|
q->qs.qname); |
1185 |
|
|
/* ifbound beats floating */ |
1186 |
|
|
if (!q->qs.ifname[0]) |
1187 |
|
|
bcopy(&p->qs, &q->qs, sizeof(q->qs)); |
1188 |
|
|
} |
1189 |
|
|
} |
1190 |
|
|
|
1191 |
|
|
TAILQ_FOREACH(p, &qi->children, entries) |
1192 |
|
|
flags |= pfctl_find_childqs(p); |
1193 |
|
|
|
1194 |
|
|
if (qi->qs.flags & HFSC_DEFAULTCLASS && !TAILQ_EMPTY(&qi->children)) |
1195 |
|
|
errx(1, "default queue %s is not a leaf queue", qi->qs.qname); |
1196 |
|
|
|
1197 |
|
|
return (flags); |
1198 |
|
|
} |
1199 |
|
|
|
1200 |
|
|
void |
1201 |
|
|
pfctl_load_queue(struct pfctl *pf, u_int32_t ticket, struct pfctl_qsitem *qi) |
1202 |
|
|
{ |
1203 |
|
|
struct pfioc_queue q; |
1204 |
|
|
struct pfctl_qsitem *p; |
1205 |
|
|
|
1206 |
|
|
q.ticket = ticket; |
1207 |
|
|
bcopy(&qi->qs, &q.queue, sizeof(q.queue)); |
1208 |
|
|
if ((pf->opts & PF_OPT_NOACTION) == 0) |
1209 |
|
|
if (ioctl(pf->dev, DIOCADDQUEUE, &q)) |
1210 |
|
|
err(1, "DIOCADDQUEUE"); |
1211 |
|
|
if (pf->opts & PF_OPT_VERBOSE) |
1212 |
|
|
print_queuespec(&qi->qs); |
1213 |
|
|
|
1214 |
|
|
TAILQ_FOREACH(p, &qi->children, entries) { |
1215 |
|
|
strlcpy(p->qs.ifname, qi->qs.ifname, IFNAMSIZ); |
1216 |
|
|
pfctl_load_queue(pf, ticket, p); |
1217 |
|
|
} |
1218 |
|
|
} |
1219 |
|
|
|
1220 |
|
|
int |
1221 |
|
|
pfctl_load_queues(struct pfctl *pf) |
1222 |
|
|
{ |
1223 |
|
|
struct pfctl_qsitem *qi, *tempqi, rqi; |
1224 |
|
|
u_int32_t ticket; |
1225 |
|
|
|
1226 |
|
|
TAILQ_FOREACH(qi, &qspecs, entries) { |
1227 |
|
|
if (qi->matches == 0) |
1228 |
|
|
errx(1, "queue %s: parent %s not found\n", qi->qs.qname, |
1229 |
|
|
qi->qs.parent); |
1230 |
|
|
if (qi->qs.realtime.m1.percent || qi->qs.realtime.m2.percent || |
1231 |
|
|
qi->qs.linkshare.m1.percent || |
1232 |
|
|
qi->qs.linkshare.m2.percent || |
1233 |
|
|
qi->qs.upperlimit.m1.percent || |
1234 |
|
|
qi->qs.upperlimit.m2.percent) |
1235 |
|
|
errx(1, "only absolute bandwidth specs for now"); |
1236 |
|
|
} |
1237 |
|
|
|
1238 |
|
|
if ((pf->opts & PF_OPT_NOACTION) == 0) |
1239 |
|
|
ticket = pfctl_get_ticket(pf->trans, PF_TRANS_RULESET, ""); |
1240 |
|
|
|
1241 |
|
|
TAILQ_FOREACH_SAFE(qi, &rootqs, entries, tempqi) { |
1242 |
|
|
TAILQ_REMOVE(&rootqs, qi, entries); |
1243 |
|
|
|
1244 |
|
|
/* |
1245 |
|
|
* We must have a hidden root queue below the user- |
1246 |
|
|
* specified/visible root queue, due to the way the |
1247 |
|
|
* dequeueing works far down there... don't ask. |
1248 |
|
|
* the _ namespace is reserved for these. |
1249 |
|
|
*/ |
1250 |
|
|
bzero(&rqi, sizeof(rqi)); |
1251 |
|
|
TAILQ_INIT(&rqi.children); |
1252 |
|
|
TAILQ_INSERT_TAIL(&rqi.children, qi, entries); |
1253 |
|
|
snprintf(rqi.qs.qname, PF_QNAME_SIZE, "_root_%s", |
1254 |
|
|
qi->qs.ifname); |
1255 |
|
|
strlcpy(rqi.qs.ifname, qi->qs.ifname, sizeof(rqi.qs.ifname)); |
1256 |
|
|
strlcpy(qi->qs.parent, rqi.qs.qname, sizeof(qi->qs.parent)); |
1257 |
|
|
|
1258 |
|
|
pfctl_load_queue(pf, ticket, &rqi); |
1259 |
|
|
|
1260 |
|
|
TAILQ_INSERT_HEAD(&rootqs, qi, entries); |
1261 |
|
|
} |
1262 |
|
|
|
1263 |
|
|
return (0); |
1264 |
|
|
} |
1265 |
|
|
|
1266 |
|
|
void |
1267 |
|
|
pfctl_clear_queues(struct pf_qihead *head) |
1268 |
|
|
{ |
1269 |
|
|
struct pfctl_qsitem *qi; |
1270 |
|
|
|
1271 |
|
|
while ((qi = TAILQ_FIRST(head)) != NULL) { |
1272 |
|
|
TAILQ_REMOVE(head, qi, entries); |
1273 |
|
|
pfctl_clear_queues(&qi->children); |
1274 |
|
|
free(qi); |
1275 |
|
|
} |
1276 |
|
|
} |
1277 |
|
|
|
1278 |
|
|
u_int |
1279 |
|
|
pfctl_leafqueue_check(char *qname) |
1280 |
|
|
{ |
1281 |
|
|
struct pfctl_qsitem *qi; |
1282 |
|
|
if (qname == NULL || qname[0] == 0) |
1283 |
|
|
return (0); |
1284 |
|
|
|
1285 |
|
|
TAILQ_FOREACH(qi, &rootqs, entries) { |
1286 |
|
|
if (strcmp(qname, qi->qs.qname)) |
1287 |
|
|
continue; |
1288 |
|
|
if (!TAILQ_EMPTY(&qi->children)) { |
1289 |
|
|
printf("queue %s: packets must be assigned to leaf " |
1290 |
|
|
"queues only\n", qname); |
1291 |
|
|
return (1); |
1292 |
|
|
} |
1293 |
|
|
} |
1294 |
|
|
TAILQ_FOREACH(qi, &qspecs, entries) { |
1295 |
|
|
if (strcmp(qname, qi->qs.qname)) |
1296 |
|
|
continue; |
1297 |
|
|
if (!TAILQ_EMPTY(&qi->children)) { |
1298 |
|
|
printf("queue %s: packets must be assigned to leaf " |
1299 |
|
|
"queues only\n", qname); |
1300 |
|
|
return (1); |
1301 |
|
|
} |
1302 |
|
|
} |
1303 |
|
|
return (0); |
1304 |
|
|
} |
1305 |
|
|
|
1306 |
|
|
u_int |
1307 |
|
|
pfctl_check_qassignments(struct pf_ruleset *rs) |
1308 |
|
|
{ |
1309 |
|
|
struct pf_rule *r; |
1310 |
|
|
struct pfctl_qsitem *qi; |
1311 |
|
|
u_int flags, errs = 0; |
1312 |
|
|
|
1313 |
|
|
/* main ruleset: need find_childqs to populate qi->children */ |
1314 |
|
|
if (rs->anchor->path[0] == 0) { |
1315 |
|
|
TAILQ_FOREACH(qi, &rootqs, entries) { |
1316 |
|
|
flags = pfctl_find_childqs(qi); |
1317 |
|
|
if (!(flags & HFSC_DEFAULTCLASS)) |
1318 |
|
|
errx(1, "no default queue specified"); |
1319 |
|
|
} |
1320 |
|
|
} |
1321 |
|
|
|
1322 |
|
|
TAILQ_FOREACH(r, rs->rules.active.ptr, entries) { |
1323 |
|
|
if (r->anchor) |
1324 |
|
|
errs += pfctl_check_qassignments(&r->anchor->ruleset); |
1325 |
|
|
if (pfctl_leafqueue_check(r->qname) || |
1326 |
|
|
pfctl_leafqueue_check(r->pqname)) |
1327 |
|
|
errs++; |
1328 |
|
|
} |
1329 |
|
|
return (errs); |
1330 |
|
|
} |
1331 |
|
|
|
1332 |
|
|
int |
1333 |
|
|
pfctl_load_ruleset(struct pfctl *pf, char *path, struct pf_ruleset *rs, |
1334 |
|
|
int depth) |
1335 |
|
|
{ |
1336 |
|
|
struct pf_rule *r; |
1337 |
|
|
int error, len = strlen(path); |
1338 |
|
|
int brace = 0; |
1339 |
|
|
|
1340 |
|
|
pf->anchor = rs->anchor; |
1341 |
|
|
|
1342 |
|
|
if (path[0]) |
1343 |
|
|
snprintf(&path[len], PATH_MAX - len, "/%s", pf->anchor->name); |
1344 |
|
|
else |
1345 |
|
|
snprintf(&path[len], PATH_MAX - len, "%s", pf->anchor->name); |
1346 |
|
|
|
1347 |
|
|
if (depth) { |
1348 |
|
|
if (TAILQ_FIRST(rs->rules.active.ptr) != NULL) { |
1349 |
|
|
brace++; |
1350 |
|
|
if (pf->opts & PF_OPT_VERBOSE) |
1351 |
|
|
printf(" {\n"); |
1352 |
|
|
if ((pf->opts & PF_OPT_NOACTION) == 0 && |
1353 |
|
|
(error = pfctl_ruleset_trans(pf, |
1354 |
|
|
path, rs->anchor))) { |
1355 |
|
|
printf("pfctl_load_rulesets: " |
1356 |
|
|
"pfctl_ruleset_trans %d\n", error); |
1357 |
|
|
goto error; |
1358 |
|
|
} |
1359 |
|
|
} else if (pf->opts & PF_OPT_VERBOSE) |
1360 |
|
|
printf("\n"); |
1361 |
|
|
|
1362 |
|
|
} |
1363 |
|
|
|
1364 |
|
|
if (pf->optimize) |
1365 |
|
|
pfctl_optimize_ruleset(pf, rs); |
1366 |
|
|
|
1367 |
|
|
while ((r = TAILQ_FIRST(rs->rules.active.ptr)) != NULL) { |
1368 |
|
|
TAILQ_REMOVE(rs->rules.active.ptr, r, entries); |
1369 |
|
|
if ((error = pfctl_load_rule(pf, path, r, depth))) |
1370 |
|
|
goto error; |
1371 |
|
|
if (r->anchor) { |
1372 |
|
|
if ((error = pfctl_load_ruleset(pf, path, |
1373 |
|
|
&r->anchor->ruleset, depth + 1))) |
1374 |
|
|
goto error; |
1375 |
|
|
} else if (pf->opts & PF_OPT_VERBOSE) |
1376 |
|
|
printf("\n"); |
1377 |
|
|
free(r); |
1378 |
|
|
} |
1379 |
|
|
if (brace && pf->opts & PF_OPT_VERBOSE) { |
1380 |
|
|
INDENT(depth - 1, (pf->opts & PF_OPT_VERBOSE)); |
1381 |
|
|
printf("}\n"); |
1382 |
|
|
} |
1383 |
|
|
path[len] = '\0'; |
1384 |
|
|
return (0); |
1385 |
|
|
|
1386 |
|
|
error: |
1387 |
|
|
path[len] = '\0'; |
1388 |
|
|
return (error); |
1389 |
|
|
|
1390 |
|
|
} |
1391 |
|
|
|
1392 |
|
|
int |
1393 |
|
|
pfctl_load_rule(struct pfctl *pf, char *path, struct pf_rule *r, int depth) |
1394 |
|
|
{ |
1395 |
|
|
char *name; |
1396 |
|
|
struct pfioc_rule pr; |
1397 |
|
|
int len = strlen(path); |
1398 |
|
|
|
1399 |
|
|
bzero(&pr, sizeof(pr)); |
1400 |
|
|
/* set up anchor before adding to path for anchor_call */ |
1401 |
|
|
if ((pf->opts & PF_OPT_NOACTION) == 0) |
1402 |
|
|
pr.ticket = pfctl_get_ticket(pf->trans, PF_TRANS_RULESET, path); |
1403 |
|
|
if (strlcpy(pr.anchor, path, sizeof(pr.anchor)) >= sizeof(pr.anchor)) |
1404 |
|
|
errx(1, "pfctl_load_rule: strlcpy"); |
1405 |
|
|
|
1406 |
|
|
if (r->anchor) { |
1407 |
|
|
if (r->anchor->match) { |
1408 |
|
|
if (path[0]) |
1409 |
|
|
snprintf(&path[len], PATH_MAX - len, |
1410 |
|
|
"/%s", r->anchor->name); |
1411 |
|
|
else |
1412 |
|
|
snprintf(&path[len], PATH_MAX - len, |
1413 |
|
|
"%s", r->anchor->name); |
1414 |
|
|
name = r->anchor->name; |
1415 |
|
|
} else |
1416 |
|
|
name = r->anchor->path; |
1417 |
|
|
} else |
1418 |
|
|
name = ""; |
1419 |
|
|
|
1420 |
|
|
if ((pf->opts & PF_OPT_NOACTION) == 0) { |
1421 |
|
|
memcpy(&pr.rule, r, sizeof(pr.rule)); |
1422 |
|
|
if (r->anchor && strlcpy(pr.anchor_call, name, |
1423 |
|
|
sizeof(pr.anchor_call)) >= sizeof(pr.anchor_call)) |
1424 |
|
|
errx(1, "pfctl_load_rule: strlcpy"); |
1425 |
|
|
if (ioctl(pf->dev, DIOCADDRULE, &pr)) |
1426 |
|
|
err(1, "DIOCADDRULE"); |
1427 |
|
|
} |
1428 |
|
|
|
1429 |
|
|
if (pf->opts & PF_OPT_VERBOSE) { |
1430 |
|
|
INDENT(depth, !(pf->opts & PF_OPT_VERBOSE2)); |
1431 |
|
|
print_rule(r, name, pf->opts); |
1432 |
|
|
} |
1433 |
|
|
path[len] = '\0'; |
1434 |
|
|
return (0); |
1435 |
|
|
} |
1436 |
|
|
|
1437 |
|
|
int |
1438 |
|
|
pfctl_rules(int dev, char *filename, int opts, int optimize, |
1439 |
|
|
char *anchorname, struct pfr_buffer *trans) |
1440 |
|
|
{ |
1441 |
|
|
#define ERR(x) do { warn(x); goto _error; } while(0) |
1442 |
|
|
#define ERRX(x) do { warnx(x); goto _error; } while(0) |
1443 |
|
|
|
1444 |
|
|
struct pfr_buffer *t, buf; |
1445 |
|
|
struct pfctl pf; |
1446 |
|
|
struct pf_ruleset *rs; |
1447 |
|
|
struct pfr_table trs; |
1448 |
|
|
char *path = NULL; |
1449 |
|
|
int osize; |
1450 |
|
|
|
1451 |
|
|
bzero(&pf, sizeof(pf)); |
1452 |
|
|
RB_INIT(&pf_anchors); |
1453 |
|
|
memset(&pf_main_anchor, 0, sizeof(pf_main_anchor)); |
1454 |
|
|
pf_init_ruleset(&pf_main_anchor.ruleset); |
1455 |
|
|
pf_main_anchor.ruleset.anchor = &pf_main_anchor; |
1456 |
|
|
if (trans == NULL) { |
1457 |
|
|
bzero(&buf, sizeof(buf)); |
1458 |
|
|
buf.pfrb_type = PFRB_TRANS; |
1459 |
|
|
t = &buf; |
1460 |
|
|
osize = 0; |
1461 |
|
|
} else { |
1462 |
|
|
t = trans; |
1463 |
|
|
osize = t->pfrb_size; |
1464 |
|
|
} |
1465 |
|
|
|
1466 |
|
|
memset(&pf, 0, sizeof(pf)); |
1467 |
|
|
memset(&trs, 0, sizeof(trs)); |
1468 |
|
|
if ((path = calloc(1, PATH_MAX)) == NULL) |
1469 |
|
|
ERRX("pfctl_rules: calloc"); |
1470 |
|
|
if (strlcpy(trs.pfrt_anchor, anchorname, |
1471 |
|
|
sizeof(trs.pfrt_anchor)) >= sizeof(trs.pfrt_anchor)) |
1472 |
|
|
ERRX("pfctl_rules: strlcpy"); |
1473 |
|
|
pf.dev = dev; |
1474 |
|
|
pf.opts = opts; |
1475 |
|
|
pf.optimize = optimize; |
1476 |
|
|
|
1477 |
|
|
/* non-brace anchor, create without resolving the path */ |
1478 |
|
|
if ((pf.anchor = calloc(1, sizeof(*pf.anchor))) == NULL) |
1479 |
|
|
ERRX("pfctl_rules: calloc"); |
1480 |
|
|
rs = &pf.anchor->ruleset; |
1481 |
|
|
pf_init_ruleset(rs); |
1482 |
|
|
rs->anchor = pf.anchor; |
1483 |
|
|
if (strlcpy(pf.anchor->path, anchorname, |
1484 |
|
|
sizeof(pf.anchor->path)) >= sizeof(pf.anchor->path)) |
1485 |
|
|
errx(1, "pfctl_add_rule: strlcpy"); |
1486 |
|
|
if (strlcpy(pf.anchor->name, anchorname, |
1487 |
|
|
sizeof(pf.anchor->name)) >= sizeof(pf.anchor->name)) |
1488 |
|
|
errx(1, "pfctl_add_rule: strlcpy"); |
1489 |
|
|
|
1490 |
|
|
|
1491 |
|
|
pf.astack[0] = pf.anchor; |
1492 |
|
|
pf.asd = 0; |
1493 |
|
|
pf.trans = t; |
1494 |
|
|
pfctl_init_options(&pf); |
1495 |
|
|
|
1496 |
|
|
if ((opts & PF_OPT_NOACTION) == 0) { |
1497 |
|
|
/* |
1498 |
|
|
* XXX For the time being we need to open transactions for |
1499 |
|
|
* the main ruleset before parsing, because tables are still |
1500 |
|
|
* loaded at parse time. |
1501 |
|
|
*/ |
1502 |
|
|
if (pfctl_ruleset_trans(&pf, anchorname, pf.anchor)) |
1503 |
|
|
ERRX("pfctl_rules"); |
1504 |
|
|
pf.astack[0]->ruleset.tticket = |
1505 |
|
|
pfctl_get_ticket(t, PF_TRANS_TABLE, anchorname); |
1506 |
|
|
} |
1507 |
|
|
|
1508 |
|
|
if (parse_config(filename, &pf) < 0) { |
1509 |
|
|
if ((opts & PF_OPT_NOACTION) == 0) |
1510 |
|
|
ERRX("Syntax error in config file: " |
1511 |
|
|
"pf rules not loaded"); |
1512 |
|
|
else |
1513 |
|
|
goto _error; |
1514 |
|
|
} |
1515 |
|
|
|
1516 |
|
|
if (!anchorname[0] && (pfctl_check_qassignments(&pf.anchor->ruleset) || |
1517 |
|
|
pfctl_load_queues(&pf))) { |
1518 |
|
|
if ((opts & PF_OPT_NOACTION) == 0) |
1519 |
|
|
ERRX("Unable to load queues into kernel"); |
1520 |
|
|
else |
1521 |
|
|
goto _error; |
1522 |
|
|
} |
1523 |
|
|
|
1524 |
|
|
if (pfctl_load_ruleset(&pf, path, rs, 0)) { |
1525 |
|
|
if ((opts & PF_OPT_NOACTION) == 0) |
1526 |
|
|
ERRX("Unable to load rules into kernel"); |
1527 |
|
|
else |
1528 |
|
|
goto _error; |
1529 |
|
|
} |
1530 |
|
|
|
1531 |
|
|
free(path); |
1532 |
|
|
path = NULL; |
1533 |
|
|
|
1534 |
|
|
/* process "load anchor" directives that might have used queues */ |
1535 |
|
|
if (!anchorname[0]) { |
1536 |
|
|
if (pfctl_load_anchors(dev, &pf, t) == -1) |
1537 |
|
|
ERRX("load anchors"); |
1538 |
|
|
pfctl_clear_queues(&qspecs); |
1539 |
|
|
pfctl_clear_queues(&rootqs); |
1540 |
|
|
} |
1541 |
|
|
|
1542 |
|
|
if (trans == NULL && (opts & PF_OPT_NOACTION) == 0) { |
1543 |
|
|
if (!anchorname[0]) |
1544 |
|
|
if (pfctl_load_options(&pf)) |
1545 |
|
|
goto _error; |
1546 |
|
|
if (pfctl_trans(dev, t, DIOCXCOMMIT, osize)) |
1547 |
|
|
ERR("DIOCXCOMMIT"); |
1548 |
|
|
} |
1549 |
|
|
return (0); |
1550 |
|
|
|
1551 |
|
|
_error: |
1552 |
|
|
if (trans == NULL) { /* main ruleset */ |
1553 |
|
|
if ((opts & PF_OPT_NOACTION) == 0) |
1554 |
|
|
if (pfctl_trans(dev, t, DIOCXROLLBACK, osize)) |
1555 |
|
|
err(1, "DIOCXROLLBACK"); |
1556 |
|
|
exit(1); |
1557 |
|
|
} else { /* sub ruleset */ |
1558 |
|
|
free(path); |
1559 |
|
|
return (-1); |
1560 |
|
|
} |
1561 |
|
|
|
1562 |
|
|
#undef ERR |
1563 |
|
|
#undef ERRX |
1564 |
|
|
} |
1565 |
|
|
|
1566 |
|
|
FILE * |
1567 |
|
|
pfctl_fopen(const char *name, const char *mode) |
1568 |
|
|
{ |
1569 |
|
|
struct stat st; |
1570 |
|
|
FILE *fp; |
1571 |
|
|
|
1572 |
|
|
fp = fopen(name, mode); |
1573 |
|
|
if (fp == NULL) |
1574 |
|
|
return (NULL); |
1575 |
|
|
if (fstat(fileno(fp), &st)) { |
1576 |
|
|
fclose(fp); |
1577 |
|
|
return (NULL); |
1578 |
|
|
} |
1579 |
|
|
if (S_ISDIR(st.st_mode)) { |
1580 |
|
|
fclose(fp); |
1581 |
|
|
errno = EISDIR; |
1582 |
|
|
return (NULL); |
1583 |
|
|
} |
1584 |
|
|
return (fp); |
1585 |
|
|
} |
1586 |
|
|
|
1587 |
|
|
void |
1588 |
|
|
pfctl_init_options(struct pfctl *pf) |
1589 |
|
|
{ |
1590 |
|
|
int64_t mem; |
1591 |
|
|
int mib[2], mcl; |
1592 |
|
|
size_t size; |
1593 |
|
|
|
1594 |
|
|
pf->timeout[PFTM_TCP_FIRST_PACKET] = PFTM_TCP_FIRST_PACKET_VAL; |
1595 |
|
|
pf->timeout[PFTM_TCP_OPENING] = PFTM_TCP_OPENING_VAL; |
1596 |
|
|
pf->timeout[PFTM_TCP_ESTABLISHED] = PFTM_TCP_ESTABLISHED_VAL; |
1597 |
|
|
pf->timeout[PFTM_TCP_CLOSING] = PFTM_TCP_CLOSING_VAL; |
1598 |
|
|
pf->timeout[PFTM_TCP_FIN_WAIT] = PFTM_TCP_FIN_WAIT_VAL; |
1599 |
|
|
pf->timeout[PFTM_TCP_CLOSED] = PFTM_TCP_CLOSED_VAL; |
1600 |
|
|
pf->timeout[PFTM_UDP_FIRST_PACKET] = PFTM_UDP_FIRST_PACKET_VAL; |
1601 |
|
|
pf->timeout[PFTM_UDP_SINGLE] = PFTM_UDP_SINGLE_VAL; |
1602 |
|
|
pf->timeout[PFTM_UDP_MULTIPLE] = PFTM_UDP_MULTIPLE_VAL; |
1603 |
|
|
pf->timeout[PFTM_ICMP_FIRST_PACKET] = PFTM_ICMP_FIRST_PACKET_VAL; |
1604 |
|
|
pf->timeout[PFTM_ICMP_ERROR_REPLY] = PFTM_ICMP_ERROR_REPLY_VAL; |
1605 |
|
|
pf->timeout[PFTM_OTHER_FIRST_PACKET] = PFTM_OTHER_FIRST_PACKET_VAL; |
1606 |
|
|
pf->timeout[PFTM_OTHER_SINGLE] = PFTM_OTHER_SINGLE_VAL; |
1607 |
|
|
pf->timeout[PFTM_OTHER_MULTIPLE] = PFTM_OTHER_MULTIPLE_VAL; |
1608 |
|
|
pf->timeout[PFTM_FRAG] = PFTM_FRAG_VAL; |
1609 |
|
|
pf->timeout[PFTM_INTERVAL] = PFTM_INTERVAL_VAL; |
1610 |
|
|
pf->timeout[PFTM_SRC_NODE] = PFTM_SRC_NODE_VAL; |
1611 |
|
|
pf->timeout[PFTM_TS_DIFF] = PFTM_TS_DIFF_VAL; |
1612 |
|
|
pf->timeout[PFTM_ADAPTIVE_START] = PFSTATE_ADAPT_START; |
1613 |
|
|
pf->timeout[PFTM_ADAPTIVE_END] = PFSTATE_ADAPT_END; |
1614 |
|
|
|
1615 |
|
|
pf->limit[PF_LIMIT_STATES] = PFSTATE_HIWAT; |
1616 |
|
|
|
1617 |
|
|
mib[0] = CTL_KERN; |
1618 |
|
|
mib[1] = KERN_MAXCLUSTERS; |
1619 |
|
|
size = sizeof(mcl); |
1620 |
|
|
if (sysctl(mib, 2, &mcl, &size, NULL, 0) == -1) |
1621 |
|
|
err(1, "sysctl"); |
1622 |
|
|
pf->limit[PF_LIMIT_FRAGS] = mcl / 4; |
1623 |
|
|
|
1624 |
|
|
pf->limit[PF_LIMIT_SRC_NODES] = PFSNODE_HIWAT; |
1625 |
|
|
pf->limit[PF_LIMIT_TABLES] = PFR_KTABLE_HIWAT; |
1626 |
|
|
pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT; |
1627 |
|
|
|
1628 |
|
|
mib[0] = CTL_HW; |
1629 |
|
|
mib[1] = HW_PHYSMEM64; |
1630 |
|
|
size = sizeof(mem); |
1631 |
|
|
if (sysctl(mib, 2, &mem, &size, NULL, 0) == -1) |
1632 |
|
|
err(1, "sysctl"); |
1633 |
|
|
if (mem <= 100*1024*1024) |
1634 |
|
|
pf->limit[PF_LIMIT_TABLE_ENTRIES] = PFR_KENTRY_HIWAT_SMALL; |
1635 |
|
|
|
1636 |
|
|
pf->debug = LOG_ERR; |
1637 |
|
|
pf->debug_set = 0; |
1638 |
|
|
pf->reassemble = PF_REASS_ENABLED; |
1639 |
|
|
} |
1640 |
|
|
|
1641 |
|
|
int |
1642 |
|
|
pfctl_load_options(struct pfctl *pf) |
1643 |
|
|
{ |
1644 |
|
|
int i, error = 0; |
1645 |
|
|
|
1646 |
|
|
/* load limits */ |
1647 |
|
|
for (i = 0; i < PF_LIMIT_MAX; i++) |
1648 |
|
|
if (pfctl_load_limit(pf, i, pf->limit[i])) |
1649 |
|
|
error = 1; |
1650 |
|
|
|
1651 |
|
|
/* |
1652 |
|
|
* If we've set the limit, but haven't explicitly set adaptive |
1653 |
|
|
* timeouts, do it now with a start of 60% and end of 120%. |
1654 |
|
|
*/ |
1655 |
|
|
if (pf->limit_set[PF_LIMIT_STATES] && |
1656 |
|
|
!pf->timeout_set[PFTM_ADAPTIVE_START] && |
1657 |
|
|
!pf->timeout_set[PFTM_ADAPTIVE_END]) { |
1658 |
|
|
pf->timeout[PFTM_ADAPTIVE_START] = |
1659 |
|
|
(pf->limit[PF_LIMIT_STATES] / 10) * 6; |
1660 |
|
|
pf->timeout_set[PFTM_ADAPTIVE_START] = 1; |
1661 |
|
|
pf->timeout[PFTM_ADAPTIVE_END] = |
1662 |
|
|
(pf->limit[PF_LIMIT_STATES] / 10) * 12; |
1663 |
|
|
pf->timeout_set[PFTM_ADAPTIVE_END] = 1; |
1664 |
|
|
} |
1665 |
|
|
|
1666 |
|
|
/* load timeouts */ |
1667 |
|
|
for (i = 0; i < PFTM_MAX; i++) |
1668 |
|
|
if (pfctl_load_timeout(pf, i, pf->timeout[i])) |
1669 |
|
|
error = 1; |
1670 |
|
|
|
1671 |
|
|
/* load debug */ |
1672 |
|
|
if (pf->debug_set && pfctl_load_debug(pf, pf->debug)) |
1673 |
|
|
error = 1; |
1674 |
|
|
|
1675 |
|
|
/* load logif */ |
1676 |
|
|
if (pf->ifname_set && pfctl_load_logif(pf, pf->ifname)) |
1677 |
|
|
error = 1; |
1678 |
|
|
|
1679 |
|
|
/* load hostid */ |
1680 |
|
|
if (pf->hostid_set && pfctl_load_hostid(pf, pf->hostid)) |
1681 |
|
|
error = 1; |
1682 |
|
|
|
1683 |
|
|
/* load reassembly settings */ |
1684 |
|
|
if (pf->reass_set && pfctl_load_reassembly(pf, pf->reassemble)) |
1685 |
|
|
error = 1; |
1686 |
|
|
|
1687 |
|
|
return (error); |
1688 |
|
|
} |
1689 |
|
|
|
1690 |
|
|
int |
1691 |
|
|
pfctl_set_limit(struct pfctl *pf, const char *opt, unsigned int limit) |
1692 |
|
|
{ |
1693 |
|
|
int i; |
1694 |
|
|
|
1695 |
|
|
|
1696 |
|
|
for (i = 0; pf_limits[i].name; i++) { |
1697 |
|
|
if (strcasecmp(opt, pf_limits[i].name) == 0) { |
1698 |
|
|
pf->limit[pf_limits[i].index] = limit; |
1699 |
|
|
pf->limit_set[pf_limits[i].index] = 1; |
1700 |
|
|
break; |
1701 |
|
|
} |
1702 |
|
|
} |
1703 |
|
|
if (pf_limits[i].name == NULL) { |
1704 |
|
|
warnx("Bad pool name."); |
1705 |
|
|
return (1); |
1706 |
|
|
} |
1707 |
|
|
|
1708 |
|
|
if (pf->opts & PF_OPT_VERBOSE) |
1709 |
|
|
printf("set limit %s %d\n", opt, limit); |
1710 |
|
|
|
1711 |
|
|
return (0); |
1712 |
|
|
} |
1713 |
|
|
|
1714 |
|
|
int |
1715 |
|
|
pfctl_load_limit(struct pfctl *pf, unsigned int index, unsigned int limit) |
1716 |
|
|
{ |
1717 |
|
|
struct pfioc_limit pl; |
1718 |
|
|
|
1719 |
|
|
memset(&pl, 0, sizeof(pl)); |
1720 |
|
|
pl.index = index; |
1721 |
|
|
pl.limit = limit; |
1722 |
|
|
if (ioctl(pf->dev, DIOCSETLIMIT, &pl)) { |
1723 |
|
|
if (errno == EBUSY) |
1724 |
|
|
warnx("Current pool size exceeds requested %s limit %u", |
1725 |
|
|
pf_limits[index].name, limit); |
1726 |
|
|
else |
1727 |
|
|
warnx("Cannot set %s limit to %u", |
1728 |
|
|
pf_limits[index].name, limit); |
1729 |
|
|
return (1); |
1730 |
|
|
} |
1731 |
|
|
return (0); |
1732 |
|
|
} |
1733 |
|
|
|
1734 |
|
|
int |
1735 |
|
|
pfctl_set_timeout(struct pfctl *pf, const char *opt, int seconds, int quiet) |
1736 |
|
|
{ |
1737 |
|
|
int i; |
1738 |
|
|
|
1739 |
|
|
for (i = 0; pf_timeouts[i].name; i++) { |
1740 |
|
|
if (strcasecmp(opt, pf_timeouts[i].name) == 0) { |
1741 |
|
|
pf->timeout[pf_timeouts[i].timeout] = seconds; |
1742 |
|
|
pf->timeout_set[pf_timeouts[i].timeout] = 1; |
1743 |
|
|
break; |
1744 |
|
|
} |
1745 |
|
|
} |
1746 |
|
|
|
1747 |
|
|
if (pf_timeouts[i].name == NULL) { |
1748 |
|
|
warnx("Bad timeout name."); |
1749 |
|
|
return (1); |
1750 |
|
|
} |
1751 |
|
|
|
1752 |
|
|
|
1753 |
|
|
if (pf->opts & PF_OPT_VERBOSE && ! quiet) |
1754 |
|
|
printf("set timeout %s %d\n", opt, seconds); |
1755 |
|
|
|
1756 |
|
|
return (0); |
1757 |
|
|
} |
1758 |
|
|
|
1759 |
|
|
int |
1760 |
|
|
pfctl_load_timeout(struct pfctl *pf, unsigned int timeout, unsigned int seconds) |
1761 |
|
|
{ |
1762 |
|
|
struct pfioc_tm pt; |
1763 |
|
|
|
1764 |
|
|
memset(&pt, 0, sizeof(pt)); |
1765 |
|
|
pt.timeout = timeout; |
1766 |
|
|
pt.seconds = seconds; |
1767 |
|
|
if (ioctl(pf->dev, DIOCSETTIMEOUT, &pt)) { |
1768 |
|
|
warnx("DIOCSETTIMEOUT"); |
1769 |
|
|
return (1); |
1770 |
|
|
} |
1771 |
|
|
return (0); |
1772 |
|
|
} |
1773 |
|
|
|
1774 |
|
|
int |
1775 |
|
|
pfctl_set_reassembly(struct pfctl *pf, int on, int nodf) |
1776 |
|
|
{ |
1777 |
|
|
pf->reass_set = 1; |
1778 |
|
|
if (on) { |
1779 |
|
|
pf->reassemble = PF_REASS_ENABLED; |
1780 |
|
|
if (nodf) |
1781 |
|
|
pf->reassemble |= PF_REASS_NODF; |
1782 |
|
|
} else { |
1783 |
|
|
pf->reassemble = 0; |
1784 |
|
|
} |
1785 |
|
|
|
1786 |
|
|
if (pf->opts & PF_OPT_VERBOSE) |
1787 |
|
|
printf("set reassemble %s %s\n", on ? "yes" : "no", |
1788 |
|
|
nodf ? "no-df" : ""); |
1789 |
|
|
|
1790 |
|
|
return (0); |
1791 |
|
|
} |
1792 |
|
|
|
1793 |
|
|
int |
1794 |
|
|
pfctl_set_optimization(struct pfctl *pf, const char *opt) |
1795 |
|
|
{ |
1796 |
|
|
const struct pf_hint *hint; |
1797 |
|
|
int i, r; |
1798 |
|
|
|
1799 |
|
|
for (i = 0; pf_hints[i].name; i++) |
1800 |
|
|
if (strcasecmp(opt, pf_hints[i].name) == 0) |
1801 |
|
|
break; |
1802 |
|
|
|
1803 |
|
|
hint = pf_hints[i].hint; |
1804 |
|
|
if (hint == NULL) { |
1805 |
|
|
warnx("invalid state timeouts optimization"); |
1806 |
|
|
return (1); |
1807 |
|
|
} |
1808 |
|
|
|
1809 |
|
|
for (i = 0; hint[i].name; i++) |
1810 |
|
|
if ((r = pfctl_set_timeout(pf, hint[i].name, |
1811 |
|
|
hint[i].timeout, 1))) |
1812 |
|
|
return (r); |
1813 |
|
|
|
1814 |
|
|
if (pf->opts & PF_OPT_VERBOSE) |
1815 |
|
|
printf("set optimization %s\n", opt); |
1816 |
|
|
|
1817 |
|
|
return (0); |
1818 |
|
|
} |
1819 |
|
|
|
1820 |
|
|
int |
1821 |
|
|
pfctl_set_logif(struct pfctl *pf, char *ifname) |
1822 |
|
|
{ |
1823 |
|
|
if (!strcmp(ifname, "none")) { |
1824 |
|
|
free(pf->ifname); |
1825 |
|
|
pf->ifname = NULL; |
1826 |
|
|
} else { |
1827 |
|
|
pf->ifname = strdup(ifname); |
1828 |
|
|
if (!pf->ifname) |
1829 |
|
|
errx(1, "pfctl_set_logif: strdup"); |
1830 |
|
|
} |
1831 |
|
|
pf->ifname_set = 1; |
1832 |
|
|
|
1833 |
|
|
if (pf->opts & PF_OPT_VERBOSE) |
1834 |
|
|
printf("set loginterface %s\n", ifname); |
1835 |
|
|
|
1836 |
|
|
return (0); |
1837 |
|
|
} |
1838 |
|
|
|
1839 |
|
|
int |
1840 |
|
|
pfctl_load_logif(struct pfctl *pf, char *ifname) |
1841 |
|
|
{ |
1842 |
|
|
struct pfioc_iface pi; |
1843 |
|
|
|
1844 |
|
|
memset(&pi, 0, sizeof(pi)); |
1845 |
|
|
if (ifname && strlcpy(pi.pfiio_name, ifname, |
1846 |
|
|
sizeof(pi.pfiio_name)) >= sizeof(pi.pfiio_name)) { |
1847 |
|
|
warnx("pfctl_load_logif: strlcpy"); |
1848 |
|
|
return (1); |
1849 |
|
|
} |
1850 |
|
|
if (ioctl(pf->dev, DIOCSETSTATUSIF, &pi)) { |
1851 |
|
|
warnx("DIOCSETSTATUSIF"); |
1852 |
|
|
return (1); |
1853 |
|
|
} |
1854 |
|
|
return (0); |
1855 |
|
|
} |
1856 |
|
|
|
1857 |
|
|
void |
1858 |
|
|
pfctl_set_hostid(struct pfctl *pf, u_int32_t hostid) |
1859 |
|
|
{ |
1860 |
|
|
HTONL(hostid); |
1861 |
|
|
|
1862 |
|
|
pf->hostid = hostid; |
1863 |
|
|
pf->hostid_set = 1; |
1864 |
|
|
|
1865 |
|
|
if (pf->opts & PF_OPT_VERBOSE) |
1866 |
|
|
printf("set hostid 0x%08x\n", ntohl(hostid)); |
1867 |
|
|
} |
1868 |
|
|
|
1869 |
|
|
int |
1870 |
|
|
pfctl_load_hostid(struct pfctl *pf, u_int32_t hostid) |
1871 |
|
|
{ |
1872 |
|
|
if (ioctl(dev, DIOCSETHOSTID, &hostid)) { |
1873 |
|
|
warnx("DIOCSETHOSTID"); |
1874 |
|
|
return (1); |
1875 |
|
|
} |
1876 |
|
|
return (0); |
1877 |
|
|
} |
1878 |
|
|
|
1879 |
|
|
int |
1880 |
|
|
pfctl_load_reassembly(struct pfctl *pf, u_int32_t reassembly) |
1881 |
|
|
{ |
1882 |
|
|
if (ioctl(dev, DIOCSETREASS, &reassembly)) { |
1883 |
|
|
warnx("DIOCSETREASS"); |
1884 |
|
|
return (1); |
1885 |
|
|
} |
1886 |
|
|
return (0); |
1887 |
|
|
} |
1888 |
|
|
|
1889 |
|
|
int |
1890 |
|
|
pfctl_set_debug(struct pfctl *pf, char *d) |
1891 |
|
|
{ |
1892 |
|
|
u_int32_t level; |
1893 |
|
|
int loglevel; |
1894 |
|
|
|
1895 |
|
|
if ((loglevel = string_to_loglevel(d)) >= 0) |
1896 |
|
|
level = loglevel; |
1897 |
|
|
else { |
1898 |
|
|
warnx("unknown debug level \"%s\"", d); |
1899 |
|
|
return (-1); |
1900 |
|
|
} |
1901 |
|
|
pf->debug = level; |
1902 |
|
|
pf->debug_set = 1; |
1903 |
|
|
|
1904 |
|
|
if ((pf->opts & PF_OPT_NOACTION) == 0) |
1905 |
|
|
if (ioctl(dev, DIOCSETDEBUG, &level)) |
1906 |
|
|
err(1, "DIOCSETDEBUG"); |
1907 |
|
|
|
1908 |
|
|
if (pf->opts & PF_OPT_VERBOSE) |
1909 |
|
|
printf("set debug %s\n", d); |
1910 |
|
|
|
1911 |
|
|
return (0); |
1912 |
|
|
} |
1913 |
|
|
|
1914 |
|
|
int |
1915 |
|
|
pfctl_load_debug(struct pfctl *pf, unsigned int level) |
1916 |
|
|
{ |
1917 |
|
|
if (ioctl(pf->dev, DIOCSETDEBUG, &level)) { |
1918 |
|
|
warnx("DIOCSETDEBUG"); |
1919 |
|
|
return (1); |
1920 |
|
|
} |
1921 |
|
|
return (0); |
1922 |
|
|
} |
1923 |
|
|
|
1924 |
|
|
int |
1925 |
|
|
pfctl_set_interface_flags(struct pfctl *pf, char *ifname, int flags, int how) |
1926 |
|
|
{ |
1927 |
|
|
struct pfioc_iface pi; |
1928 |
|
|
|
1929 |
|
|
bzero(&pi, sizeof(pi)); |
1930 |
|
|
|
1931 |
|
|
pi.pfiio_flags = flags; |
1932 |
|
|
|
1933 |
|
|
if (strlcpy(pi.pfiio_name, ifname, sizeof(pi.pfiio_name)) >= |
1934 |
|
|
sizeof(pi.pfiio_name)) |
1935 |
|
|
errx(1, "pfctl_set_interface_flags: strlcpy"); |
1936 |
|
|
|
1937 |
|
|
if ((pf->opts & PF_OPT_NOACTION) == 0) { |
1938 |
|
|
if (how == 0) { |
1939 |
|
|
if (ioctl(pf->dev, DIOCCLRIFFLAG, &pi)) |
1940 |
|
|
err(1, "DIOCCLRIFFLAG"); |
1941 |
|
|
} else { |
1942 |
|
|
if (ioctl(pf->dev, DIOCSETIFFLAG, &pi)) |
1943 |
|
|
err(1, "DIOCSETIFFLAG"); |
1944 |
|
|
} |
1945 |
|
|
} |
1946 |
|
|
return (0); |
1947 |
|
|
} |
1948 |
|
|
|
1949 |
|
|
void |
1950 |
|
|
pfctl_debug(int dev, u_int32_t level, int opts) |
1951 |
|
|
{ |
1952 |
|
|
struct pfr_buffer t; |
1953 |
|
|
|
1954 |
|
|
memset(&t, 0, sizeof(t)); |
1955 |
|
|
t.pfrb_type = PFRB_TRANS; |
1956 |
|
|
if (pfctl_trans(dev, &t, DIOCXBEGIN, 0) || |
1957 |
|
|
ioctl(dev, DIOCSETDEBUG, &level) || |
1958 |
|
|
pfctl_trans(dev, &t, DIOCXCOMMIT, 0)) |
1959 |
|
|
err(1, "pfctl_debug ioctl"); |
1960 |
|
|
|
1961 |
|
|
if ((opts & PF_OPT_QUIET) == 0) |
1962 |
|
|
fprintf(stderr, "debug level set to '%s'\n", |
1963 |
|
|
loglevel_to_string(level)); |
1964 |
|
|
} |
1965 |
|
|
|
1966 |
|
|
int |
1967 |
|
|
pfctl_show_anchors(int dev, int opts, char *anchorname) |
1968 |
|
|
{ |
1969 |
|
|
struct pfioc_ruleset pr; |
1970 |
|
|
u_int32_t mnr, nr; |
1971 |
|
|
|
1972 |
|
|
memset(&pr, 0, sizeof(pr)); |
1973 |
|
|
memcpy(pr.path, anchorname, sizeof(pr.path)); |
1974 |
|
|
if (ioctl(dev, DIOCGETRULESETS, &pr)) { |
1975 |
|
|
if (errno == EINVAL) |
1976 |
|
|
fprintf(stderr, "Anchor '%s' not found.\n", |
1977 |
|
|
anchorname); |
1978 |
|
|
else |
1979 |
|
|
err(1, "DIOCGETRULESETS"); |
1980 |
|
|
return (-1); |
1981 |
|
|
} |
1982 |
|
|
mnr = pr.nr; |
1983 |
|
|
for (nr = 0; nr < mnr; ++nr) { |
1984 |
|
|
char sub[PATH_MAX]; |
1985 |
|
|
|
1986 |
|
|
pr.nr = nr; |
1987 |
|
|
if (ioctl(dev, DIOCGETRULESET, &pr)) |
1988 |
|
|
err(1, "DIOCGETRULESET"); |
1989 |
|
|
if (!strcmp(pr.name, PF_RESERVED_ANCHOR)) |
1990 |
|
|
continue; |
1991 |
|
|
sub[0] = 0; |
1992 |
|
|
if (pr.path[0]) { |
1993 |
|
|
strlcat(sub, pr.path, sizeof(sub)); |
1994 |
|
|
strlcat(sub, "/", sizeof(sub)); |
1995 |
|
|
} |
1996 |
|
|
strlcat(sub, pr.name, sizeof(sub)); |
1997 |
|
|
if (sub[0] != '_' || (opts & PF_OPT_VERBOSE)) |
1998 |
|
|
printf(" %s\n", sub); |
1999 |
|
|
if ((opts & PF_OPT_VERBOSE) && pfctl_show_anchors(dev, opts, sub)) |
2000 |
|
|
return (-1); |
2001 |
|
|
} |
2002 |
|
|
return (0); |
2003 |
|
|
} |
2004 |
|
|
|
2005 |
|
|
const char * |
2006 |
|
|
pfctl_lookup_option(char *cmd, const char **list) |
2007 |
|
|
{ |
2008 |
|
|
const char *item = NULL; |
2009 |
|
|
if (cmd != NULL && *cmd) |
2010 |
|
|
for (; *list; list++) |
2011 |
|
|
if (!strncmp(cmd, *list, strlen(cmd))) { |
2012 |
|
|
if (item == NULL) |
2013 |
|
|
item = *list; |
2014 |
|
|
else |
2015 |
|
|
errx(1, "%s is ambigious", cmd); |
2016 |
|
|
} |
2017 |
|
|
|
2018 |
|
|
return (item); |
2019 |
|
|
} |
2020 |
|
|
|
2021 |
|
|
|
2022 |
|
|
void |
2023 |
|
|
pfctl_state_store(int dev, const char *file) |
2024 |
|
|
{ |
2025 |
|
|
FILE *f; |
2026 |
|
|
struct pfioc_states ps; |
2027 |
|
|
char *inbuf = NULL, *newinbuf = NULL; |
2028 |
|
|
unsigned int len = 0; |
2029 |
|
|
size_t n; |
2030 |
|
|
|
2031 |
|
|
f = fopen(file, "w"); |
2032 |
|
|
if (f == NULL) |
2033 |
|
|
err(1, "open: %s", file); |
2034 |
|
|
|
2035 |
|
|
memset(&ps, 0, sizeof(ps)); |
2036 |
|
|
for (;;) { |
2037 |
|
|
ps.ps_len = len; |
2038 |
|
|
if (len) { |
2039 |
|
|
newinbuf = realloc(inbuf, len); |
2040 |
|
|
if (newinbuf == NULL) |
2041 |
|
|
err(1, "realloc"); |
2042 |
|
|
ps.ps_buf = inbuf = newinbuf; |
2043 |
|
|
} |
2044 |
|
|
if (ioctl(dev, DIOCGETSTATES, &ps) < 0) |
2045 |
|
|
err(1, "DIOCGETSTATES"); |
2046 |
|
|
|
2047 |
|
|
if (ps.ps_len + sizeof(struct pfioc_states) < len) |
2048 |
|
|
break; |
2049 |
|
|
if (len == 0 && ps.ps_len == 0) |
2050 |
|
|
goto done; |
2051 |
|
|
if (len == 0 && ps.ps_len != 0) |
2052 |
|
|
len = ps.ps_len; |
2053 |
|
|
if (ps.ps_len == 0) |
2054 |
|
|
goto done; /* no states */ |
2055 |
|
|
len *= 2; |
2056 |
|
|
} |
2057 |
|
|
|
2058 |
|
|
n = ps.ps_len / sizeof(struct pfsync_state); |
2059 |
|
|
if (fwrite(inbuf, sizeof(struct pfsync_state), n, f) < n) |
2060 |
|
|
err(1, "fwrite"); |
2061 |
|
|
|
2062 |
|
|
done: |
2063 |
|
|
free(inbuf); |
2064 |
|
|
fclose(f); |
2065 |
|
|
} |
2066 |
|
|
|
2067 |
|
|
void |
2068 |
|
|
pfctl_state_load(int dev, const char *file) |
2069 |
|
|
{ |
2070 |
|
|
FILE *f; |
2071 |
|
|
struct pfioc_state ps; |
2072 |
|
|
|
2073 |
|
|
f = fopen(file, "r"); |
2074 |
|
|
if (f == NULL) |
2075 |
|
|
err(1, "open: %s", file); |
2076 |
|
|
|
2077 |
|
|
while (fread(&ps.state, sizeof(ps.state), 1, f) == 1) { |
2078 |
|
|
if (ioctl(dev, DIOCADDSTATE, &ps) < 0) { |
2079 |
|
|
switch (errno) { |
2080 |
|
|
case EEXIST: |
2081 |
|
|
case EINVAL: |
2082 |
|
|
break; |
2083 |
|
|
default: |
2084 |
|
|
err(1, "DIOCADDSTATE"); |
2085 |
|
|
} |
2086 |
|
|
} |
2087 |
|
|
} |
2088 |
|
|
|
2089 |
|
|
fclose(f); |
2090 |
|
|
} |
2091 |
|
|
|
2092 |
|
|
int |
2093 |
|
|
main(int argc, char *argv[]) |
2094 |
|
|
{ |
2095 |
|
|
int error = 0; |
2096 |
|
|
int ch; |
2097 |
|
|
int mode = O_RDONLY; |
2098 |
|
|
int opts = 0; |
2099 |
|
|
int optimize = PF_OPTIMIZE_BASIC; |
2100 |
|
|
int level; |
2101 |
|
|
char anchorname[PATH_MAX]; |
2102 |
|
|
int anchor_wildcard = 0; |
2103 |
|
|
char *path; |
2104 |
|
|
char *lfile = NULL, *sfile = NULL; |
2105 |
|
|
const char *errstr; |
2106 |
|
|
long shownr = -1; |
2107 |
|
|
|
2108 |
|
|
if (argc < 2) |
2109 |
|
|
usage(); |
2110 |
|
|
|
2111 |
|
|
while ((ch = getopt(argc, argv, |
2112 |
|
|
"a:dD:eqf:F:ghi:k:K:L:no:Pp:R:rS:s:t:T:vx:z")) != -1) { |
2113 |
|
|
switch (ch) { |
2114 |
|
|
case 'a': |
2115 |
|
|
anchoropt = optarg; |
2116 |
|
|
break; |
2117 |
|
|
case 'd': |
2118 |
|
|
opts |= PF_OPT_DISABLE; |
2119 |
|
|
mode = O_RDWR; |
2120 |
|
|
break; |
2121 |
|
|
case 'D': |
2122 |
|
|
if (pfctl_cmdline_symset(optarg) < 0) |
2123 |
|
|
warnx("could not parse macro definition %s", |
2124 |
|
|
optarg); |
2125 |
|
|
break; |
2126 |
|
|
case 'e': |
2127 |
|
|
opts |= PF_OPT_ENABLE; |
2128 |
|
|
mode = O_RDWR; |
2129 |
|
|
break; |
2130 |
|
|
case 'q': |
2131 |
|
|
opts |= PF_OPT_QUIET; |
2132 |
|
|
break; |
2133 |
|
|
case 'F': |
2134 |
|
|
clearopt = pfctl_lookup_option(optarg, clearopt_list); |
2135 |
|
|
if (clearopt == NULL) { |
2136 |
|
|
warnx("Unknown flush modifier '%s'", optarg); |
2137 |
|
|
usage(); |
2138 |
|
|
} |
2139 |
|
|
mode = O_RDWR; |
2140 |
|
|
break; |
2141 |
|
|
case 'i': |
2142 |
|
|
ifaceopt = optarg; |
2143 |
|
|
break; |
2144 |
|
|
case 'k': |
2145 |
|
|
if (state_killers >= 2) { |
2146 |
|
|
warnx("can only specify -k twice"); |
2147 |
|
|
usage(); |
2148 |
|
|
/* NOTREACHED */ |
2149 |
|
|
} |
2150 |
|
|
state_kill[state_killers++] = optarg; |
2151 |
|
|
mode = O_RDWR; |
2152 |
|
|
break; |
2153 |
|
|
case 'K': |
2154 |
|
|
if (src_node_killers >= 2) { |
2155 |
|
|
warnx("can only specify -K twice"); |
2156 |
|
|
usage(); |
2157 |
|
|
/* NOTREACHED */ |
2158 |
|
|
} |
2159 |
|
|
src_node_kill[src_node_killers++] = optarg; |
2160 |
|
|
mode = O_RDWR; |
2161 |
|
|
break; |
2162 |
|
|
case 'n': |
2163 |
|
|
opts |= PF_OPT_NOACTION; |
2164 |
|
|
break; |
2165 |
|
|
case 'r': |
2166 |
|
|
opts |= PF_OPT_USEDNS; |
2167 |
|
|
break; |
2168 |
|
|
case 'R': |
2169 |
|
|
shownr = strtonum(optarg, -1, LONG_MAX, &errstr); |
2170 |
|
|
if (errstr) { |
2171 |
|
|
warnx("invalid rule id: %s", errstr); |
2172 |
|
|
usage(); |
2173 |
|
|
} |
2174 |
|
|
break; |
2175 |
|
|
case 'f': |
2176 |
|
|
rulesopt = optarg; |
2177 |
|
|
mode = O_RDWR; |
2178 |
|
|
break; |
2179 |
|
|
case 'g': |
2180 |
|
|
opts |= PF_OPT_DEBUG; |
2181 |
|
|
break; |
2182 |
|
|
case 'o': |
2183 |
|
|
optiopt = pfctl_lookup_option(optarg, optiopt_list); |
2184 |
|
|
if (optiopt == NULL) { |
2185 |
|
|
warnx("Unknown optimization '%s'", optarg); |
2186 |
|
|
usage(); |
2187 |
|
|
} |
2188 |
|
|
opts |= PF_OPT_OPTIMIZE; |
2189 |
|
|
break; |
2190 |
|
|
case 'P': |
2191 |
|
|
opts |= PF_OPT_PORTNAMES; |
2192 |
|
|
break; |
2193 |
|
|
case 'p': |
2194 |
|
|
pf_device = optarg; |
2195 |
|
|
break; |
2196 |
|
|
case 's': |
2197 |
|
|
showopt = pfctl_lookup_option(optarg, showopt_list); |
2198 |
|
|
if (showopt == NULL) { |
2199 |
|
|
warnx("Unknown show modifier '%s'", optarg); |
2200 |
|
|
usage(); |
2201 |
|
|
} |
2202 |
|
|
break; |
2203 |
|
|
case 't': |
2204 |
|
|
tableopt = optarg; |
2205 |
|
|
break; |
2206 |
|
|
case 'T': |
2207 |
|
|
tblcmdopt = pfctl_lookup_option(optarg, tblcmdopt_list); |
2208 |
|
|
if (tblcmdopt == NULL) { |
2209 |
|
|
warnx("Unknown table command '%s'", optarg); |
2210 |
|
|
usage(); |
2211 |
|
|
} |
2212 |
|
|
break; |
2213 |
|
|
case 'v': |
2214 |
|
|
if (opts & PF_OPT_VERBOSE) |
2215 |
|
|
opts |= PF_OPT_VERBOSE2; |
2216 |
|
|
opts |= PF_OPT_VERBOSE; |
2217 |
|
|
break; |
2218 |
|
|
case 'x': |
2219 |
|
|
debugopt = pfctl_lookup_option(optarg, debugopt_list); |
2220 |
|
|
if (debugopt == NULL) { |
2221 |
|
|
warnx("Unknown debug level '%s'", optarg); |
2222 |
|
|
usage(); |
2223 |
|
|
} |
2224 |
|
|
mode = O_RDWR; |
2225 |
|
|
break; |
2226 |
|
|
case 'z': |
2227 |
|
|
opts |= PF_OPT_CLRRULECTRS; |
2228 |
|
|
mode = O_RDWR; |
2229 |
|
|
break; |
2230 |
|
|
case 'S': |
2231 |
|
|
sfile = optarg; |
2232 |
|
|
break; |
2233 |
|
|
case 'L': |
2234 |
|
|
mode = O_RDWR; |
2235 |
|
|
lfile = optarg; |
2236 |
|
|
break; |
2237 |
|
|
case 'h': |
2238 |
|
|
/* FALLTHROUGH */ |
2239 |
|
|
default: |
2240 |
|
|
usage(); |
2241 |
|
|
/* NOTREACHED */ |
2242 |
|
|
} |
2243 |
|
|
} |
2244 |
|
|
|
2245 |
|
|
if (tblcmdopt != NULL) { |
2246 |
|
|
argc -= optind; |
2247 |
|
|
argv += optind; |
2248 |
|
|
ch = *tblcmdopt; |
2249 |
|
|
mode = strchr("acdefkrz", ch) ? O_RDWR : O_RDONLY; |
2250 |
|
|
} else if (argc != optind) { |
2251 |
|
|
warnx("unknown command line argument: %s ...", argv[optind]); |
2252 |
|
|
usage(); |
2253 |
|
|
/* NOTREACHED */ |
2254 |
|
|
} |
2255 |
|
|
|
2256 |
|
|
if ((path = calloc(1, PATH_MAX)) == NULL) |
2257 |
|
|
errx(1, "pfctl: calloc"); |
2258 |
|
|
memset(anchorname, 0, sizeof(anchorname)); |
2259 |
|
|
if (anchoropt != NULL) { |
2260 |
|
|
int len = strlen(anchoropt); |
2261 |
|
|
|
2262 |
|
|
if (anchoropt[len - 1] == '*') { |
2263 |
|
|
if (len >= 2 && anchoropt[len - 2] == '/') { |
2264 |
|
|
anchoropt[len - 2] = '\0'; |
2265 |
|
|
anchor_wildcard = 1; |
2266 |
|
|
} else |
2267 |
|
|
anchoropt[len - 1] = '\0'; |
2268 |
|
|
opts |= PF_OPT_RECURSE; |
2269 |
|
|
} |
2270 |
|
|
if (strlcpy(anchorname, anchoropt, |
2271 |
|
|
sizeof(anchorname)) >= sizeof(anchorname)) |
2272 |
|
|
errx(1, "anchor name '%s' too long", |
2273 |
|
|
anchoropt); |
2274 |
|
|
} |
2275 |
|
|
|
2276 |
|
|
if ((opts & PF_OPT_NOACTION) == 0) { |
2277 |
|
|
dev = open(pf_device, mode); |
2278 |
|
|
if (dev == -1) |
2279 |
|
|
err(1, "%s", pf_device); |
2280 |
|
|
} else { |
2281 |
|
|
dev = open(pf_device, O_RDONLY); |
2282 |
|
|
if (dev >= 0) |
2283 |
|
|
opts |= PF_OPT_DUMMYACTION; |
2284 |
|
|
/* turn off options */ |
2285 |
|
|
opts &= ~ (PF_OPT_DISABLE | PF_OPT_ENABLE); |
2286 |
|
|
clearopt = showopt = debugopt = NULL; |
2287 |
|
|
} |
2288 |
|
|
|
2289 |
|
|
if (opts & PF_OPT_DISABLE) |
2290 |
|
|
if (pfctl_disable(dev, opts)) |
2291 |
|
|
error = 1; |
2292 |
|
|
|
2293 |
|
|
if (showopt != NULL) { |
2294 |
|
|
switch (*showopt) { |
2295 |
|
|
case 'A': |
2296 |
|
|
pfctl_show_anchors(dev, opts, anchorname); |
2297 |
|
|
break; |
2298 |
|
|
case 'r': |
2299 |
|
|
pfctl_load_fingerprints(dev, opts); |
2300 |
|
|
pfctl_show_rules(dev, path, opts, PFCTL_SHOW_RULES, |
2301 |
|
|
anchorname, 0, anchor_wildcard, shownr); |
2302 |
|
|
break; |
2303 |
|
|
case 'l': |
2304 |
|
|
pfctl_load_fingerprints(dev, opts); |
2305 |
|
|
pfctl_show_rules(dev, path, opts, PFCTL_SHOW_LABELS, |
2306 |
|
|
anchorname, 0, anchor_wildcard, shownr); |
2307 |
|
|
break; |
2308 |
|
|
case 'q': |
2309 |
|
|
pfctl_show_queues(dev, ifaceopt, opts, |
2310 |
|
|
opts & PF_OPT_VERBOSE2); |
2311 |
|
|
break; |
2312 |
|
|
case 's': |
2313 |
|
|
pfctl_show_states(dev, ifaceopt, opts, shownr); |
2314 |
|
|
break; |
2315 |
|
|
case 'S': |
2316 |
|
|
pfctl_show_src_nodes(dev, opts); |
2317 |
|
|
break; |
2318 |
|
|
case 'i': |
2319 |
|
|
pfctl_show_status(dev, opts); |
2320 |
|
|
break; |
2321 |
|
|
case 't': |
2322 |
|
|
pfctl_show_timeouts(dev, opts); |
2323 |
|
|
break; |
2324 |
|
|
case 'm': |
2325 |
|
|
pfctl_show_limits(dev, opts); |
2326 |
|
|
break; |
2327 |
|
|
case 'a': |
2328 |
|
|
opts |= PF_OPT_SHOWALL; |
2329 |
|
|
pfctl_load_fingerprints(dev, opts); |
2330 |
|
|
|
2331 |
|
|
pfctl_show_rules(dev, path, opts, 0, anchorname, |
2332 |
|
|
0, 0, -1); |
2333 |
|
|
pfctl_show_queues(dev, ifaceopt, opts, |
2334 |
|
|
opts & PF_OPT_VERBOSE2); |
2335 |
|
|
pfctl_show_states(dev, ifaceopt, opts, -1); |
2336 |
|
|
pfctl_show_src_nodes(dev, opts); |
2337 |
|
|
pfctl_show_status(dev, opts); |
2338 |
|
|
pfctl_show_rules(dev, path, opts, 1, anchorname, |
2339 |
|
|
0, 0, -1); |
2340 |
|
|
pfctl_show_timeouts(dev, opts); |
2341 |
|
|
pfctl_show_limits(dev, opts); |
2342 |
|
|
pfctl_show_tables(anchorname, opts); |
2343 |
|
|
pfctl_show_fingerprints(opts); |
2344 |
|
|
break; |
2345 |
|
|
case 'T': |
2346 |
|
|
pfctl_show_tables(anchorname, opts); |
2347 |
|
|
break; |
2348 |
|
|
case 'o': |
2349 |
|
|
pfctl_load_fingerprints(dev, opts); |
2350 |
|
|
pfctl_show_fingerprints(opts); |
2351 |
|
|
break; |
2352 |
|
|
case 'I': |
2353 |
|
|
pfctl_show_ifaces(ifaceopt, opts); |
2354 |
|
|
break; |
2355 |
|
|
} |
2356 |
|
|
} |
2357 |
|
|
|
2358 |
|
|
if ((opts & PF_OPT_CLRRULECTRS) && showopt == NULL) |
2359 |
|
|
pfctl_show_rules(dev, path, opts, PFCTL_SHOW_NOTHING, |
2360 |
|
|
anchorname, 0, 0, -1); |
2361 |
|
|
|
2362 |
|
|
if (clearopt != NULL) { |
2363 |
|
|
if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) |
2364 |
|
|
errx(1, "anchor names beginning with '_' cannot " |
2365 |
|
|
"be modified from the command line"); |
2366 |
|
|
|
2367 |
|
|
switch (*clearopt) { |
2368 |
|
|
case 'r': |
2369 |
|
|
pfctl_clear_rules(dev, opts, anchorname); |
2370 |
|
|
break; |
2371 |
|
|
case 's': |
2372 |
|
|
pfctl_clear_states(dev, ifaceopt, opts); |
2373 |
|
|
break; |
2374 |
|
|
case 'S': |
2375 |
|
|
pfctl_clear_src_nodes(dev, opts); |
2376 |
|
|
break; |
2377 |
|
|
case 'i': |
2378 |
|
|
pfctl_clear_stats(dev, ifaceopt, opts); |
2379 |
|
|
break; |
2380 |
|
|
case 'a': |
2381 |
|
|
pfctl_clear_rules(dev, opts, anchorname); |
2382 |
|
|
pfctl_clear_tables(anchorname, opts); |
2383 |
|
|
if (ifaceopt && *ifaceopt) { |
2384 |
|
|
warnx("don't specify an interface with -Fall"); |
2385 |
|
|
usage(); |
2386 |
|
|
/* NOTREACHED */ |
2387 |
|
|
} |
2388 |
|
|
if (!*anchorname) { |
2389 |
|
|
pfctl_clear_states(dev, ifaceopt, opts); |
2390 |
|
|
pfctl_clear_src_nodes(dev, opts); |
2391 |
|
|
pfctl_clear_stats(dev, ifaceopt, opts); |
2392 |
|
|
pfctl_clear_fingerprints(dev, opts); |
2393 |
|
|
pfctl_clear_interface_flags(dev, opts); |
2394 |
|
|
} |
2395 |
|
|
break; |
2396 |
|
|
case 'o': |
2397 |
|
|
pfctl_clear_fingerprints(dev, opts); |
2398 |
|
|
break; |
2399 |
|
|
case 'T': |
2400 |
|
|
pfctl_clear_tables(anchorname, opts); |
2401 |
|
|
break; |
2402 |
|
|
} |
2403 |
|
|
} |
2404 |
|
|
if (state_killers) { |
2405 |
|
|
if (!strcmp(state_kill[0], "label")) |
2406 |
|
|
pfctl_label_kill_states(dev, ifaceopt, opts); |
2407 |
|
|
else if (!strcmp(state_kill[0], "id")) |
2408 |
|
|
pfctl_id_kill_states(dev, ifaceopt, opts); |
2409 |
|
|
else |
2410 |
|
|
pfctl_net_kill_states(dev, ifaceopt, opts); |
2411 |
|
|
} |
2412 |
|
|
|
2413 |
|
|
if (src_node_killers) |
2414 |
|
|
pfctl_kill_src_nodes(dev, ifaceopt, opts); |
2415 |
|
|
|
2416 |
|
|
if (tblcmdopt != NULL) { |
2417 |
|
|
error = pfctl_command_tables(argc, argv, tableopt, |
2418 |
|
|
tblcmdopt, rulesopt, anchorname, opts); |
2419 |
|
|
rulesopt = NULL; |
2420 |
|
|
} |
2421 |
|
|
if (optiopt != NULL) { |
2422 |
|
|
switch (*optiopt) { |
2423 |
|
|
case 'n': |
2424 |
|
|
optimize = 0; |
2425 |
|
|
break; |
2426 |
|
|
case 'b': |
2427 |
|
|
optimize |= PF_OPTIMIZE_BASIC; |
2428 |
|
|
break; |
2429 |
|
|
case 'o': |
2430 |
|
|
case 'p': |
2431 |
|
|
optimize |= PF_OPTIMIZE_PROFILE; |
2432 |
|
|
break; |
2433 |
|
|
} |
2434 |
|
|
} |
2435 |
|
|
|
2436 |
|
|
if ((rulesopt != NULL) && !anchorname[0]) |
2437 |
|
|
if (pfctl_clear_interface_flags(dev, opts | PF_OPT_QUIET)) |
2438 |
|
|
error = 1; |
2439 |
|
|
|
2440 |
|
|
if (rulesopt != NULL && !anchorname[0]) |
2441 |
|
|
if (pfctl_file_fingerprints(dev, opts, PF_OSFP_FILE)) |
2442 |
|
|
error = 1; |
2443 |
|
|
|
2444 |
|
|
if (rulesopt != NULL) { |
2445 |
|
|
if (anchorname[0] == '_' || strstr(anchorname, "/_") != NULL) |
2446 |
|
|
errx(1, "anchor names beginning with '_' cannot " |
2447 |
|
|
"be modified from the command line"); |
2448 |
|
|
if (pfctl_rules(dev, rulesopt, opts, optimize, |
2449 |
|
|
anchorname, NULL)) |
2450 |
|
|
error = 1; |
2451 |
|
|
else if (!(opts & PF_OPT_NOACTION)) |
2452 |
|
|
warn_namespace_collision(NULL); |
2453 |
|
|
} |
2454 |
|
|
|
2455 |
|
|
if (opts & PF_OPT_ENABLE) |
2456 |
|
|
if (pfctl_enable(dev, opts)) |
2457 |
|
|
error = 1; |
2458 |
|
|
|
2459 |
|
|
if (debugopt != NULL) { |
2460 |
|
|
if ((level = string_to_loglevel((char *)debugopt)) < 0) { |
2461 |
|
|
switch (*debugopt) { |
2462 |
|
|
case 'n': |
2463 |
|
|
level = LOG_CRIT; |
2464 |
|
|
break; |
2465 |
|
|
case 'u': |
2466 |
|
|
level = LOG_ERR; |
2467 |
|
|
break; |
2468 |
|
|
case 'm': |
2469 |
|
|
level = LOG_NOTICE; |
2470 |
|
|
break; |
2471 |
|
|
case 'l': |
2472 |
|
|
level = LOG_DEBUG; |
2473 |
|
|
break; |
2474 |
|
|
} |
2475 |
|
|
} |
2476 |
|
|
if (level >= 0) |
2477 |
|
|
pfctl_debug(dev, level, opts); |
2478 |
|
|
} |
2479 |
|
|
|
2480 |
|
|
if (sfile != NULL) |
2481 |
|
|
pfctl_state_store(dev, sfile); |
2482 |
|
|
if (lfile != NULL) |
2483 |
|
|
pfctl_state_load(dev, lfile); |
2484 |
|
|
|
2485 |
|
|
exit(error); |
2486 |
|
|
} |