Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 06 Apr 2023 16:21:44 +0200
From:      Kristof Provost <kp@FreeBSD.org>
To:        FreeBSD PF List <freebsd-pf@freebsd.org>, FreeBSD Ports ML <freebsd-ports@freebsd.org>
Subject:   pf userspace API changes
Message-ID:  <0E45DD6F-81E3-45DB-9FB2-E47B8F26FD00@FreeBSD.org>

next in thread | raw e-mail | index | archive | help

--=_MailMate_778328E2-0F61-4D1F-9B96-3408223FC9DB_=
Content-Type: text/plain; charset=UTF-8; format=flowed; markup=markdown
Content-Transfer-Encoding: 8bit

Hi,

Quick heads up that there are going to be breaking changes to the pf API 
towards userspace for 14.0. (That is, the ioctl interface presented by 
/dev/pf).

I’ve been rewriting several types of calls to start using nvlists, 
because otherwise it’s basically unmanageable to extend calls (which 
we pretty much have to do to add new features).
The old struct-based ioctls have been left in place so far, but as 
that’s a substantial amount of (now untested!) code I’m very keen to 
be able to remove.

To be very explicit: removal of old ioctls will only ever affect new 
major versions. That is, 14.0 at the earliest. I will not break 
stable/12 or stable/13 or 13.2 or …

The initial breaking change is https://reviews.freebsd.org/D30056 . That 
removes DIOCCLRSTATES and DIOCKILLSTATES, which are now DIOCCLRSTATESNV 
and DIOCKILLSTATESNV, based on nvlists.

To make that all easier for userspace to manage there’s libpfctl, 
which wraps all of the API details. That port will be available for all 
supported platforms (when https://reviews.freebsd.org/D39360 lands, 
soon).

There are likely to be more changes in the future, so I’d strongly 
encourage all API users to migrate to using libpfctl rather than trying 
to roll their own implementations.

Here’s an example of how security/snortsam needed to be changed to 
cope with the above:

	commit 1136cf1ef66dc93397455818dfce0794d4e65170 (HEAD -> 
freebsd_current/libpfctl)
	Author: Kristof Provost <kp@FreeBSD.org>
	Date:   Sun Apr 2 07:01:06 2023 +0200

	    security/snortsam: use libpfctl

	    FreeBSD main will remove DIOCKILLSTATES soon. We can use libpfctl 
to
	    accomplish the same task though.

	    Sponsored by:   Rubicon Communications, LLC ("Netgate")

	diff --git a/security/snortsam/Makefile b/security/snortsam/Makefile
	index fbd106774..18ad44448 100644
	--- a/security/snortsam/Makefile
	+++ b/security/snortsam/Makefile
	@@ -1,6 +1,6 @@
	 PORTNAME=      snortsam
	 PORTVERSION=   2.70
	-PORTREVISION=  1
	+PORTREVISION=  2
	 CATEGORIES=    security
	 MASTER_SITES=  http://www.snortsam.net/files/snortsam/
	 DISTNAME=      ${PORTNAME}-src-${PORTVERSION}
	@@ -16,6 +16,8 @@ SAMTOOL_DESC= install samtool

	 .include <bsd.port.pre.mk>

	+LIB_DEPENDS=   libpfctl.so:net/libpfctl
	+
	 USE_RC_SUBR=   snortsam
	 SUB_FILES=     pkg-message \
	                pkg-install
	diff --git a/security/snortsam/files/patch-src_Makefile 
b/security/snortsam/files/patch-src_Makefile
	new file mode 100644
	index 000000000..59936d3d1
	--- /dev/null
	+++ b/security/snortsam/files/patch-src_Makefile
	@@ -0,0 +1,12 @@
	+--- src/Makefile.orig  2010-03-29 20:57:55 UTC
	++++ src/Makefile
	+@@ -36,9 +36,9 @@ SAMTOOL = samtool
	+ PROG    = snortsam
	+ SAMTOOL = samtool
	+-CFLAGS  = -O2 -D$(SYSTYPE) $(DEBUG)
	+-LDFLAGS =
	++CFLAGS  = -O2 -D$(SYSTYPE) $(DEBUG) -I/usr/local/include
	++LDFLAGS = -L/usr/local/lib -lpfctl
	+ SYSTYPE = `uname`
	+
	+ # OS specific flags
	diff --git a/security/snortsam/files/patch-src__ssp_pf2.c 
b/security/snortsam/files/patch-src__ssp_pf2.c
	index 81ce7d93e..00327f19c 100644
	--- a/security/snortsam/files/patch-src__ssp_pf2.c
	+++ b/security/snortsam/files/patch-src__ssp_pf2.c
	@@ -1,6 +1,14 @@
	---- ./src/ssp_pf2.c.orig       2009-11-27 02:39:40.000000000 +0100
	-+++ ./src/ssp_pf2.c    2014-01-20 19:03:47.000000000 +0100
	-@@ -95,7 +95,7 @@
	+--- src/ssp_pf2.c.orig 2009-11-27 01:39:40 UTC
	++++ src/ssp_pf2.c
	+@@ -48,6 +48,7 @@
	+
	+ #include "snortsam.h"
	+ #include "ssp_pf2.h"
	++#include <libpfctl.h>
	+
	+ unsigned int PF2use_anchor = TRUE;
	+ unsigned int PF2val_count = 0;
	+@@ -95,7 +96,7 @@ int parse_opts(char *line, opt_pf2 *opt, char *sep, 
ch
	          }
	       }

	@@ -9,3 +17,79 @@
	  }


	+@@ -393,20 +394,21 @@ pf2_kill_states(int pfdev, const char *ipsrc, 
int tin,
	+ {
	+     char   msg[STRBUFSIZE + 2];
	+     struct pf_addr pfa;
	+-    struct pfioc_state_kill psk;
	++    struct pfctl_kill k;
	+     sa_family_t saf;        /* stafe AF_INET family */
	+     unsigned long killed=0, killed_src=0, killed_dst=0;
	++    unsigned int kcount;
	+
	+     bzero(&pfa, sizeof(pfa));
	+-    bzero(&psk, sizeof(psk));
	++    bzero(&k, sizeof(k));
	+
	+     if (ipsrc == NULL || !ipsrc[0])
	+       return (-1);
	+
	+     if (inet_pton(AF_INET, ipsrc, &pfa.v4) == 1)
	+-          psk.psk_af = saf = AF_INET;
	++          k.af = AF_INET;
	+     else if (inet_pton(AF_INET6, ipsrc, &pfa.v6) == 1)
	+-          psk.psk_af = saf = AF_INET6;
	++          k.af = AF_INET6;
	+     else {
	+       snprintf(msg, sizeof(msg) - 1, "invalid ipsrc");
	+       logmessage(3, msg, "pf2", 0);
	+@@ -415,40 +417,31 @@ pf2_kill_states(int pfdev, const char *ipsrc, 
int tin,
	+
	+     /* Kill all states from pfa */
	+     if (tin || PF2_KILL_STATE_ALL) {
	+-      memcpy(&psk.psk_src.addr.v.a.addr, &pfa, 
sizeof(psk.psk_src.addr.v.a.addr));
	+-      memset(&psk.psk_src.addr.v.a.mask, 0xff, 
sizeof(psk.psk_src.addr.v.a.mask));
	+-      if (ioctl(pfdev, DIOCKILLSTATES, &psk)) {
	++      memcpy(&k.src.addr.v.a.addr, &pfa, 
sizeof(k.src.addr.v.a.addr));
	++      memset(&k.src.addr.v.a.mask, 0xff, 
sizeof(k.src.addr.v.a.mask));
	++      if (pfctl_kill_states(pfdev, &k, &kcount)) {
	+           snprintf(msg, sizeof(msg) - 1, "Error: DIOCKILLSTATES 
failed (%s)", strerror(errno));
	+           logmessage(1, msg, "pf2", 0);
	+       }
	+       else {
	+-#if OpenBSD >= 200811 /* since OpenBSD4_4 killed states returned in 
psk_killed */
	+-          killed_src += psk.psk_killed;
	+-#else
	+-          killed_src += psk.psk_af;
	+-#endif
	++          killed_src += kcount;
	+ #ifdef FWSAMDEBUG
	+           printf("Debug: [pf2] killed %lu (tin) states for host 
%s\n", killed_src, ipsrc);
	+ #endif
	+       }
	+-    psk.psk_af = saf; /* restore AF_INET */
	+     }
	+
	+     /* Kill all states to pfa */
	+     if (tout || PF2_KILL_STATE_ALL) {
	+-      bzero(&psk.psk_src, sizeof(psk.psk_src));  /* clear source 
address field (set before for incomming) */
	+-      memcpy(&psk.psk_dst.addr.v.a.addr, &pfa, 
sizeof(psk.psk_dst.addr.v.a.addr));
	+-      memset(&psk.psk_dst.addr.v.a.mask, 0xff, 
sizeof(psk.psk_dst.addr.v.a.mask));
	+-      if (ioctl(pfdev, DIOCKILLSTATES, &psk)) {
	++      bzero(&k.src, sizeof(k.src));  /* clear source address field 
(set before for incomming) */
	++      memcpy(&k.dst.addr.v.a.addr, &pfa, 
sizeof(k.dst.addr.v.a.addr));
	++      memset(&k.dst.addr.v.a.mask, 0xff, 
sizeof(k.dst.addr.v.a.mask));
	++      if (pfctl_kill_states(pfdev, &k, &kcount)) {
	+           snprintf(msg, sizeof(msg) - 1, "Error: DIOCKILLSTATES 
failed (%s)", strerror(errno));
	+           logmessage(1, msg, "pf2", 0);
	+       }
	+       else {
	+-#if OpenBSD >= 200811 /* since OpenBSD4_4 killed states returned in 
psk_killed */
	+-          killed_dst += psk.psk_killed;
	+-#else
	+-          killed_dst += psk.psk_af;
	+-#endif
	++          killed_dst += kcount;
	+ #ifdef FWSAMDEBUG
	+           printf("Debug: [pf2] killed %lu (tout) states for host 
%s\n", killed_dst, ipsrc);
	+ #endif

Tl;dr If you maintain a port that uses /dev/pf you’re going to have to 
start using net/libpfctl.

Best regards,
Kristof
--=_MailMate_778328E2-0F61-4D1F-9B96-3408223FC9DB_=
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<!DOCTYPE html>
<html>
<head>
<meta http-equiv=3D"Content-Type" content=3D"text/xhtml; charset=3Dutf-8"=
>
</head>
<body><div style=3D"font-family: sans-serif;"><div class=3D"markdown" sty=
le=3D"white-space: normal;">
<p dir=3D"auto">Hi,</p>
<p dir=3D"auto">Quick heads up that there are going to be breaking change=
s to the pf API towards userspace for 14.0. (That is, the ioctl interface=
 presented by /dev/pf).</p>
<p dir=3D"auto">I=E2=80=99ve been rewriting several types of calls to sta=
rt using nvlists, because otherwise it=E2=80=99s basically unmanageable t=
o extend calls (which we pretty much have to do to add new features).<br>=

The old struct-based ioctls have been left in place so far, but as that=E2=
=80=99s a substantial amount of (now untested!) code I=E2=80=99m very kee=
n to be able to remove.</p>
<p dir=3D"auto">To be very explicit: removal of old ioctls will only ever=
 affect new major versions. That is, 14.0 at the earliest. I will not bre=
ak stable/12 or stable/13 or 13.2 or =E2=80=A6</p>
<p dir=3D"auto">The initial breaking change is <a href=3D"https://reviews=
=2Efreebsd.org/D30056">https://reviews.freebsd.org/D30056</a>; . That remo=
ves DIOCCLRSTATES and DIOCKILLSTATES, which are now DIOCCLRSTATESNV and D=
IOCKILLSTATESNV, based on nvlists.</p>
<p dir=3D"auto">To make that all easier for userspace to manage there=E2=80=
=99s libpfctl, which wraps all of the API details. That port will be avai=
lable for all supported platforms (when <a href=3D"https://reviews.freebs=
d.org/D39360">https://reviews.freebsd.org/D39360</a>; lands, soon).</p>
<p dir=3D"auto">There are likely to be more changes in the future, so I=E2=
=80=99d strongly encourage all API users to migrate to using libpfctl rat=
her than trying to roll their own implementations.</p>
<p dir=3D"auto">Here=E2=80=99s an example of how security/snortsam needed=
 to be changed to cope with the above:</p>
<pre style=3D"margin-left: 15px; margin-right: 15px; padding: 5px; border=
: thin solid gray; overflow-x: auto; max-width: 90vw; background-color: #=
E4E4E4;"><code style=3D"padding: 0 0.25em; background-color: #E4E4E4;">co=
mmit 1136cf1ef66dc93397455818dfce0794d4e65170 (HEAD -&gt; freebsd_current=
/libpfctl)
Author: Kristof Provost &lt;kp@FreeBSD.org&gt;
Date:   Sun Apr 2 07:01:06 2023 +0200

    security/snortsam: use libpfctl

    FreeBSD main will remove DIOCKILLSTATES soon. We can use libpfctl to
    accomplish the same task though.

    Sponsored by:   Rubicon Communications, LLC (&quot;Netgate&quot;)

diff --git a/security/snortsam/Makefile b/security/snortsam/Makefile
index fbd106774..18ad44448 100644
--- a/security/snortsam/Makefile
+++ b/security/snortsam/Makefile
@@ -1,6 +1,6 @@
 PORTNAME=3D      snortsam
 PORTVERSION=3D   2.70
-PORTREVISION=3D  1
+PORTREVISION=3D  2
 CATEGORIES=3D    security
 MASTER_SITES=3D  http://www.snortsam.net/files/snortsam/
 DISTNAME=3D      ${PORTNAME}-src-${PORTVERSION}
@@ -16,6 +16,8 @@ SAMTOOL_DESC=3D install samtool

 .include &lt;bsd.port.pre.mk&gt;

+LIB_DEPENDS=3D   libpfctl.so:net/libpfctl
+
 USE_RC_SUBR=3D   snortsam
 SUB_FILES=3D     pkg-message \
                pkg-install
diff --git a/security/snortsam/files/patch-src_Makefile b/security/snorts=
am/files/patch-src_Makefile
new file mode 100644
index 000000000..59936d3d1
--- /dev/null
+++ b/security/snortsam/files/patch-src_Makefile
@@ -0,0 +1,12 @@
+--- src/Makefile.orig  2010-03-29 20:57:55 UTC
++++ src/Makefile
+@@ -36,9 +36,9 @@ SAMTOOL =3D samtool
+ PROG    =3D snortsam
+ SAMTOOL =3D samtool
+-CFLAGS  =3D -O2 -D$(SYSTYPE) $(DEBUG)
+-LDFLAGS =3D
++CFLAGS  =3D -O2 -D$(SYSTYPE) $(DEBUG) -I/usr/local/include
++LDFLAGS =3D -L/usr/local/lib -lpfctl
+ SYSTYPE =3D `uname`
+
+ # OS specific flags
diff --git a/security/snortsam/files/patch-src__ssp_pf2.c b/security/snor=
tsam/files/patch-src__ssp_pf2.c
index 81ce7d93e..00327f19c 100644
--- a/security/snortsam/files/patch-src__ssp_pf2.c
+++ b/security/snortsam/files/patch-src__ssp_pf2.c
@@ -1,6 +1,14 @@
---- ./src/ssp_pf2.c.orig       2009-11-27 02:39:40.000000000 +0100
-+++ ./src/ssp_pf2.c    2014-01-20 19:03:47.000000000 +0100
-@@ -95,7 +95,7 @@
+--- src/ssp_pf2.c.orig 2009-11-27 01:39:40 UTC
++++ src/ssp_pf2.c
+@@ -48,6 +48,7 @@
+
+ #include &quot;snortsam.h&quot;
+ #include &quot;ssp_pf2.h&quot;
++#include &lt;libpfctl.h&gt;
+
+ unsigned int PF2use_anchor =3D TRUE;
+ unsigned int PF2val_count =3D 0;
+@@ -95,7 +96,7 @@ int parse_opts(char *line, opt_pf2 *opt, char *sep, ch=

          }
       }

@@ -9,3 +17,79 @@
  }


+@@ -393,20 +394,21 @@ pf2_kill_states(int pfdev, const char *ipsrc, int =
tin,
+ {
+     char   msg[STRBUFSIZE + 2];
+     struct pf_addr pfa;
+-    struct pfioc_state_kill psk;
++    struct pfctl_kill k;
+     sa_family_t saf;        /* stafe AF_INET family */
+     unsigned long killed=3D0, killed_src=3D0, killed_dst=3D0;
++    unsigned int kcount;
+
+     bzero(&amp;pfa, sizeof(pfa));
+-    bzero(&amp;psk, sizeof(psk));
++    bzero(&amp;k, sizeof(k));
+
+     if (ipsrc =3D=3D NULL || !ipsrc[0])
+       return (-1);
+
+     if (inet_pton(AF_INET, ipsrc, &amp;pfa.v4) =3D=3D 1)
+-          psk.psk_af =3D saf =3D AF_INET;
++          k.af =3D AF_INET;
+     else if (inet_pton(AF_INET6, ipsrc, &amp;pfa.v6) =3D=3D 1)
+-          psk.psk_af =3D saf =3D AF_INET6;
++          k.af =3D AF_INET6;
+     else {
+       snprintf(msg, sizeof(msg) - 1, &quot;invalid ipsrc&quot;);
+       logmessage(3, msg, &quot;pf2&quot;, 0);
+@@ -415,40 +417,31 @@ pf2_kill_states(int pfdev, const char *ipsrc, int =
tin,
+
+     /* Kill all states from pfa */
+     if (tin || PF2_KILL_STATE_ALL) {
+-      memcpy(&amp;psk.psk_src.addr.v.a.addr, &amp;pfa, sizeof(psk.psk_s=
rc.addr.v.a.addr));
+-      memset(&amp;psk.psk_src.addr.v.a.mask, 0xff, sizeof(psk.psk_src.a=
ddr.v.a.mask));
+-      if (ioctl(pfdev, DIOCKILLSTATES, &amp;psk)) {
++      memcpy(&amp;k.src.addr.v.a.addr, &amp;pfa, sizeof(k.src.addr.v.a.=
addr));
++      memset(&amp;k.src.addr.v.a.mask, 0xff, sizeof(k.src.addr.v.a.mask=
));
++      if (pfctl_kill_states(pfdev, &amp;k, &amp;kcount)) {
+           snprintf(msg, sizeof(msg) - 1, &quot;Error: DIOCKILLSTATES fa=
iled (%s)&quot;, strerror(errno));
+           logmessage(1, msg, &quot;pf2&quot;, 0);
+       }
+       else {
+-#if OpenBSD &gt;=3D 200811 /* since OpenBSD4_4 killed states returned i=
n psk_killed */
+-          killed_src +=3D psk.psk_killed;
+-#else
+-          killed_src +=3D psk.psk_af;
+-#endif
++          killed_src +=3D kcount;
+ #ifdef FWSAMDEBUG
+           printf(&quot;Debug: [pf2] killed %lu (tin) states for host %s=
\n&quot;, killed_src, ipsrc);
+ #endif
+       }
+-    psk.psk_af =3D saf; /* restore AF_INET */
+     }
+
+     /* Kill all states to pfa */
+     if (tout || PF2_KILL_STATE_ALL) {
+-      bzero(&amp;psk.psk_src, sizeof(psk.psk_src));  /* clear source ad=
dress field (set before for incomming) */
+-      memcpy(&amp;psk.psk_dst.addr.v.a.addr, &amp;pfa, sizeof(psk.psk_d=
st.addr.v.a.addr));
+-      memset(&amp;psk.psk_dst.addr.v.a.mask, 0xff, sizeof(psk.psk_dst.a=
ddr.v.a.mask));
+-      if (ioctl(pfdev, DIOCKILLSTATES, &amp;psk)) {
++      bzero(&amp;k.src, sizeof(k.src));  /* clear source address field =
(set before for incomming) */
++      memcpy(&amp;k.dst.addr.v.a.addr, &amp;pfa, sizeof(k.dst.addr.v.a.=
addr));
++      memset(&amp;k.dst.addr.v.a.mask, 0xff, sizeof(k.dst.addr.v.a.mask=
));
++      if (pfctl_kill_states(pfdev, &amp;k, &amp;kcount)) {
+           snprintf(msg, sizeof(msg) - 1, &quot;Error: DIOCKILLSTATES fa=
iled (%s)&quot;, strerror(errno));
+           logmessage(1, msg, &quot;pf2&quot;, 0);
+       }
+       else {
+-#if OpenBSD &gt;=3D 200811 /* since OpenBSD4_4 killed states returned i=
n psk_killed */
+-          killed_dst +=3D psk.psk_killed;
+-#else
+-          killed_dst +=3D psk.psk_af;
+-#endif
++          killed_dst +=3D kcount;
+ #ifdef FWSAMDEBUG
+           printf(&quot;Debug: [pf2] killed %lu (tout) states for host %=
s\n&quot;, killed_dst, ipsrc);
+ #endif
</code></pre>
<p dir=3D"auto">Tl;dr If you maintain a port that uses /dev/pf you=E2=80=99=
re going to have to start using net/libpfctl.</p>
<p dir=3D"auto">Best regards,<br>
Kristof</p>

</div>
</div>
</body>

</html>

--=_MailMate_778328E2-0F61-4D1F-9B96-3408223FC9DB_=--



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?0E45DD6F-81E3-45DB-9FB2-E47B8F26FD00>