git: 727e413ff3f1 - main - libpfctl: add pfctl_open_from_nl_fd() and pfctl_nl_fd()

From: Kristof Provost <kp_at_FreeBSD.org>
Date: Fri, 30 Oct 2026 14:08:07 UTC
The branch main has been updated by kp:

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

commit 727e413ff3f18af8788ea78043b506e0111bfadc
Author:     Avinash Duduskar <avinash.duduskar@gmail.com>
AuthorDate: 2026-10-26 14:38:10 +0000
Commit:     Kristof Provost <kp@FreeBSD.org>
CommitDate: 2026-10-30 14:06:58 +0000

    libpfctl: add pfctl_open_from_nl_fd() and pfctl_nl_fd()
    
    pfctl_open_from_nl_fd() opens the pf device as pfctl_open() does but,
    when given a descriptor, adopts it as the Netlink socket instead of
    creating one. The handle's sequence numbers start at a random value:
    replies are matched by sequence number, so a random start makes it
    improbable that a reply an earlier owner of the socket left unread is
    taken for the answer to one of ours, or one of ours for theirs, however
    many times the socket has been handed on. pfctl_open() becomes a
    wrapper that passes -1.
    
    pfctl_nl_fd() returns the handle's Netlink descriptor, as pfctl_fd()
    does for the device, so a caller can hand it to a child process.
    
    PR:             291981
    Signed-off-by:  Avinash Duduskar <avinash.duduskar@gmail.com>
    Reviewed by:    kp
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2508
---
 lib/libpfctl/libpfctl.c | 28 +++++++++++++++++++++++++---
 lib/libpfctl/libpfctl.h |  3 +++
 2 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/lib/libpfctl/libpfctl.c b/lib/libpfctl/libpfctl.c
index 1522fd1554ab..22ad7888bace 100644
--- a/lib/libpfctl/libpfctl.c
+++ b/lib/libpfctl/libpfctl.c
@@ -73,7 +73,7 @@ static int	_pfctl_clear_states(int , const struct pfctl_kill *,
 static void	_pfctl_verify_parsers(void);
 
 struct pfctl_handle *
-pfctl_open(const char *pf_device)
+pfctl_open_from_nl_fd(const char *pf_device, int nl_fd)
 {
 	struct pfctl_handle *h;
 
@@ -85,8 +85,18 @@ pfctl_open(const char *pf_device)
 	if (h->fd < 0)
 		goto error;
 
-	if (!snl_init(&h->ss, NETLINK_GENERIC))
-		goto error;
+	if (nl_fd >= 0) {
+		if (!snl_init_fd(&h->ss, nl_fd))
+			goto error;
+		/*
+		 * Replies are matched by sequence number; a random start makes
+		 * a collision with an earlier owner's counter improbable.
+		 */
+		h->ss.seq = arc4random();
+	} else {
+		if (!snl_init(&h->ss, NETLINK_GENERIC))
+			goto error;
+	}
 
 	h->family_id = snl_get_genl_family(&h->ss, PFNL_FAMILY_NAME);
 	if (h->family_id == 0)
@@ -102,6 +112,12 @@ error:
 	return (NULL);
 }
 
+struct pfctl_handle *
+pfctl_open(const char *pf_device)
+{
+	return (pfctl_open_from_nl_fd(pf_device, -1));
+}
+
 void
 pfctl_close(struct pfctl_handle *h)
 {
@@ -116,6 +132,12 @@ pfctl_fd(struct pfctl_handle *h)
 	return (h->fd);
 }
 
+int
+pfctl_nl_fd(struct pfctl_handle *h)
+{
+	return (h->ss.fd);
+}
+
 static int
 pfctl_do_netlink_cmd(struct pfctl_handle *h, uint cmd)
 {
diff --git a/lib/libpfctl/libpfctl.h b/lib/libpfctl/libpfctl.h
index 0e56d081e9d7..41be320329d1 100644
--- a/lib/libpfctl/libpfctl.h
+++ b/lib/libpfctl/libpfctl.h
@@ -444,8 +444,11 @@ struct pfctl_src_node {
 
 struct pfctl_handle;
 struct pfctl_handle	*pfctl_open(const char *pf_device);
+struct pfctl_handle	*pfctl_open_from_nl_fd(const char *pf_device,
+	    int nl_fd);
 void	pfctl_close(struct pfctl_handle *);
 int	pfctl_fd(struct pfctl_handle *);
+int	pfctl_nl_fd(struct pfctl_handle *);
 
 int	pfctl_startstop(struct pfctl_handle *h, int start);
 struct pfctl_status* pfctl_get_status_h(struct pfctl_handle *h);