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