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: https://github.com/pfsense/FreeBSD-src/pull/11/ MFC after: 1 week Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D30058
This commit is contained in:
parent
2b2ed4a697
commit
abbcba9cf5
@ -642,6 +642,7 @@ _pfctl_clear_states(int dev, const struct pfctl_kill *kill,
|
|||||||
nvlist_add_number(nvl, "proto", kill->proto);
|
nvlist_add_number(nvl, "proto", kill->proto);
|
||||||
pfctl_nv_add_rule_addr(nvl, "src", &kill->src);
|
pfctl_nv_add_rule_addr(nvl, "src", &kill->src);
|
||||||
pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst);
|
pfctl_nv_add_rule_addr(nvl, "dst", &kill->dst);
|
||||||
|
pfctl_nv_add_rule_addr(nvl, "rt_addr", &kill->rt_addr);
|
||||||
nvlist_add_string(nvl, "ifname", kill->ifname);
|
nvlist_add_string(nvl, "ifname", kill->ifname);
|
||||||
nvlist_add_string(nvl, "label", kill->label);
|
nvlist_add_string(nvl, "label", kill->label);
|
||||||
|
|
||||||
|
@ -191,6 +191,7 @@ struct pfctl_kill {
|
|||||||
int proto;
|
int proto;
|
||||||
struct pf_rule_addr src;
|
struct pf_rule_addr src;
|
||||||
struct pf_rule_addr dst;
|
struct pf_rule_addr dst;
|
||||||
|
struct pf_rule_addr rt_addr;
|
||||||
char ifname[IFNAMSIZ];
|
char ifname[IFNAMSIZ];
|
||||||
char label[PF_RULE_LABEL_SIZE];
|
char label[PF_RULE_LABEL_SIZE];
|
||||||
};
|
};
|
||||||
|
@ -45,7 +45,7 @@
|
|||||||
.Op Fl K Ar host | network
|
.Op Fl K Ar host | network
|
||||||
.Xo
|
.Xo
|
||||||
.Oo Fl k
|
.Oo Fl k
|
||||||
.Ar host | network | label | id
|
.Ar host | network | label | id | gateway
|
||||||
.Oc Xc
|
.Oc Xc
|
||||||
.Op Fl o Ar level
|
.Op Fl o Ar level
|
||||||
.Op Fl p Ar device
|
.Op Fl p Ar device
|
||||||
@ -256,14 +256,15 @@ option may be specified, which will kill all the source tracking
|
|||||||
entries from the first host/network to the second.
|
entries from the first host/network to the second.
|
||||||
.It Xo
|
.It Xo
|
||||||
.Fl k
|
.Fl k
|
||||||
.Ar host | network | label | id
|
.Ar host | network | label | id | gateway
|
||||||
.Xc
|
.Xc
|
||||||
Kill all of the state entries matching the specified
|
Kill all of the state entries matching the specified
|
||||||
.Ar host ,
|
.Ar host ,
|
||||||
.Ar network ,
|
.Ar network ,
|
||||||
.Ar label ,
|
.Ar label ,
|
||||||
|
.Ar id ,
|
||||||
or
|
or
|
||||||
.Ar id .
|
.Ar gateway.
|
||||||
.Pp
|
.Pp
|
||||||
For example, to kill all of the state entries originating from
|
For example, to kill all of the state entries originating from
|
||||||
.Dq host :
|
.Dq host :
|
||||||
@ -317,6 +318,19 @@ To kill a state with ID 4823e84500000018 created from a backup
|
|||||||
firewall with hostid 00000002 use:
|
firewall with hostid 00000002 use:
|
||||||
.Pp
|
.Pp
|
||||||
.Dl # pfctl -k id -k 4823e84500000018/2
|
.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 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
|
.It Fl m
|
||||||
Merge in explicitly given options without resetting those
|
Merge in explicitly given options without resetting those
|
||||||
which are omitted.
|
which are omitted.
|
||||||
|
@ -83,6 +83,7 @@ int pfctl_clear_iface_states(int, const char *, int);
|
|||||||
void pfctl_addrprefix(char *, struct pf_addr *);
|
void pfctl_addrprefix(char *, struct pf_addr *);
|
||||||
int pfctl_kill_src_nodes(int, const char *, int);
|
int pfctl_kill_src_nodes(int, const char *, int);
|
||||||
int pfctl_net_kill_states(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_label_kill_states(int, const char *, int);
|
||||||
int pfctl_id_kill_states(int, const char *, int);
|
int pfctl_id_kill_states(int, const char *, int);
|
||||||
void pfctl_init_options(struct pfctl *);
|
void pfctl_init_options(struct pfctl *);
|
||||||
@ -246,7 +247,7 @@ usage(void)
|
|||||||
fprintf(stderr,
|
fprintf(stderr,
|
||||||
"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
|
"usage: %s [-AdeghmNnOPqRrvz] [-a anchor] [-D macro=value] [-F modifier]\n"
|
||||||
"\t[-f file] [-i interface] [-K host | network]\n"
|
"\t[-f file] [-i interface] [-K host | network]\n"
|
||||||
"\t[-k host | network | label | id] [-o level] [-p device]\n"
|
"\t[-k host | network | gateway | label | id] [-o level] [-p device]\n"
|
||||||
"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
|
"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
|
||||||
__progname);
|
__progname);
|
||||||
|
|
||||||
@ -744,6 +745,67 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
pfctl_gateway_kill_states(int dev, const char *iface, int opts)
|
||||||
|
{
|
||||||
|
struct pfctl_kill kill;
|
||||||
|
struct addrinfo *res, *resp;
|
||||||
|
struct sockaddr last_src;
|
||||||
|
unsigned int newkilled;
|
||||||
|
int killed = 0;
|
||||||
|
int ret_ga;
|
||||||
|
|
||||||
|
if (state_killers != 2 || (strlen(state_kill[1]) == 0)) {
|
||||||
|
warnx("no gateway specified");
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&kill, 0, sizeof(kill));
|
||||||
|
memset(&kill.rt_addr.addr.v.a.mask, 0xff,
|
||||||
|
sizeof(kill.rt_addr.addr.v.a.mask));
|
||||||
|
memset(&last_src, 0xff, sizeof(last_src));
|
||||||
|
if (iface != NULL && strlcpy(kill.ifname, iface,
|
||||||
|
sizeof(kill.ifname)) >= sizeof(kill.ifname))
|
||||||
|
errx(1, "invalid interface: %s", iface);
|
||||||
|
|
||||||
|
pfctl_addrprefix(state_kill[1], &kill.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;
|
||||||
|
|
||||||
|
kill.af = resp->ai_family;
|
||||||
|
|
||||||
|
if (kill.af == AF_INET)
|
||||||
|
kill.rt_addr.addr.v.a.addr.v4 =
|
||||||
|
((struct sockaddr_in *)resp->ai_addr)->sin_addr;
|
||||||
|
else if (kill.af == AF_INET6)
|
||||||
|
kill.rt_addr.addr.v.a.addr.v6 =
|
||||||
|
((struct sockaddr_in6 *)resp->ai_addr)->
|
||||||
|
sin6_addr;
|
||||||
|
else
|
||||||
|
errx(1, "Unknown address family %d", kill.af);
|
||||||
|
|
||||||
|
if (pfctl_kill_states(dev, &kill, &newkilled))
|
||||||
|
err(1, "DIOCKILLSTATES");
|
||||||
|
killed += newkilled;
|
||||||
|
}
|
||||||
|
|
||||||
|
freeaddrinfo(res);
|
||||||
|
|
||||||
|
if ((opts & PF_OPT_QUIET) == 0)
|
||||||
|
fprintf(stderr, "killed %d states\n", killed);
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
pfctl_label_kill_states(int dev, const char *iface, int opts)
|
pfctl_label_kill_states(int dev, const char *iface, int opts)
|
||||||
{
|
{
|
||||||
@ -2455,6 +2517,8 @@ main(int argc, char *argv[])
|
|||||||
pfctl_label_kill_states(dev, ifaceopt, opts);
|
pfctl_label_kill_states(dev, ifaceopt, opts);
|
||||||
else if (!strcmp(state_kill[0], "id"))
|
else if (!strcmp(state_kill[0], "id"))
|
||||||
pfctl_id_kill_states(dev, ifaceopt, opts);
|
pfctl_id_kill_states(dev, ifaceopt, opts);
|
||||||
|
else if (!strcmp(state_kill[0], "gateway"))
|
||||||
|
pfctl_gateway_kill_states(dev, ifaceopt, opts);
|
||||||
else
|
else
|
||||||
pfctl_net_kill_states(dev, ifaceopt, opts);
|
pfctl_net_kill_states(dev, ifaceopt, opts);
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $FreeBSD$
|
.\" $FreeBSD$
|
||||||
.\"
|
.\"
|
||||||
.Dd August 5, 2018
|
.Dd May 7, 2021
|
||||||
.Dt PF 4
|
.Dt PF 4
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
|
@ -1081,6 +1081,7 @@ struct pf_kstate_kill {
|
|||||||
int psk_proto;
|
int psk_proto;
|
||||||
struct pf_rule_addr psk_src;
|
struct pf_rule_addr psk_src;
|
||||||
struct pf_rule_addr psk_dst;
|
struct pf_rule_addr psk_dst;
|
||||||
|
struct pf_rule_addr psk_rt_addr;
|
||||||
char psk_ifname[IFNAMSIZ];
|
char psk_ifname[IFNAMSIZ];
|
||||||
char psk_label[PF_RULE_LABEL_SIZE];
|
char psk_label[PF_RULE_LABEL_SIZE];
|
||||||
u_int psk_killed;
|
u_int psk_killed;
|
||||||
|
@ -2458,6 +2458,10 @@ pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
|
|||||||
return (EINVAL);
|
return (EINVAL);
|
||||||
PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
|
PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "dst"),
|
||||||
&kill->psk_dst));
|
&kill->psk_dst));
|
||||||
|
if (nvlist_exists_nvlist(nvl, "rt_addr")) {
|
||||||
|
PFNV_CHK(pf_nvrule_addr_to_rule_addr(
|
||||||
|
nvlist_get_nvlist(nvl, "rt_addr"), &kill->psk_rt_addr));
|
||||||
|
}
|
||||||
|
|
||||||
PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
|
PFNV_CHK(pf_nvstring(nvl, "ifname", kill->psk_ifname,
|
||||||
sizeof(kill->psk_ifname)));
|
sizeof(kill->psk_ifname)));
|
||||||
@ -2679,6 +2683,12 @@ pf_killstates_row(struct pf_kstate_kill *psk, struct pf_idhash *ih)
|
|||||||
&psk->psk_dst.addr.v.a.mask, dstaddr, sk->af))
|
&psk->psk_dst.addr.v.a.mask, dstaddr, sk->af))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (! 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))
|
||||||
|
continue;
|
||||||
|
|
||||||
if (psk->psk_src.port_op != 0 &&
|
if (psk->psk_src.port_op != 0 &&
|
||||||
! pf_match_port(psk->psk_src.port_op,
|
! pf_match_port(psk->psk_src.port_op,
|
||||||
psk->psk_src.port[0], psk->psk_src.port[1], srcport))
|
psk->psk_src.port[0], psk->psk_src.port[1], srcport))
|
||||||
|
Loading…
Reference in New Issue
Block a user