Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 14 May 2021 13:06:49 GMT
From:      Kristof Provost <kp@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org
Subject:   git: a9620e7c7046 - stable/13 - pf: Allow states to by killed per 'gateway'
Message-ID:  <202105141306.14ED6nUA052543@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch stable/13 has been updated by kp:

URL: https://cgit.FreeBSD.org/src/commit/?id=a9620e7c70463e01e1762d1c2296248027afc9be

commit a9620e7c70463e01e1762d1c2296248027afc9be
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2021-04-30 13:15:05 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2021-05-14 08:24:00 +0000

    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
    
    (cherry picked from commit abbcba9cf5b1c26e837f00e0fbc205652cb05e51)
---
 lib/libpfctl/libpfctl.c   |  1 +
 lib/libpfctl/libpfctl.h   |  1 +
 sbin/pfctl/pfctl.8        | 20 +++++++++++---
 sbin/pfctl/pfctl.c        | 66 ++++++++++++++++++++++++++++++++++++++++++++++-
 share/man/man4/pf.4       |  2 +-
 sys/net/pfvar.h           |  1 +
 sys/netpfil/pf/pf_ioctl.c | 10 +++++++
 7 files changed, 96 insertions(+), 5 deletions(-)

diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 9f504237b4ee..f50afa7c78ef 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -642,6 +642,7 @@ _pfctl_clear_states(int dev, const struct pfctl_kill *kill,
 	nvlist_add_number(nvl, "proto", kill->proto);
 	pfctl_nv_add_rule_addr(nvl, "src", &kill->src);
 	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, "label", kill->label);
 
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index aa7f0ffd8fad..5c8b2108d937 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -191,6 +191,7 @@ struct pfctl_kill {
 	int			proto;
 	struct pf_rule_addr	src;
 	struct pf_rule_addr	dst;
+	struct pf_rule_addr	rt_addr;
 	char			ifname[IFNAMSIZ];
 	char			label[PF_RULE_LABEL_SIZE];
 };
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
index f12489d9493a..f3905f850c5a 100644
--- a/sbin/pfctl/pfctl.8
+++ b/sbin/pfctl/pfctl.8
@@ -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
@@ -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 :
@@ -317,6 +318,19 @@ 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 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
 Merge in explicitly given options without resetting those
 which are omitted.
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index 487dfb480cdc..96f3b4740d90 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -83,6 +83,7 @@ int	 pfctl_clear_iface_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_id_kill_states(int, const char *, int);
 void	 pfctl_init_options(struct pfctl *);
@@ -246,7 +247,7 @@ usage(void)
 	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[-k host | network | gateway | label | id] [-o level] [-p device]\n"
 	"\t[-s modifier] [-t table -T command [address ...]] [-x level]\n",
 	    __progname);
 
@@ -744,6 +745,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 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
 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);
 		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);
 	}
diff --git a/share/man/man4/pf.4 b/share/man/man4/pf.4
index e71ef8f426e4..2fb132203908 100644
--- a/share/man/man4/pf.4
+++ b/share/man/man4/pf.4
@@ -28,7 +28,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd August 5, 2018
+.Dd May 7, 2021
 .Dt PF 4
 .Os
 .Sh NAME
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index 7b18ef7d3b0c..0b08b418d625 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1079,6 +1079,7 @@ struct pf_kstate_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];
 	u_int			psk_killed;
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 897a5ff512a6..07ee7ba77a80 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2455,6 +2455,12 @@ relock_DIOCKILLSTATES:
 		    &psk->psk_dst.addr.v.a.mask, dstaddr, sk->af))
 			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 &&
 		    ! pf_match_port(psk->psk_src.port_op,
 		    psk->psk_src.port[0], psk->psk_src.port[1], srcport))
@@ -2538,6 +2544,10 @@ pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
 		return (EINVAL);
 	PFNV_CHK(pf_nvrule_addr_to_rule_addr(nvlist_get_nvlist(nvl, "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,
 	    sizeof(kill->psk_ifname)));



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202105141306.14ED6nUA052543>