Skip to content

Extra functionality added when killing states #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: RELENG_2_4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions sbin/pfctl/pf_print_state.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,8 @@ print_state(struct pfsync_state *s, int opts)
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");
}
}
Expand Down
30 changes: 26 additions & 4 deletions sbin/pfctl/pfctl.8
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
.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
Expand All @@ -45,7 +45,7 @@
.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
Expand Down Expand Up @@ -256,14 +256,15 @@ option may be specified, which will kill all the source tracking
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 :
Expand Down Expand Up @@ -317,6 +318,27 @@ To kill a state with ID 4823e84500000018 created from a backup
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
.Pp
.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
.Pp
.It Fl m
Merge in explicitly given options without resetting those
which are omitted.
Expand Down
108 changes: 97 additions & 11 deletions sbin/pfctl/pfctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ int pfctl_clear_states(int, const char *, int);
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);
Expand Down Expand Up @@ -234,13 +235,13 @@ usage(void)
{
extern char *__progname;

fprintf(stderr,
"usage: %s [-AdeghmNnOPqRrvz] [-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",
__progname);

fprintf(stderr, "usage: %s [-AdeghMmNnOPqRrvz] ", __progname);
fprintf(stderr, "[-a anchor] [-D macro=value] [-F modifier]\n");
fprintf(stderr, "\t[-f file] [-i interface] [-K host | network]\n");
fprintf(stderr, "\t[-k host | network | label | id | gateway ] ");
fprintf(stderr, "[-o level] [-p device]\n");
fprintf(stderr, "\t[-s modifier] ");
fprintf(stderr, "[-t table -T command [address ...]] [-x level]\n");
exit(1);
}

Expand Down Expand Up @@ -380,9 +381,14 @@ pfctl_clear_states(int dev, const char *iface, int opts)
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");
Expand Down Expand Up @@ -564,6 +570,10 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
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]))) {
Expand Down Expand Up @@ -650,6 +660,67 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
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)
{
Expand Down Expand Up @@ -679,6 +750,11 @@ pfctl_label_kill_states(int dev, const char *iface, 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);
Expand Down Expand Up @@ -707,6 +783,11 @@ pfctl_id_kill_states(int dev, const char *iface, int opts)
}

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);
Expand Down Expand Up @@ -2027,7 +2108,7 @@ main(int argc, char *argv[])
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;
Expand Down Expand Up @@ -2080,6 +2161,9 @@ main(int argc, char *argv[])
case 'm':
opts |= PF_OPT_MERGE;
break;
case 'M':
opts |= PF_OPT_KILLMATCH;
break;
case 'n':
opts |= PF_OPT_NOACTION;
break;
Expand Down Expand Up @@ -2348,6 +2432,8 @@ main(int argc, char *argv[])
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);
}
Expand Down
1 change: 1 addition & 0 deletions sbin/pfctl/pfctl_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#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

Expand Down
8 changes: 7 additions & 1 deletion share/man/man4/pf.4
Original file line number Diff line number Diff line change
Expand Up @@ -338,15 +338,20 @@ structure from the state table.
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;
sa_family_t psk_af;
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
Expand All @@ -358,8 +363,9 @@ but ignores the
.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.
Expand Down
4 changes: 4 additions & 0 deletions sys/net/pfvar.h
Original file line number Diff line number Diff line change
Expand Up @@ -1309,11 +1309,15 @@ struct pfioc_state_kill {
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];
Expand Down
65 changes: 65 additions & 0 deletions sys/netpfil/pf/pf_ioctl.c
Original file line number Diff line number Diff line change
Expand Up @@ -1655,6 +1655,37 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
* 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++;
Expand Down Expand Up @@ -1717,6 +1748,10 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
&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],
Expand All @@ -1732,6 +1767,36 @@ pfioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flags, struct thread *td
(!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;
Expand Down