git: 4f33755051c6 - main - pf: allow states to be killed by their pre-NAT address

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Mon, 23 Oct 2023 16:41:46 UTC
The branch main has been updated by kp:

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

commit 4f33755051c60c6f65ba9f6aaa33d11e72909618
Author:     Kristof Provost <kp@FreeBSD.org>
AuthorDate: 2023-10-20 05:37:46 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2023-10-23 14:37:05 +0000

    pf: allow states to be killed by their pre-NAT address
    
    If a connection is NAT-ed we could previously only terminate it by its
    ID or the post-NAT IP address. Allow users to specify they want look for
    the state by its pre-NAT address. Usage: `pfctl -k nat -k <address>`.
    
    See also:       https://redmine.pfsense.org/issues/11556
    Sponsored by:   Rubicon Communications, LLC ("Netgate")
    Differential Revision:  https://reviews.freebsd.org/D42312
---
 lib/libpfctl/libpfctl.c   |  1 +
 lib/libpfctl/libpfctl.h   |  1 +
 sbin/pfctl/pfctl.8        | 13 +++++++++----
 sbin/pfctl/pfctl.c        |  6 ++++++
 sys/net/pfvar.h           |  1 +
 sys/netpfil/pf/pf_ioctl.c |  6 +++---
 sys/netpfil/pf/pf_nv.c    |  3 +++
 7 files changed, 24 insertions(+), 7 deletions(-)

diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 25bb77d9c021..0360c0c63be7 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -1468,6 +1468,7 @@ _pfctl_clear_states(int dev, const struct pfctl_kill *kill,
 	nvlist_add_string(nvl, "ifname", kill->ifname);
 	nvlist_add_string(nvl, "label", kill->label);
 	nvlist_add_bool(nvl, "kill_match", kill->kill_match);
+	nvlist_add_bool(nvl, "nat", kill->nat);
 
 	if ((ret = pfctl_do_ioctl(dev, ioctlval, 1024, &nvl)) != 0)
 		return (ret);
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index ad6fde89771c..0b50cc054060 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -310,6 +310,7 @@ struct pfctl_kill {
 	char			ifname[IFNAMSIZ];
 	char			label[PF_RULE_LABEL_SIZE];
 	bool			kill_match;
+	bool			nat;
 };
 
 struct pfctl_state_peer {
diff --git a/sbin/pfctl/pfctl.8 b/sbin/pfctl/pfctl.8
index 41eb2bea9f94..6c9a9f3b2ca4 100644
--- a/sbin/pfctl/pfctl.8
+++ b/sbin/pfctl/pfctl.8
@@ -24,7 +24,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd February 22, 2021
+.Dd October 20, 2023
 .Dt PFCTL 8
 .Os
 .Sh NAME
@@ -43,7 +43,7 @@
 .Op Fl K Ar host | network
 .Xo
 .Oo Fl k
-.Ar host | network | label | id | gateway
+.Ar host | network | label | id | gateway | nat
 .Oc Xc
 .Op Fl o Ar level
 .Op Fl p Ar device
@@ -256,15 +256,16 @@ 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 | gateway
+.Ar host | network | label | id | gateway | nat
 .Xc
 Kill all of the state entries matching the specified
 .Ar host ,
 .Ar network ,
 .Ar label ,
 .Ar id ,
+.Ar gateway,
 or
-.Ar gateway.
+.Ar nat.
 .Pp
 For example, to kill all of the state entries originating from
 .Dq host :
@@ -332,6 +333,10 @@ 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
+States can also be killed based on their pre-NAT address:
+.Pp
+.Dl # pfctl -k nat -k 192.168.0.1
+.Pp
 .It Fl M
 Kill matching states in the opposite direction (on other interfaces) when
 killing states.
diff --git a/sbin/pfctl/pfctl.c b/sbin/pfctl/pfctl.c
index c3f3d82ff767..03b7f24ce60a 100644
--- a/sbin/pfctl/pfctl.c
+++ b/sbin/pfctl/pfctl.c
@@ -725,6 +725,12 @@ pfctl_net_kill_states(int dev, const char *iface, int opts)
 	    sizeof(kill.ifname)) >= sizeof(kill.ifname))
 		errx(1, "invalid interface: %s", iface);
 
+	if (state_killers == 2 && (strcmp(state_kill[0], "nat") == 0)) {
+		kill.nat = true;
+		state_kill[0] = state_kill[1];
+		state_killers = 1;
+	}
+
 	pfctl_addrprefix(state_kill[0], &kill.src.addr.v.a.mask);
 
 	if (opts & PF_OPT_KILLMATCH)
diff --git a/sys/net/pfvar.h b/sys/net/pfvar.h
index b2aa1c450c50..6a5f8761755d 100644
--- a/sys/net/pfvar.h
+++ b/sys/net/pfvar.h
@@ -1770,6 +1770,7 @@ struct pf_kstate_kill {
 	char			psk_label[PF_RULE_LABEL_SIZE];
 	u_int			psk_killed;
 	bool			psk_kill_match;
+	bool			psk_nat;
 };
 #endif
 
diff --git a/sys/netpfil/pf/pf_ioctl.c b/sys/netpfil/pf/pf_ioctl.c
index 2eae03a908ec..851bf8ee5b63 100644
--- a/sys/netpfil/pf/pf_ioctl.c
+++ b/sys/netpfil/pf/pf_ioctl.c
@@ -2249,7 +2249,7 @@ relock_DIOCKILLSTATES:
 		/* For floating states look at the original kif. */
 		kif = s->kif == V_pfi_all ? s->orig_kif : s->kif;
 
-		sk = s->key[PF_SK_WIRE];
+		sk = s->key[psk->psk_nat ? PF_SK_STACK : PF_SK_WIRE];
 		if (s->direction == PF_OUT) {
 			srcaddr = &sk->addr[1];
 			dstaddr = &sk->addr[0];
@@ -2308,10 +2308,10 @@ relock_DIOCKILLSTATES:
 
 			if (s->direction == PF_OUT) {
 				dir = PF_IN;
-				idx = PF_SK_STACK;
+				idx = psk->psk_nat ? PF_SK_WIRE : PF_SK_STACK;
 			} else {
 				dir = PF_OUT;
-				idx = PF_SK_WIRE;
+				idx = psk->psk_nat ? PF_SK_STACK : PF_SK_WIRE;
 			}
 
 			match_key.af = s->key[idx]->af;
diff --git a/sys/netpfil/pf/pf_nv.c b/sys/netpfil/pf/pf_nv.c
index c4fa276da8fe..721d35be8916 100644
--- a/sys/netpfil/pf/pf_nv.c
+++ b/sys/netpfil/pf/pf_nv.c
@@ -873,6 +873,9 @@ pf_nvstate_kill_to_kstate_kill(const nvlist_t *nvl,
 	    sizeof(kill->psk_label)));
 	PFNV_CHK(pf_nvbool(nvl, "kill_match", &kill->psk_kill_match));
 
+	if (nvlist_exists_bool(nvl, "nat"))
+		PFNV_CHK(pf_nvbool(nvl, "nat", &kill->psk_nat));
+
 errout:
 	return (error);
 }