Skip to content

Commit c7fbd6e

Browse files
kprovostbsdjhb
authored andcommitted
pf: Allow states to by killed per 'gateway'
This allows us to kill states created from a rule with route-to/reply-to set. This is particularly useful in multi-wan setups, where one of the WAN links goes down. Submitted by: Steven Brown Obtained from: pfsense/FreeBSD-src#11 MFC after: 1 week Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D30058
2 parents cc12fac + abbcba9 commit c7fbd6e

File tree

7 files changed

+96
-5
lines changed

7 files changed

+96
-5
lines changed

lib/libpfctl/libpfctl.c

+1
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,7 @@ _pfctl_clear_states(int dev, const struct pfctl_kill *kill,
642642
nvlist_add_number(nvl, "proto", kill->proto);
643643
pfctl_nv_add_rule_addr(nvl, "src", &kill->src);
644644
pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst);
645+
pfctl_nv_add_rule_addr(nvl, "rt_addr", &kill->rt_addr);
645646
nvlist_add_string(nvl, "ifname", kill->ifname);
646647
nvlist_add_string(nvl, "label", kill->label);
647648

lib/libpfctl/libpfctl.h

+1
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,7 @@ struct pfctl_kill {
191191
int proto;
192192
struct pf_rule_addr src;
193193
struct pf_rule_addr dst;
194+
struct pf_rule_addr rt_addr;
194195
char ifname[IFNAMSIZ];
195196
char label[PF_RULE_LABEL_SIZE];
196197
};

sbin/pfctl/pfctl.8

+17-3
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
.Op Fl K Ar host | network
4646
.Xo
4747
.Oo Fl k
48-
.Ar host | network | label | id
48+
.Ar host | network | label | id | gateway
4949
.Oc Xc
5050
.Op Fl o Ar level
5151
.Op Fl p Ar device
@@ -256,14 +256,15 @@ option may be specified, which will kill all the source tracking
256256
entries from the first host/network to the second.
257257
.It Xo
258258
.Fl k
259-
.Ar host | network | label | id
259+
.Ar host | network | label | id | gateway
260260
.Xc
261261
Kill all of the state entries matching the specified
262262
.Ar host ,
263263
.Ar network ,
264264
.Ar label ,
265+
.Ar id ,
265266
or
266-
.Ar id .
267+
.Ar gateway.
267268
.Pp
268269
For example, to kill all of the state entries originating from
269270
.Dq host :
@@ -317,6 +318,19 @@ To kill a state with ID 4823e84500000018 created from a backup
317318
firewall with hostid 00000002 use:
318319
.Pp
319320
.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 the default routing table (not via a route-to
325+
rule) will have their rt_addr set as 0.0.0.0 or ::.
326+
To kill all states using 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
320334
.It Fl m
321335
Merge in explicitly given options without resetting those
322336
which are omitted.

sbin/pfctl/pfctl.c

+65-1
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@ int pfctl_clear_iface_states(int, const char *, int);
8383
void pfctl_addrprefix(char *, struct pf_addr *);
8484
int pfctl_kill_src_nodes(int, const char *, int);
8585
int pfctl_net_kill_states(int, const char *, int);
86+
int pfctl_gateway_kill_states(int, const char *, int);
8687
int pfctl_label_kill_states(int, const char *, int);
8788
int pfctl_id_kill_states(int, const char *, int);
8889
void pfctl_init_options(struct pfctl *);
@@ -246,7 +247,7 @@ usage(void)
246247
fprintf(stderr,
247248
"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
248249
"\t[-f file] [-i interface] [-K host | network]\n"
249-
"\t[-k host | network | label | id] [-o level] [-p device]\n"
250+
"\t[-k host | network | gateway | label | id] [-o level] [-p device]\n"
250251
"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
251252
__progname);
252253

@@ -744,6 +745,67 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
744745
return (0);
745746
}
746747

748+
int
749+
pfctl_gateway_kill_states(int dev, const char *iface, int opts)
750+
{
751+
struct pfctl_kill kill;
752+
struct addrinfo *res, *resp;
753+
struct sockaddr last_src;
754+
unsigned int newkilled;
755+
int killed = 0;
756+
int ret_ga;
757+
758+
if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
759+
warnx("no gateway specified");
760+
usage();
761+
}
762+
763+
memset(&kill, 0, sizeof(kill));
764+
memset(&kill.rt_addr.addr.v.a.mask, 0xff,
765+
sizeof(kill.rt_addr.addr.v.a.mask));
766+
memset(&last_src, 0xff, sizeof(last_src));
767+
if (iface != NULL && strlcpy(kill.ifname, iface,
768+
sizeof(kill.ifname)) >= sizeof(kill.ifname))
769+
errx(1, "invalid interface: %s", iface);
770+
771+
pfctl_addrprefix(state_kill[1], &kill.rt_addr.addr.v.a.mask);
772+
773+
if ((ret_ga = getaddrinfo(state_kill[1], NULL, NULL, &res))) {
774+
errx(1, "getaddrinfo: %s", gai_strerror(ret_ga));
775+
/* NOTREACHED */
776+
}
777+
for (resp = res; resp; resp = resp->ai_next) {
778+
if (resp->ai_addr == NULL)
779+
continue;
780+
/* We get lots of duplicates. Catch the easy ones */
781+
if (memcmp(&last_src, resp->ai_addr, sizeof(last_src)) == 0)
782+
continue;
783+
last_src = *(struct sockaddr *)resp->ai_addr;
784+
785+
kill.af = resp->ai_family;
786+
787+
if (kill.af == AF_INET)
788+
kill.rt_addr.addr.v.a.addr.v4 =
789+
((struct sockaddr_in *)resp->ai_addr)->sin_addr;
790+
else if (kill.af == AF_INET6)
791+
kill.rt_addr.addr.v.a.addr.v6 =
792+
((struct sockaddr_in6 *)resp->ai_addr)->
793+
sin6_addr;
794+
else
795+
errx(1, "Unknown address family %d", kill.af);
796+
797+
if (pfctl_kill_states(dev, &kill, &newkilled))
798+
err(1, "DIOCKILLSTATES");
799+
killed += newkilled;
800+
}
801+
802+
freeaddrinfo(res);
803+
804+
if ((opts & PF_OPT_QUIET) == 0)
805+
fprintf(stderr, "killed %d states\n", killed);
806+
return (0);
807+
}
808+
747809
int
748810
pfctl_label_kill_states(int dev, const char *iface, int opts)
749811
{
@@ -2455,6 +2517,8 @@ main(int argc, char *argv[])
24552517
pfctl_label_kill_states(dev, ifaceopt, opts);
24562518
else if (!strcmp(state_kill[0], "id"))
24572519
pfctl_id_kill_states(dev, ifaceopt, opts);
2520+
else if (!strcmp(state_kill[0], "gateway"))
2521+
pfctl_gateway_kill_states(dev, ifaceopt, opts);
24582522
else
24592523
pfctl_net_kill_states(dev, ifaceopt, opts);
24602524
}

share/man/man4/pf.4

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
.\"
2929
.\" $FreeBSD$
3030
.\"
31-
.Dd August 5, 2018
31+
.Dd May 7, 2021
3232
.Dt PF 4
3333
.Os
3434
.Sh NAME

sys/net/pfvar.h

+1
Original file line numberDiff line numberDiff line change
@@ -1081,6 +1081,7 @@ struct pf_kstate_kill {
10811081
int psk_proto;
10821082
struct pf_rule_addr psk_src;
10831083
struct pf_rule_addr psk_dst;
1084+
struct pf_rule_addr psk_rt_addr;
10841085
char psk_ifname[IFNAMSIZ];
10851086
char psk_label[PF_RULE_LABEL_SIZE];
10861087
u_int psk_killed;

sys/netpfil/pf/pf_ioctl.c

+10
Original file line numberDiff line numberDiff line change
@@ -2458,6 +2458,10 @@ pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
24582458
return (EINVAL);
24592459
PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
24602460
&kill->psk_dst));
2461+
if (nvlist_exists_nvlist(nvl, "rt_addr")) {
2462+
PFNV_CHK(pf_nvrule_addr_to_rule_addr(
2463+
nvlist_get_nvlist(nvl, "rt_addr"), &kill->psk_rt_addr));
2464+
}
24612465

24622466
PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
24632467
sizeof(kill->psk_ifname)));
@@ -2679,6 +2683,12 @@ pf_killstates_row(struct pf_kstate_kill *psk, struct pf_idhash *ih)
26792683
&psk->psk_dst.addr.v.a.mask, dstaddr, sk->af))
26802684
continue;
26812685

2686+
if (! PF_MATCHA(psk->psk_rt_addr.neg,
2687+
&psk->psk_rt_addr.addr.v.a.addr,
2688+
&psk->psk_rt_addr.addr.v.a.mask,
2689+
&s->rt_addr, sk->af))
2690+
continue;
2691+
26822692
if (psk->psk_src.port_op != 0 &&
26832693
! pf_match_port(psk->psk_src.port_op,
26842694
psk->psk_src.port[0], psk->psk_src.port[1], srcport))

0 commit comments

Comments
 (0)