Project

General

Profile

Bug #8555 » FreeBSD-src.patch

Steven Brown, 07/15/2018 09:44 PM

View differences:

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;
(3-3/4)