Bug #8555 » FreeBSD-src.patch
sbin/pfctl/pf_print_state.c | ||
---|---|---|
352 | 352 |
bcopy(&s->id, &id, sizeof(u_int64_t)); |
353 | 353 |
printf(" id: %016jx creatorid: %08x", |
354 | 354 |
(uintmax_t )be64toh(id), ntohl(s->creatorid)); |
355 |
printf(" gateway: "); |
|
356 |
print_host(&s->rt_addr, 0, s->af, opts); |
|
355 | 357 |
printf("\n"); |
358 | ||
356 | 359 |
} |
357 | 360 |
} |
358 | 361 |
sbin/pfctl/pfctl.8 | ||
---|---|---|
35 | 35 |
.Sh SYNOPSIS |
36 | 36 |
.Nm pfctl |
37 | 37 |
.Bk -words |
38 |
.Op Fl AdeghmNnOPqRrvz |
|
38 |
.Op Fl AdeghMmNnOPqRrvz
|
|
39 | 39 |
.Op Fl a Ar anchor |
40 | 40 |
.Oo Fl D Ar macro Ns = |
41 | 41 |
.Ar value Oc |
... | ... | |
45 | 45 |
.Op Fl K Ar host | network |
46 | 46 |
.Xo |
47 | 47 |
.Oo Fl k |
48 |
.Ar host | network | label | id |
|
48 |
.Ar host | network | label | id | gateway
|
|
49 | 49 |
.Oc Xc |
50 | 50 |
.Op Fl o Ar level |
51 | 51 |
.Op Fl p Ar device |
... | ... | |
256 | 256 |
entries from the first host/network to the second. |
257 | 257 |
.It Xo |
258 | 258 |
.Fl k |
259 |
.Ar host | network | label | id |
|
259 |
.Ar host | network | label | id | gateway
|
|
260 | 260 |
.Xc |
261 | 261 |
Kill all of the state entries matching the specified |
262 | 262 |
.Ar host , |
263 | 263 |
.Ar network , |
264 | 264 |
.Ar label , |
265 |
.Ar id , |
|
265 | 266 |
or |
266 |
.Ar id .
|
|
267 |
.Ar gateway.
|
|
267 | 268 |
.Pp |
268 | 269 |
For example, to kill all of the state entries originating from |
269 | 270 |
.Dq host : |
... | ... | |
317 | 318 |
firewall with hostid 00000002 use: |
318 | 319 |
.Pp |
319 | 320 |
.Dl # pfctl -k id -k 4823e84500000018/2 |
321 |
.Pp |
|
322 |
It is also possible to kill states created from a rule with the route-to/reply-to |
|
323 |
parameter set to route the connection through a particular gateway. |
|
324 |
Note that rules routing via a the default routing table (not via a route-to |
|
325 |
rule) will have their rt_addr set as 0.0.0.0 or ::. To kill all states using |
|
326 |
a gateway of 192.168.0.1 use: |
|
327 |
.Pp |
|
328 |
.Dl # pfctl -k gateway -k 192.168.0.1 |
|
329 |
.Pp |
|
330 |
A network prefix length can also be specified. |
|
331 |
To kill all states using a gateway in 192.168.0.0/24: |
|
332 |
.Pp |
|
333 |
.Dl # pfctl -k gateway -k 192.168.0.0/24 |
|
334 |
.It Fl M |
|
335 |
Kill matching states in the opposite direction (on other interfaces) when killing states. |
|
336 |
This applies to states killed using the -k option and also will apply to the flush |
|
337 |
command when flushing states. This is useful when an interface is specified when flushing states. Example: |
|
338 |
.Pp |
|
339 |
.Dl # pfctl -M -i interface -Fs |
|
320 | 340 |
.It Fl m |
321 | 341 |
Merge in explicitly given options without resetting those |
322 | 342 |
which are omitted. |
sbin/pfctl/pfctl.c | ||
---|---|---|
74 | 74 |
void pfctl_addrprefix(char *, struct pf_addr *); |
75 | 75 |
int pfctl_kill_src_nodes(int, const char *, int); |
76 | 76 |
int pfctl_net_kill_states(int, const char *, int); |
77 |
int pfctl_gateway_kill_states(int, const char *, int); |
|
77 | 78 |
int pfctl_label_kill_states(int, const char *, int); |
78 | 79 |
int pfctl_kill_schedule(int, const char *, int); |
79 | 80 |
int pfctl_id_kill_states(int, const char *, int); |
... | ... | |
235 | 236 |
extern char *__progname; |
236 | 237 | |
237 | 238 |
fprintf(stderr, |
238 |
"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n" |
|
239 |
"usage: %s [-AdeghMmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
|
|
239 | 240 |
"\t[-f file] [-i interface] [-K host | network]\n" |
240 | 241 |
"\t[-k host | network | label | id] [-o level] [-p device]\n" |
241 | 242 |
"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n", |
... | ... | |
380 | 381 |
struct pfioc_state_kill psk; |
381 | 382 | |
382 | 383 |
memset(&psk, 0, sizeof(psk)); |
383 |
if (iface != NULL && strlcpy(psk.psk_ifname, iface, |
|
384 |
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) |
|
385 |
errx(1, "invalid interface: %s", iface); |
|
384 |
if (iface != NULL) { |
|
385 |
if (strlcpy(psk.psk_ifname, iface, |
|
386 |
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) { |
|
387 |
errx(1, "invalid interface: %s", iface); |
|
388 |
} else if (opts & PF_OPT_KILLMATCH) { |
|
389 |
psk.psk_flag |= PSK_FLAG_KILLMATCH; |
|
390 |
} |
|
391 |
} |
|
386 | 392 | |
387 | 393 |
if (ioctl(dev, DIOCCLRSTATES, &psk)) |
388 | 394 |
err(1, "DIOCCLRSTATES"); |
... | ... | |
564 | 570 |
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) |
565 | 571 |
errx(1, "invalid interface: %s", iface); |
566 | 572 | |
573 |
if (opts & PF_OPT_KILLMATCH) { |
|
574 |
psk.psk_flag |= PSK_FLAG_KILLMATCH; |
|
575 |
} |
|
576 | ||
567 | 577 |
pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask); |
568 | 578 | |
569 | 579 |
if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) { |
... | ... | |
650 | 660 |
return (0); |
651 | 661 |
} |
652 | 662 | |
663 |
int |
|
664 |
pfctl_gateway_kill_states(int dev, const char *iface, int opts) |
|
665 |
{ |
|
666 |
struct pfioc_state_kill psk; |
|
667 |
struct addrinfo *res, *resp; |
|
668 |
struct sockaddr last_src; |
|
669 |
int killed; |
|
670 |
int ret_ga; |
|
671 | ||
672 |
killed = 0; |
|
673 | ||
674 |
memset(&psk, 0, sizeof(psk)); |
|
675 |
memset(&psk.psk_rt_addr.addr.v.a.mask, 0xff, |
|
676 |
sizeof(psk.psk_rt_addr.addr.v.a.mask)); |
|
677 |
memset(&last_src, 0xff, sizeof(last_src)); |
|
678 |
if (iface != NULL && strlcpy(psk.psk_ifname, iface, |
|
679 |
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) |
|
680 |
errx(1, "invalid interface: %s", iface); |
|
681 | ||
682 |
if (opts & PF_OPT_KILLMATCH) { |
|
683 |
psk.psk_flag |= PSK_FLAG_KILLMATCH; |
|
684 |
} |
|
685 | ||
686 |
pfctl_addrprefix(state_kill[1], &psk.psk_rt_addr.addr.v.a.mask); |
|
687 | ||
688 |
if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res))) { |
|
689 |
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga)); |
|
690 |
/* NOTREACHED */ |
|
691 |
} |
|
692 |
for (resp = res; resp; resp = resp->ai_next) { |
|
693 |
if (resp->ai_addr == NULL) |
|
694 |
continue; |
|
695 |
/* We get lots of duplicates. Catch the easy ones */ |
|
696 |
if (memcmp(&last_src, resp->ai_addr, sizeof(last_src)) == 0) |
|
697 |
continue; |
|
698 |
last_src = *(struct sockaddr *)resp->ai_addr; |
|
699 | ||
700 |
psk.psk_af = resp->ai_family; |
|
701 | ||
702 |
if (psk.psk_af == AF_INET) |
|
703 |
psk.psk_rt_addr.addr.v.a.addr.v4 = |
|
704 |
((struct sockaddr_in *)resp->ai_addr)->sin_addr; |
|
705 |
else if (psk.psk_af == AF_INET6) |
|
706 |
psk.psk_rt_addr.addr.v.a.addr.v6 = |
|
707 |
((struct sockaddr_in6 *)resp->ai_addr)-> |
|
708 |
sin6_addr; |
|
709 |
else |
|
710 |
errx(1, "Unknown address family %d", psk.psk_af); |
|
711 | ||
712 |
if (ioctl(dev, DIOCKILLSTATES, &psk)) |
|
713 |
err(1, "DIOCKILLSTATES"); |
|
714 |
killed += psk.psk_killed; |
|
715 |
} |
|
716 | ||
717 |
freeaddrinfo(res); |
|
718 | ||
719 |
if ((opts & PF_OPT_QUIET) == 0) |
|
720 |
fprintf(stderr, "killed %d states\n", killed); |
|
721 |
return (0); |
|
722 |
} |
|
723 | ||
653 | 724 |
int |
654 | 725 |
pfctl_kill_schedule(int dev, const char *sched, int opts) |
655 | 726 |
{ |
... | ... | |
679 | 750 |
usage(); |
680 | 751 |
} |
681 | 752 |
memset(&psk, 0, sizeof(psk)); |
753 | ||
754 |
if (opts & PF_OPT_KILLMATCH) { |
|
755 |
psk.psk_flag |= PSK_FLAG_KILLMATCH; |
|
756 |
} |
|
757 | ||
682 | 758 |
if (iface != NULL && strlcpy(psk.psk_ifname, iface, |
683 | 759 |
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) |
684 | 760 |
errx(1, "invalid interface: %s", iface); |
... | ... | |
707 | 783 |
} |
708 | 784 | |
709 | 785 |
memset(&psk, 0, sizeof(psk)); |
786 | ||
787 |
if (opts & PF_OPT_KILLMATCH) { |
|
788 |
psk.psk_flag |= PSK_FLAG_KILLMATCH; |
|
789 |
} |
|
790 | ||
710 | 791 |
if ((sscanf(state_kill[1], "%jx/%x", |
711 | 792 |
&psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2) |
712 | 793 |
HTONL(psk.psk_pfcmp.creatorid); |
... | ... | |
2027 | 2108 |
usage(); |
2028 | 2109 | |
2029 | 2110 |
while ((ch = getopt(argc, argv, |
2030 |
"a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:y:z")) != -1) { |
|
2111 |
"a:AdD:eqf:F:ghi:k:K:mMnNOo:Pp:rRs:t:T:vx:y:z")) != -1) {
|
|
2031 | 2112 |
switch (ch) { |
2032 | 2113 |
case 'a': |
2033 | 2114 |
anchoropt = optarg; |
... | ... | |
2080 | 2161 |
case 'm': |
2081 | 2162 |
opts |= PF_OPT_MERGE; |
2082 | 2163 |
break; |
2164 |
case 'M': |
|
2165 |
opts |= PF_OPT_KILLMATCH; |
|
2166 |
break; |
|
2083 | 2167 |
case 'n': |
2084 | 2168 |
opts |= PF_OPT_NOACTION; |
2085 | 2169 |
break; |
... | ... | |
2348 | 2432 |
pfctl_label_kill_states(dev, ifaceopt, opts); |
2349 | 2433 |
else if (!strcmp(state_kill[0], "id")) |
2350 | 2434 |
pfctl_id_kill_states(dev, ifaceopt, opts); |
2435 |
else if (!strcmp(state_kill[0], "gateway")) |
|
2436 |
pfctl_gateway_kill_states(dev, ifaceopt, opts); |
|
2351 | 2437 |
else |
2352 | 2438 |
pfctl_net_kill_states(dev, ifaceopt, opts); |
2353 | 2439 |
} |
sbin/pfctl/pfctl_parser.h | ||
---|---|---|
51 | 51 |
#define PF_OPT_NUMERIC 0x1000 |
52 | 52 |
#define PF_OPT_MERGE 0x2000 |
53 | 53 |
#define PF_OPT_RECURSE 0x4000 |
54 |
#define PF_OPT_KILLMATCH 0x8000 |
|
54 | 55 | |
55 | 56 |
#define PF_TH_ALL 0xFF |
56 | 57 |
share/man/man4/pf.4 | ||
---|---|---|
338 | 338 |
Remove matching entries from the state table. |
339 | 339 |
This ioctl returns the number of killed states in |
340 | 340 |
.Va psk_killed . |
341 |
The psk_flag can be set with PSK_FLAG_KILLMATCH to also look |
|
342 |
for and kill a matching state in the opposite direction for |
|
343 |
each state matching the original criteria. |
|
341 | 344 |
.Bd -literal |
342 | 345 |
struct pfioc_state_kill { |
343 | 346 |
struct pf_state_cmp psk_pfcmp; |
... | ... | |
345 | 348 |
int psk_proto; |
346 | 349 |
struct pf_rule_addr psk_src; |
347 | 350 |
struct pf_rule_addr psk_dst; |
351 |
struct pf_rule_addr psk_rt_addr; |
|
348 | 352 |
char psk_ifname[IFNAMSIZ]; |
349 | 353 |
char psk_label[PF_RULE_LABEL_SIZE]; |
354 |
int psk_flag; |
|
350 | 355 |
u_int psk_killed; |
351 | 356 |
}; |
352 | 357 |
.Ed |
... | ... | |
358 | 363 |
.Va psk_af , |
359 | 364 |
.Va psk_proto , |
360 | 365 |
.Va psk_src , |
366 |
.Va psk_dst , |
|
361 | 367 |
and |
362 |
.Va psk_dst
|
|
368 |
.Va psk_rt_addr
|
|
363 | 369 |
fields of the |
364 | 370 |
.Vt pfioc_state_kill |
365 | 371 |
structure. |
sys/net/pfvar.h | ||
---|---|---|
1309 | 1309 |
int psk_proto; |
1310 | 1310 |
struct pf_rule_addr psk_src; |
1311 | 1311 |
struct pf_rule_addr psk_dst; |
1312 |
struct pf_rule_addr psk_rt_addr; |
|
1312 | 1313 |
char psk_ifname[IFNAMSIZ]; |
1313 | 1314 |
char psk_label[PF_RULE_LABEL_SIZE]; |
1315 |
int psk_flag; |
|
1314 | 1316 |
u_int psk_killed; |
1315 | 1317 |
}; |
1316 | 1318 | |
1319 |
#define PSK_FLAG_KILLMATCH 0x0001 |
|
1320 | ||
1317 | 1321 |
struct pfioc_schedule_kill { |
1318 | 1322 |
int numberkilled; |
1319 | 1323 |
char schedule[PF_RULE_LABEL_SIZE]; |
sys/netpfil/pf/pf_ioctl.c | ||
---|---|---|
1655 | 1655 |
* Don't send out individual |
1656 | 1656 |
* delete messages. |
1657 | 1657 |
*/ |
1658 |
if (psk->psk_flag & PSK_FLAG_KILLMATCH) { |
|
1659 |
u_int dir; |
|
1660 |
struct pf_state *match; |
|
1661 |
struct pf_state_key_cmp key; |
|
1662 |
int idx, more = 0; |
|
1663 | ||
1664 |
bzero(&key, sizeof(key)); |
|
1665 | ||
1666 |
if (s->direction == PF_OUT) { |
|
1667 |
dir = PF_IN; |
|
1668 |
idx = PF_SK_STACK; |
|
1669 |
} else { |
|
1670 |
dir = PF_OUT; |
|
1671 |
idx = PF_SK_WIRE; |
|
1672 |
} |
|
1673 | ||
1674 |
key.af = s->key[idx]->af; |
|
1675 |
key.proto = s->key[idx]->proto; |
|
1676 |
PF_ACPY(&key.addr[0], &s->key[idx]->addr[1],key.af); |
|
1677 |
key.port[0] = s->key[idx]->port[1]; |
|
1678 |
PF_ACPY(&key.addr[1], &s->key[idx]->addr[0],key.af); |
|
1679 |
key.port[1] = s->key[idx]->port[0]; |
|
1680 | ||
1681 |
match = pf_find_state_all(&key, dir, &more); |
|
1682 |
if (match && !more) { |
|
1683 |
pf_unlink_state(match, 0); |
|
1684 |
killed++; |
|
1685 |
} |
|
1686 | ||
1687 |
} |
|
1688 | ||
1658 | 1689 |
s->state_flags |= PFSTATE_NOSYNC; |
1659 | 1690 |
pf_unlink_state(s, PF_ENTER_LOCKED); |
1660 | 1691 |
killed++; |
... | ... | |
1717 | 1748 |
&psk->psk_dst.addr.v.a.addr, |
1718 | 1749 |
&psk->psk_dst.addr.v.a.mask, |
1719 | 1750 |
dstaddr, sk->af) && |
1751 |
PF_MATCHA(psk->psk_rt_addr.neg, |
|
1752 |
&psk->psk_rt_addr.addr.v.a.addr, |
|
1753 |
&psk->psk_rt_addr.addr.v.a.mask, |
|
1754 |
&s->rt_addr, sk->af) && |
|
1720 | 1755 |
(psk->psk_src.port_op == 0 || |
1721 | 1756 |
pf_match_port(psk->psk_src.port_op, |
1722 | 1757 |
psk->psk_src.port[0], psk->psk_src.port[1], |
... | ... | |
1732 | 1767 |
(!psk->psk_ifname[0] || |
1733 | 1768 |
!strcmp(psk->psk_ifname, |
1734 | 1769 |
s->kif->pfik_name))) { |
1770 |
if (psk->psk_flag & PSK_FLAG_KILLMATCH) { |
|
1771 |
u_int dir; |
|
1772 |
struct pf_state *match; |
|
1773 |
struct pf_state_key_cmp key; |
|
1774 |
int idx, more = 0; |
|
1775 | ||
1776 |
bzero(&key, sizeof(key)); |
|
1777 | ||
1778 |
if (s->direction == PF_OUT) { |
|
1779 |
dir = PF_IN; |
|
1780 |
idx = PF_SK_STACK; |
|
1781 |
} else { |
|
1782 |
dir = PF_OUT; |
|
1783 |
idx = PF_SK_WIRE; |
|
1784 |
} |
|
1785 | ||
1786 |
key.af = s->key[idx]->af; |
|
1787 |
key.proto = s->key[idx]->proto; |
|
1788 |
PF_ACPY(&key.addr[0], &s->key[idx]->addr[1],key.af); |
|
1789 |
key.port[0] = s->key[idx]->port[1]; |
|
1790 |
PF_ACPY(&key.addr[1], &s->key[idx]->addr[0],key.af); |
|
1791 |
key.port[1] = s->key[idx]->port[0]; |
|
1792 | ||
1793 |
match = pf_find_state_all(&key, dir, &more); |
|
1794 |
if (match && !more) { |
|
1795 |
pf_unlink_state(match, 0); |
|
1796 |
killed++; |
|
1797 |
} |
|
1798 | ||
1799 |
} |
|
1735 | 1800 |
pf_unlink_state(s, PF_ENTER_LOCKED); |
1736 | 1801 |
killed++; |
1737 | 1802 |
goto relock_DIOCKILLSTATES; |