Bug #8555 » FreeBSD-src.patch
| sbin/pfctl/pf_print_state.c | ||
|---|---|---|
|
bcopy(&s->id, &id, sizeof(u_int64_t));
|
||
|
printf(" id: %016jx creatorid: %08x",
|
||
|
(uintmax_t )be64toh(id), ntohl(s->creatorid));
|
||
|
printf(" gateway: ");
|
||
|
print_host(&s->rt_addr, 0, s->af, opts);
|
||
|
printf("\n");
|
||
|
}
|
||
|
}
|
||
| sbin/pfctl/pfctl.8 | ||
|---|---|---|
|
.Sh SYNOPSIS
|
||
|
.Nm pfctl
|
||
|
.Bk -words
|
||
|
.Op Fl AdeghmNnOPqRrvz
|
||
|
.Op Fl AdeghMmNnOPqRrvz
|
||
|
.Op Fl a Ar anchor
|
||
|
.Oo Fl D Ar macro Ns =
|
||
|
.Ar value Oc
|
||
| ... | ... | |
|
.Op Fl K Ar host | network
|
||
|
.Xo
|
||
|
.Oo Fl k
|
||
|
.Ar host | network | label | id
|
||
|
.Ar host | network | label | id | gateway
|
||
|
.Oc Xc
|
||
|
.Op Fl o Ar level
|
||
|
.Op Fl p Ar device
|
||
| ... | ... | |
|
entries from the first host/network to the second.
|
||
|
.It Xo
|
||
|
.Fl k
|
||
|
.Ar host | network | label | id
|
||
|
.Ar host | network | label | id | gateway
|
||
|
.Xc
|
||
|
Kill all of the state entries matching the specified
|
||
|
.Ar host ,
|
||
|
.Ar network ,
|
||
|
.Ar label ,
|
||
|
.Ar id ,
|
||
|
or
|
||
|
.Ar id .
|
||
|
.Ar gateway.
|
||
|
.Pp
|
||
|
For example, to kill all of the state entries originating from
|
||
|
.Dq host :
|
||
| ... | ... | |
|
firewall with hostid 00000002 use:
|
||
|
.Pp
|
||
|
.Dl # pfctl -k id -k 4823e84500000018/2
|
||
|
.Pp
|
||
|
It is also possible to kill states created from a rule with the route-to/reply-to
|
||
|
parameter set to route the connection through a particular gateway.
|
||
|
Note that rules routing via a the default routing table (not via a route-to
|
||
|
rule) will have their rt_addr set as 0.0.0.0 or ::. To kill all states using
|
||
|
a gateway of 192.168.0.1 use:
|
||
|
.Pp
|
||
|
.Dl # pfctl -k gateway -k 192.168.0.1
|
||
|
.Pp
|
||
|
A network prefix length can also be specified.
|
||
|
To kill all states using a gateway in 192.168.0.0/24:
|
||
|
.Pp
|
||
|
.Dl # pfctl -k gateway -k 192.168.0.0/24
|
||
|
.It Fl M
|
||
|
Kill matching states in the opposite direction (on other interfaces) when killing states.
|
||
|
This applies to states killed using the -k option and also will apply to the flush
|
||
|
command when flushing states. This is useful when an interface is specified when flushing states. Example:
|
||
|
.Pp
|
||
|
.Dl # pfctl -M -i interface -Fs
|
||
|
.It Fl m
|
||
|
Merge in explicitly given options without resetting those
|
||
|
which are omitted.
|
||
| sbin/pfctl/pfctl.c | ||
|---|---|---|
|
void pfctl_addrprefix(char *, struct pf_addr *);
|
||
|
int pfctl_kill_src_nodes(int, const char *, int);
|
||
|
int pfctl_net_kill_states(int, const char *, int);
|
||
|
int pfctl_gateway_kill_states(int, const char *, int);
|
||
|
int pfctl_label_kill_states(int, const char *, int);
|
||
|
int pfctl_kill_schedule(int, const char *, int);
|
||
|
int pfctl_id_kill_states(int, const char *, int);
|
||
| ... | ... | |
|
extern char *__progname;
|
||
|
fprintf(stderr,
|
||
|
"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
|
||
|
"usage: %s [-AdeghMmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
|
||
|
"\t[-f file] [-i interface] [-K host | network]\n"
|
||
|
"\t[-k host | network | label | id] [-o level] [-p device]\n"
|
||
|
"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
|
||
| ... | ... | |
|
struct pfioc_state_kill psk;
|
||
|
memset(&psk, 0, sizeof(psk));
|
||
|
if (iface != NULL && strlcpy(psk.psk_ifname, iface,
|
||
|
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
|
||
|
errx(1, "invalid interface: %s", iface);
|
||
|
if (iface != NULL) {
|
||
|
if (strlcpy(psk.psk_ifname, iface,
|
||
|
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname)) {
|
||
|
errx(1, "invalid interface: %s", iface);
|
||
|
} else if (opts & PF_OPT_KILLMATCH) {
|
||
|
psk.psk_flag |= PSK_FLAG_KILLMATCH;
|
||
|
}
|
||
|
}
|
||
|
if (ioctl(dev, DIOCCLRSTATES, &psk))
|
||
|
err(1, "DIOCCLRSTATES");
|
||
| ... | ... | |
|
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
|
||
|
errx(1, "invalid interface: %s", iface);
|
||
|
if (opts & PF_OPT_KILLMATCH) {
|
||
|
psk.psk_flag |= PSK_FLAG_KILLMATCH;
|
||
|
}
|
||
|
pfctl_addrprefix(state_kill[0], &psk.psk_src.addr.v.a.mask);
|
||
|
if ((ret_ga = getaddrinfo(state_kill[0], NULL, NULL, &res[0]))) {
|
||
| ... | ... | |
|
return (0);
|
||
|
}
|
||
|
int
|
||
|
pfctl_gateway_kill_states(int dev, const char *iface, int opts)
|
||
|
{
|
||
|
struct pfioc_state_kill psk;
|
||
|
struct addrinfo *res, *resp;
|
||
|
struct sockaddr last_src;
|
||
|
int killed;
|
||
|
int ret_ga;
|
||
|
killed = 0;
|
||
|
memset(&psk, 0, sizeof(psk));
|
||
|
memset(&psk.psk_rt_addr.addr.v.a.mask, 0xff,
|
||
|
sizeof(psk.psk_rt_addr.addr.v.a.mask));
|
||
|
memset(&last_src, 0xff, sizeof(last_src));
|
||
|
if (iface != NULL && strlcpy(psk.psk_ifname, iface,
|
||
|
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
|
||
|
errx(1, "invalid interface: %s", iface);
|
||
|
if (opts & PF_OPT_KILLMATCH) {
|
||
|
psk.psk_flag |= PSK_FLAG_KILLMATCH;
|
||
|
}
|
||
|
pfctl_addrprefix(state_kill[1], &psk.psk_rt_addr.addr.v.a.mask);
|
||
|
if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res))) {
|
||
|
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
|
||
|
/* NOTREACHED */
|
||
|
}
|
||
|
for (resp = res; resp; resp = resp->ai_next) {
|
||
|
if (resp->ai_addr == NULL)
|
||
|
continue;
|
||
|
/* We get lots of duplicates. Catch the easy ones */
|
||
|
if (memcmp(&last_src, resp->ai_addr, sizeof(last_src)) == 0)
|
||
|
continue;
|
||
|
last_src = *(struct sockaddr *)resp->ai_addr;
|
||
|
psk.psk_af = resp->ai_family;
|
||
|
if (psk.psk_af == AF_INET)
|
||
|
psk.psk_rt_addr.addr.v.a.addr.v4 =
|
||
|
((struct sockaddr_in *)resp->ai_addr)->sin_addr;
|
||
|
else if (psk.psk_af == AF_INET6)
|
||
|
psk.psk_rt_addr.addr.v.a.addr.v6 =
|
||
|
((struct sockaddr_in6 *)resp->ai_addr)->
|
||
|
sin6_addr;
|
||
|
else
|
||
|
errx(1, "Unknown address family %d", psk.psk_af);
|
||
|
if (ioctl(dev, DIOCKILLSTATES, &psk))
|
||
|
err(1, "DIOCKILLSTATES");
|
||
|
killed += psk.psk_killed;
|
||
|
}
|
||
|
freeaddrinfo(res);
|
||
|
if ((opts & PF_OPT_QUIET) == 0)
|
||
|
fprintf(stderr, "killed %d states\n", killed);
|
||
|
return (0);
|
||
|
}
|
||
|
int
|
||
|
pfctl_kill_schedule(int dev, const char *sched, int opts)
|
||
|
{
|
||
| ... | ... | |
|
usage();
|
||
|
}
|
||
|
memset(&psk, 0, sizeof(psk));
|
||
|
if (opts & PF_OPT_KILLMATCH) {
|
||
|
psk.psk_flag |= PSK_FLAG_KILLMATCH;
|
||
|
}
|
||
|
if (iface != NULL && strlcpy(psk.psk_ifname, iface,
|
||
|
sizeof(psk.psk_ifname)) >= sizeof(psk.psk_ifname))
|
||
|
errx(1, "invalid interface: %s", iface);
|
||
| ... | ... | |
|
}
|
||
|
memset(&psk, 0, sizeof(psk));
|
||
|
if (opts & PF_OPT_KILLMATCH) {
|
||
|
psk.psk_flag |= PSK_FLAG_KILLMATCH;
|
||
|
}
|
||
|
if ((sscanf(state_kill[1], "%jx/%x",
|
||
|
&psk.psk_pfcmp.id, &psk.psk_pfcmp.creatorid)) == 2)
|
||
|
HTONL(psk.psk_pfcmp.creatorid);
|
||
| ... | ... | |
|
usage();
|
||
|
while ((ch = getopt(argc, argv,
|
||
|
"a:AdD:eqf:F:ghi:k:K:mnNOo:Pp:rRs:t:T:vx:y:z")) != -1) {
|
||
|
"a:AdD:eqf:F:ghi:k:K:mMnNOo:Pp:rRs:t:T:vx:y:z")) != -1) {
|
||
|
switch (ch) {
|
||
|
case 'a':
|
||
|
anchoropt = optarg;
|
||
| ... | ... | |
|
case 'm':
|
||
|
opts |= PF_OPT_MERGE;
|
||
|
break;
|
||
|
case 'M':
|
||
|
opts |= PF_OPT_KILLMATCH;
|
||
|
break;
|
||
|
case 'n':
|
||
|
opts |= PF_OPT_NOACTION;
|
||
|
break;
|
||
| ... | ... | |
|
pfctl_label_kill_states(dev, ifaceopt, opts);
|
||
|
else if (!strcmp(state_kill[0], "id"))
|
||
|
pfctl_id_kill_states(dev, ifaceopt, opts);
|
||
|
else if (!strcmp(state_kill[0], "gateway"))
|
||
|
pfctl_gateway_kill_states(dev, ifaceopt, opts);
|
||
|
else
|
||
|
pfctl_net_kill_states(dev, ifaceopt, opts);
|
||
|
}
|
||
| sbin/pfctl/pfctl_parser.h | ||
|---|---|---|
|
#define PF_OPT_NUMERIC 0x1000
|
||
|
#define PF_OPT_MERGE 0x2000
|
||
|
#define PF_OPT_RECURSE 0x4000
|
||
|
#define PF_OPT_KILLMATCH 0x8000
|
||
|
#define PF_TH_ALL 0xFF
|
||
| share/man/man4/pf.4 | ||
|---|---|---|
|
Remove matching entries from the state table.
|
||
|
This ioctl returns the number of killed states in
|
||
|
.Va psk_killed .
|
||
|
The psk_flag can be set with PSK_FLAG_KILLMATCH to also look
|
||
|
for and kill a matching state in the opposite direction for
|
||
|
each state matching the original criteria.
|
||
|
.Bd -literal
|
||
|
struct pfioc_state_kill {
|
||
|
struct pf_state_cmp psk_pfcmp;
|
||
| ... | ... | |
|
int psk_proto;
|
||
|
struct pf_rule_addr psk_src;
|
||
|
struct pf_rule_addr psk_dst;
|
||
|
struct pf_rule_addr psk_rt_addr;
|
||
|
char psk_ifname[IFNAMSIZ];
|
||
|
char psk_label[PF_RULE_LABEL_SIZE];
|
||
|
int psk_flag;
|
||
|
u_int psk_killed;
|
||
|
};
|
||
|
.Ed
|
||
| ... | ... | |
|
.Va psk_af ,
|
||
|
.Va psk_proto ,
|
||
|
.Va psk_src ,
|
||
|
.Va psk_dst ,
|
||
|
and
|
||
|
.Va psk_dst
|
||
|
.Va psk_rt_addr
|
||
|
fields of the
|
||
|
.Vt pfioc_state_kill
|
||
|
structure.
|
||
| sys/net/pfvar.h | ||
|---|---|---|
|
int psk_proto;
|
||
|
struct pf_rule_addr psk_src;
|
||
|
struct pf_rule_addr psk_dst;
|
||
|
struct pf_rule_addr psk_rt_addr;
|
||
|
char psk_ifname[IFNAMSIZ];
|
||
|
char psk_label[PF_RULE_LABEL_SIZE];
|
||
|
int psk_flag;
|
||
|
u_int psk_killed;
|
||
|
};
|
||
|
#define PSK_FLAG_KILLMATCH 0x0001
|
||
|
struct pfioc_schedule_kill {
|
||
|
int numberkilled;
|
||
|
char schedule[PF_RULE_LABEL_SIZE];
|
||
| sys/netpfil/pf/pf_ioctl.c | ||
|---|---|---|
|
* Don't send out individual
|
||
|
* delete messages.
|
||
|
*/
|
||
|
if (psk->psk_flag & PSK_FLAG_KILLMATCH) {
|
||
|
u_int dir;
|
||
|
struct pf_state *match;
|
||
|
struct pf_state_key_cmp key;
|
||
|
int idx, more = 0;
|
||
|
bzero(&key, sizeof(key));
|
||
|
if (s->direction == PF_OUT) {
|
||
|
dir = PF_IN;
|
||
|
idx = PF_SK_STACK;
|
||
|
} else {
|
||
|
dir = PF_OUT;
|
||
|
idx = PF_SK_WIRE;
|
||
|
}
|
||
|
key.af = s->key[idx]->af;
|
||
|
key.proto = s->key[idx]->proto;
|
||
|
PF_ACPY(&key.addr[0], &s->key[idx]->addr[1],key.af);
|
||
|
key.port[0] = s->key[idx]->port[1];
|
||
|
PF_ACPY(&key.addr[1], &s->key[idx]->addr[0],key.af);
|
||
|
key.port[1] = s->key[idx]->port[0];
|
||
|
match = pf_find_state_all(&key, dir, &more);
|
||
|
if (match && !more) {
|
||
|
pf_unlink_state(match, 0);
|
||
|
killed++;
|
||
|
}
|
||
|
}
|
||
|
s->state_flags |= PFSTATE_NOSYNC;
|
||
|
pf_unlink_state(s, PF_ENTER_LOCKED);
|
||
|
killed++;
|
||
| ... | ... | |
|
&psk->psk_dst.addr.v.a.addr,
|
||
|
&psk->psk_dst.addr.v.a.mask,
|
||
|
dstaddr, sk->af) &&
|
||
|
PF_MATCHA(psk->psk_rt_addr.neg,
|
||
|
&psk->psk_rt_addr.addr.v.a.addr,
|
||
|
&psk->psk_rt_addr.addr.v.a.mask,
|
||
|
&s->rt_addr, sk->af) &&
|
||
|
(psk->psk_src.port_op == 0 ||
|
||
|
pf_match_port(psk->psk_src.port_op,
|
||
|
psk->psk_src.port[0], psk->psk_src.port[1],
|
||
| ... | ... | |
|
(!psk->psk_ifname[0] ||
|
||
|
!strcmp(psk->psk_ifname,
|
||
|
s->kif->pfik_name))) {
|
||
|
if (psk->psk_flag & PSK_FLAG_KILLMATCH) {
|
||
|
u_int dir;
|
||
|
struct pf_state *match;
|
||
|
struct pf_state_key_cmp key;
|
||
|
int idx, more = 0;
|
||
|
bzero(&key, sizeof(key));
|
||
|
if (s->direction == PF_OUT) {
|
||
|
dir = PF_IN;
|
||
|
idx = PF_SK_STACK;
|
||
|
} else {
|
||
|
dir = PF_OUT;
|
||
|
idx = PF_SK_WIRE;
|
||
|
}
|
||
|
key.af = s->key[idx]->af;
|
||
|
key.proto = s->key[idx]->proto;
|
||
|
PF_ACPY(&key.addr[0], &s->key[idx]->addr[1],key.af);
|
||
|
key.port[0] = s->key[idx]->port[1];
|
||
|
PF_ACPY(&key.addr[1], &s->key[idx]->addr[0],key.af);
|
||
|
key.port[1] = s->key[idx]->port[0];
|
||
|
match = pf_find_state_all(&key, dir, &more);
|
||
|
if (match && !more) {
|
||
|
pf_unlink_state(match, 0);
|
||
|
killed++;
|
||
|
}
|
||
|
}
|
||
|
pf_unlink_state(s, PF_ENTER_LOCKED);
|
||
|
killed++;
|
||
|
goto relock_DIOCKILLSTATES;
|
||