aboutsummaryrefslogtreecommitdiff
path: root/sys/netpfil/pf
diff options
context:
space:
mode:
authorLuiz Amaral <email@luiz.eng.br>2022-11-09 11:40:43 +0000
committerKristof Provost <kp@FreeBSD.org>2022-11-09 20:06:07 +0000
commit813c5b75e68073a724fdc032b24a12baeab8f6d9 (patch)
tree34131389bb7fc5ca80e69da4d3f49892993eb99f /sys/netpfil/pf
parentcfbf1da0deede6b82ac197471b6cd439706a2dea (diff)
downloadsrc-813c5b75e68073a724fdc032b24a12baeab8f6d9.tar.gz
src-813c5b75e68073a724fdc032b24a12baeab8f6d9.zip
pfsync: prepare code to accommodate AF_INET6 family
Work is ongoing to add support for pfsync over IPv6. This required some changes to allow for differentiating between the two families in a more generic way. This patch converts the relevant ioctls to using nvlists, making future extensions (such as supporting IPv6 addresses) easier. Sponsored by: InnoGames GmbH Differential Revision: https://reviews.freebsd.org/D36277
Diffstat (limited to 'sys/netpfil/pf')
-rw-r--r--sys/netpfil/pf/if_pfsync.c404
-rw-r--r--sys/netpfil/pf/pfsync_nv.c150
-rw-r--r--sys/netpfil/pf/pfsync_nv.h42
3 files changed, 475 insertions, 121 deletions
diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c
index 9cc25c83bd06..f8cca8a4460b 100644
--- a/sys/netpfil/pf/if_pfsync.c
+++ b/sys/netpfil/pf/if_pfsync.c
@@ -75,6 +75,7 @@ __FBSDID("$FreeBSD$");
#include <sys/mbuf.h>
#include <sys/module.h>
#include <sys/mutex.h>
+#include <sys/nv.h>
#include <sys/priv.h>
#include <sys/smp.h>
#include <sys/socket.h>
@@ -101,13 +102,19 @@ __FBSDID("$FreeBSD$");
#include <netinet/tcp_fsm.h>
#include <netinet/tcp_seq.h>
+#include <netpfil/pf/pfsync_nv.h>
+
+struct pfsync_bucket;
+
+union inet_template {
+ struct ip ipv4;
+};
+
#define PFSYNC_MINPKT ( \
- sizeof(struct ip) + \
+ sizeof(union inet_template) + \
sizeof(struct pfsync_header) + \
sizeof(struct pfsync_subheader) )
-struct pfsync_bucket;
-
static int pfsync_upd_tcp(struct pf_kstate *, struct pfsync_state_peer *,
struct pfsync_state_peer *);
static int pfsync_in_clr(struct mbuf *, int, int, int);
@@ -206,10 +213,10 @@ struct pfsync_softc {
struct ifnet *sc_ifp;
struct ifnet *sc_sync_if;
struct ip_moptions sc_imo;
- struct in_addr sc_sync_peer;
+ struct sockaddr_storage sc_sync_peer;
uint32_t sc_flags;
uint8_t sc_maxupdates;
- struct ip sc_template;
+ union inet_template sc_template;
struct mtx sc_mtx;
/* Queued data */
@@ -302,6 +309,12 @@ static void pfsync_bulk_update(void *);
static void pfsync_bulk_fail(void *);
static void pfsync_detach_ifnet(struct ifnet *);
+
+static int pfsync_pfsyncreq_to_kstatus(struct pfsyncreq *,
+ struct pfsync_kstatus *);
+static int pfsync_kstatus_to_softc(struct pfsync_kstatus *,
+ struct pfsync_softc *);
+
#ifdef IPSEC
static void pfsync_update_net_tdb(struct pfsync_tdb *);
#endif
@@ -617,6 +630,7 @@ cleanup_state: /* pf_state_insert() frees the state keys. */
return (error);
}
+#ifdef INET
static int
pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused)
{
@@ -716,6 +730,7 @@ done:
m_freem(m);
return (IPPROTO_DONE);
}
+#endif
static int
pfsync_in_clr(struct mbuf *m, int offset, int count, int flags)
@@ -1308,6 +1323,7 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
struct pfsync_softc *sc = ifp->if_softc;
struct ifreq *ifr = (struct ifreq *)data;
struct pfsyncreq pfsyncr;
+ size_t nvbuflen;
int error;
int c;
@@ -1346,18 +1362,56 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
strlcpy(pfsyncr.pfsyncr_syncdev,
sc->sc_sync_if->if_xname, IFNAMSIZ);
}
- pfsyncr.pfsyncr_syncpeer = sc->sc_sync_peer;
+ pfsyncr.pfsyncr_syncpeer = ((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr;
pfsyncr.pfsyncr_maxupdates = sc->sc_maxupdates;
pfsyncr.pfsyncr_defer = sc->sc_flags;
PFSYNC_UNLOCK(sc);
return (copyout(&pfsyncr, ifr_data_get_ptr(ifr),
sizeof(pfsyncr)));
+ case SIOCGETPFSYNCNV:
+ {
+ nvlist_t *nvl_syncpeer;
+ nvlist_t *nvl = nvlist_create(0);
+
+ if (nvl == NULL)
+ return (ENOMEM);
+
+ if (sc->sc_sync_if)
+ nvlist_add_string(nvl, "syncdev", sc->sc_sync_if->if_xname);
+ nvlist_add_number(nvl, "maxupdates", sc->sc_maxupdates);
+ nvlist_add_number(nvl, "flags", sc->sc_flags);
+ if ((nvl_syncpeer = pfsync_sockaddr_to_syncpeer_nvlist(&sc->sc_sync_peer)) != NULL)
+ nvlist_add_nvlist(nvl, "syncpeer", nvl_syncpeer);
+
+ void *packed = NULL;
+ packed = nvlist_pack(nvl, &nvbuflen);
+ if (packed == NULL) {
+ free(packed, M_NVLIST);
+ nvlist_destroy(nvl);
+ return (ENOMEM);
+ }
+
+ if (nvbuflen > ifr->ifr_cap_nv.buf_length) {
+ ifr->ifr_cap_nv.length = nvbuflen;
+ ifr->ifr_cap_nv.buffer = NULL;
+ free(packed, M_NVLIST);
+ nvlist_destroy(nvl);
+ return (EFBIG);
+ }
+
+ ifr->ifr_cap_nv.length = nvbuflen;
+ error = copyout(packed, ifr->ifr_cap_nv.buffer, nvbuflen);
+
+ nvlist_destroy(nvl);
+ nvlist_destroy(nvl_syncpeer);
+ free(packed, M_NVLIST);
+ break;
+ }
+
case SIOCSETPFSYNC:
{
- struct in_mfilter *imf = NULL;
- struct ifnet *sifp;
- struct ip *ip;
+ struct pfsync_kstatus status;
if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
return (error);
@@ -1365,101 +1419,44 @@ pfsyncioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
sizeof(pfsyncr))))
return (error);
- if (pfsyncr.pfsyncr_maxupdates > 255)
- return (EINVAL);
+ memset((char *)&status, 0, sizeof(struct pfsync_kstatus));
+ pfsync_pfsyncreq_to_kstatus(&pfsyncr, &status);
- if (pfsyncr.pfsyncr_syncdev[0] == 0)
- sifp = NULL;
- else if ((sifp = ifunit_ref(pfsyncr.pfsyncr_syncdev)) == NULL)
- return (EINVAL);
+ error = pfsync_kstatus_to_softc(&status, sc);
+ return (error);
+ }
+ case SIOCSETPFSYNCNV:
+ {
+ struct pfsync_kstatus status;
+ void *data;
+ nvlist_t *nvl;
- if (sifp != NULL && (
- pfsyncr.pfsyncr_syncpeer.s_addr == 0 ||
- pfsyncr.pfsyncr_syncpeer.s_addr ==
- htonl(INADDR_PFSYNC_GROUP)))
- imf = ip_mfilter_alloc(M_WAITOK, 0, 0);
+ if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0)
+ return (error);
+ if (ifr->ifr_cap_nv.length > IFR_CAP_NV_MAXBUFSIZE)
+ return (EINVAL);
- PFSYNC_LOCK(sc);
- if (pfsyncr.pfsyncr_syncpeer.s_addr == 0)
- sc->sc_sync_peer.s_addr = htonl(INADDR_PFSYNC_GROUP);
- else
- sc->sc_sync_peer.s_addr =
- pfsyncr.pfsyncr_syncpeer.s_addr;
-
- sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates;
- if (pfsyncr.pfsyncr_defer & PFSYNCF_DEFER) {
- sc->sc_flags |= PFSYNCF_DEFER;
- V_pfsync_defer_ptr = pfsync_defer;
- } else {
- sc->sc_flags &= ~PFSYNCF_DEFER;
- V_pfsync_defer_ptr = NULL;
- }
+ data = malloc(ifr->ifr_cap_nv.length, M_TEMP, M_WAITOK);
- if (sifp == NULL) {
- if (sc->sc_sync_if)
- if_rele(sc->sc_sync_if);
- sc->sc_sync_if = NULL;
- pfsync_multicast_cleanup(sc);
- PFSYNC_UNLOCK(sc);
- break;
+ if ((error = copyin(ifr->ifr_cap_nv.buffer, data,
+ ifr->ifr_cap_nv.length)) != 0) {
+ free(data, M_TEMP);
+ return (error);
}
- for (c = 0; c < pfsync_buckets; c++) {
- PFSYNC_BUCKET_LOCK(&sc->sc_buckets[c]);
- if (sc->sc_buckets[c].b_len > PFSYNC_MINPKT &&
- (sifp->if_mtu < sc->sc_ifp->if_mtu ||
- (sc->sc_sync_if != NULL &&
- sifp->if_mtu < sc->sc_sync_if->if_mtu) ||
- sifp->if_mtu < MCLBYTES - sizeof(struct ip)))
- pfsync_sendout(1, c);
- PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]);
+ if ((nvl = nvlist_unpack(data, ifr->ifr_cap_nv.length, 0)) == NULL) {
+ free(data, M_TEMP);
+ return (EINVAL);
}
- pfsync_multicast_cleanup(sc);
+ memset((char *)&status, 0, sizeof(struct pfsync_kstatus));
+ pfsync_nvstatus_to_kstatus(nvl, &status);
- if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
- error = pfsync_multicast_setup(sc, sifp, imf);
- if (error) {
- if_rele(sifp);
- ip_mfilter_free(imf);
- PFSYNC_UNLOCK(sc);
- return (error);
- }
- }
- if (sc->sc_sync_if)
- if_rele(sc->sc_sync_if);
- sc->sc_sync_if = sifp;
-
- ip = &sc->sc_template;
- bzero(ip, sizeof(*ip));
- ip->ip_v = IPVERSION;
- ip->ip_hl = sizeof(sc->sc_template) >> 2;
- ip->ip_tos = IPTOS_LOWDELAY;
- /* len and id are set later. */
- ip->ip_off = htons(IP_DF);
- ip->ip_ttl = PFSYNC_DFLTTL;
- ip->ip_p = IPPROTO_PFSYNC;
- ip->ip_src.s_addr = INADDR_ANY;
- ip->ip_dst.s_addr = sc->sc_sync_peer.s_addr;
-
- /* Request a full state table update. */
- if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p)
- (*carp_demote_adj_p)(V_pfsync_carp_adj,
- "pfsync bulk start");
- sc->sc_flags &= ~PFSYNCF_OK;
- if (V_pf_status.debug >= PF_DEBUG_MISC)
- printf("pfsync: requesting bulk update\n");
- PFSYNC_UNLOCK(sc);
- PFSYNC_BUCKET_LOCK(&sc->sc_buckets[0]);
- pfsync_request_update(0, 0);
- PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[0]);
- PFSYNC_BLOCK(sc);
- sc->sc_ureq_sent = time_uptime;
- callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail,
- sc);
- PFSYNC_BUNLOCK(sc);
+ nvlist_destroy(nvl);
+ free(data, M_TEMP);
- break;
+ error = pfsync_kstatus_to_softc(&status, sc);
+ return (error);
}
default:
return (ENOTTY);
@@ -1548,13 +1545,12 @@ pfsync_sendout(int schedswi, int c)
struct pfsync_softc *sc = V_pfsyncif;
struct ifnet *ifp = sc->sc_ifp;
struct mbuf *m;
- struct ip *ip;
struct pfsync_header *ph;
struct pfsync_subheader *subh;
struct pf_kstate *st, *st_next;
struct pfsync_upd_req_item *ur;
struct pfsync_bucket *b = &sc->sc_buckets[c];
- int offset;
+ int aflen, offset;
int q, count = 0;
KASSERT(sc != NULL, ("%s: null sc", __func__));
@@ -1577,12 +1573,25 @@ pfsync_sendout(int schedswi, int c)
m->m_len = m->m_pkthdr.len = b->b_len;
/* build the ip header */
- ip = (struct ip *)m->m_data;
- bcopy(&sc->sc_template, ip, sizeof(*ip));
- offset = sizeof(*ip);
+ switch (sc->sc_sync_peer.ss_family) {
+#ifdef INET
+ case AF_INET:
+ {
+ struct ip *ip;
+
+ ip = mtod(m, struct ip *);
+ bcopy(&sc->sc_template.ipv4, ip, sizeof(*ip));
+ aflen = offset = sizeof(*ip);
+
+ ip->ip_len = htons(m->m_pkthdr.len);
+ ip_fillid(ip);
+ break;
+ }
+#endif
+ default:
+ return;
+ }
- ip->ip_len = htons(m->m_pkthdr.len);
- ip_fillid(ip);
/* build the pfsync header */
ph = (struct pfsync_header *)(m->m_data + offset);
@@ -1590,7 +1599,7 @@ pfsync_sendout(int schedswi, int c)
offset += sizeof(*ph);
ph->version = PFSYNC_VERSION;
- ph->len = htons(b->b_len - sizeof(*ip));
+ ph->len = htons(b->b_len - aflen);
bcopy(V_pf_status.pf_chksum, ph->pfcksum, PF_MD5_DIGEST_LENGTH);
/* walk the queues */
@@ -1663,10 +1672,10 @@ pfsync_sendout(int schedswi, int c)
/* we're done, let's put it on the wire */
if (ifp->if_bpf) {
- m->m_data += sizeof(*ip);
- m->m_len = m->m_pkthdr.len = b->b_len - sizeof(*ip);
+ m->m_data += aflen;
+ m->m_len = m->m_pkthdr.len = b->b_len - aflen;
BPF_MTAP(ifp, m);
- m->m_data -= sizeof(*ip);
+ m->m_data -= aflen;
m->m_len = m->m_pkthdr.len = b->b_len;
}
@@ -1819,7 +1828,13 @@ pfsync_defer_tmo(void *arg)
free(pd, M_PFSYNC);
PFSYNC_BUCKET_UNLOCK(b);
- ip_output(m, NULL, NULL, 0, NULL, NULL);
+ switch (sc->sc_sync_peer.ss_family) {
+#ifdef INET
+ case AF_INET:
+ ip_output(m, NULL, NULL, 0, NULL, NULL);
+ break;
+#endif
+ }
pf_release_state(st);
@@ -2309,7 +2324,7 @@ pfsyncintr(void *arg)
struct pfsync_softc *sc = arg;
struct pfsync_bucket *b;
struct mbuf *m, *n;
- int c;
+ int c, error;
NET_EPOCH_ENTER(et);
CURVNET_SET(sc->sc_ifp->if_vnet);
@@ -2334,10 +2349,21 @@ pfsyncintr(void *arg)
* own pfsync packet based on M_SKIP_FIREWALL
* flag. This is XXX.
*/
- if (m->m_flags & M_SKIP_FIREWALL)
- ip_output(m, NULL, NULL, 0, NULL, NULL);
- else if (ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo,
- NULL) == 0)
+ switch (sc->sc_sync_peer.ss_family) {
+#ifdef INET
+ case AF_INET:
+ if (m->m_flags & M_SKIP_FIREWALL) {
+ error = ip_output(m, NULL, NULL, 0,
+ NULL, NULL);
+ } else {
+ error = ip_output(m, NULL, NULL,
+ IP_RAWOUTPUT, &sc->sc_imo, NULL);
+ }
+ break;
+#endif
+ }
+
+ if (error == 0)
V_pfsyncstats.pfsyncs_opackets++;
else
V_pfsyncstats.pfsyncs_oerrors++;
@@ -2357,17 +2383,24 @@ pfsync_multicast_setup(struct pfsync_softc *sc, struct ifnet *ifp,
if (!(ifp->if_flags & IFF_MULTICAST))
return (EADDRNOTAVAIL);
- imo->imo_multicast_vif = -1;
-
- if ((error = in_joingroup(ifp, &sc->sc_sync_peer, NULL,
- &imf->imf_inm)) != 0)
- return (error);
+ switch (sc->sc_sync_peer.ss_family) {
+#ifdef INET
+ case AF_INET:
+ {
+ ip_mfilter_init(&imo->imo_head);
+ imo->imo_multicast_vif = -1;
+ if ((error = in_joingroup(ifp, &((struct sockaddr_in *)&sc->sc_sync_peer)->sin_addr, NULL,
+ &imf->imf_inm)) != 0)
+ return (error);
- ip_mfilter_init(&imo->imo_head);
- ip_mfilter_insert(&imo->imo_head, imf);
- imo->imo_multicast_ifp = ifp;
- imo->imo_multicast_ttl = PFSYNC_DFLTTL;
- imo->imo_multicast_loop = 0;
+ ip_mfilter_insert(&imo->imo_head, imf);
+ imo->imo_multicast_ifp = ifp;
+ imo->imo_multicast_ttl = PFSYNC_DFLTTL;
+ imo->imo_multicast_loop = 0;
+ break;
+ }
+#endif
+ }
return (0);
}
@@ -2409,6 +2442,135 @@ pfsync_detach_ifnet(struct ifnet *ifp)
PFSYNC_UNLOCK(sc);
}
+static int
+pfsync_pfsyncreq_to_kstatus(struct pfsyncreq *pfsyncr, struct pfsync_kstatus *status)
+{
+ struct sockaddr_storage sa;
+ status->maxupdates = pfsyncr->pfsyncr_maxupdates;
+ status->flags = pfsyncr->pfsyncr_defer;
+
+ strlcpy(status->syncdev, pfsyncr->pfsyncr_syncdev, IFNAMSIZ);
+
+ memset(&sa, 0, sizeof(sa));
+ if (pfsyncr->pfsyncr_syncpeer.s_addr != 0) {
+ struct sockaddr_in *in = (struct sockaddr_in *)&sa;
+ in->sin_family = AF_INET;
+ in->sin_len = sizeof(*in);
+ in->sin_addr.s_addr = pfsyncr->pfsyncr_syncpeer.s_addr;
+ }
+ status->syncpeer = sa;
+
+ return 0;
+}
+
+static int
+pfsync_kstatus_to_softc(struct pfsync_kstatus *status, struct pfsync_softc *sc)
+{
+ struct in_mfilter *imf = NULL;
+ struct ifnet *sifp;
+ struct ip *ip;
+ int error;
+ int c;
+
+ if ((status->maxupdates < 0) || (status->maxupdates > 255))
+ return (EINVAL);
+
+ if (status->syncdev[0] == '\0')
+ sifp = NULL;
+ else if ((sifp = ifunit_ref(status->syncdev)) == NULL)
+ return (EINVAL);
+
+ struct sockaddr_in *status_sin =
+ (struct sockaddr_in *)&(status->syncpeer);
+ if (sifp != NULL && (status_sin->sin_addr.s_addr == 0 ||
+ status_sin->sin_addr.s_addr ==
+ htonl(INADDR_PFSYNC_GROUP)))
+ imf = ip_mfilter_alloc(M_WAITOK, 0, 0);
+
+ PFSYNC_LOCK(sc);
+ struct sockaddr_in *sc_sin = (struct sockaddr_in *)&sc->sc_sync_peer;
+ sc_sin->sin_family = AF_INET;
+ sc_sin->sin_len = sizeof(*sc_sin);
+ if (status_sin->sin_addr.s_addr == 0) {
+ sc_sin->sin_addr.s_addr = htonl(INADDR_PFSYNC_GROUP);
+ } else {
+ sc_sin->sin_addr.s_addr = status_sin->sin_addr.s_addr;
+ }
+
+ sc->sc_maxupdates = status->maxupdates;
+ if (status->flags & PFSYNCF_DEFER) {
+ sc->sc_flags |= PFSYNCF_DEFER;
+ V_pfsync_defer_ptr = pfsync_defer;
+ } else {
+ sc->sc_flags &= ~PFSYNCF_DEFER;
+ V_pfsync_defer_ptr = NULL;
+ }
+
+ if (sifp == NULL) {
+ if (sc->sc_sync_if)
+ if_rele(sc->sc_sync_if);
+ sc->sc_sync_if = NULL;
+ pfsync_multicast_cleanup(sc);
+ PFSYNC_UNLOCK(sc);
+ return (0);
+ }
+
+ for (c = 0; c < pfsync_buckets; c++) {
+ PFSYNC_BUCKET_LOCK(&sc->sc_buckets[c]);
+ if (sc->sc_buckets[c].b_len > PFSYNC_MINPKT &&
+ (sifp->if_mtu < sc->sc_ifp->if_mtu ||
+ (sc->sc_sync_if != NULL &&
+ sifp->if_mtu < sc->sc_sync_if->if_mtu) ||
+ sifp->if_mtu < MCLBYTES - sizeof(struct ip)))
+ pfsync_sendout(1, c);
+ PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[c]);
+ }
+
+ pfsync_multicast_cleanup(sc);
+
+ if (sc_sin->sin_addr.s_addr == htonl(INADDR_PFSYNC_GROUP)) {
+ error = pfsync_multicast_setup(sc, sifp, imf);
+ if (error) {
+ if_rele(sifp);
+ ip_mfilter_free(imf);
+ PFSYNC_UNLOCK(sc);
+ return (error);
+ }
+ }
+ if (sc->sc_sync_if)
+ if_rele(sc->sc_sync_if);
+ sc->sc_sync_if = sifp;
+
+ ip = &sc->sc_template.ipv4;
+ bzero(ip, sizeof(*ip));
+ ip->ip_v = IPVERSION;
+ ip->ip_hl = sizeof(sc->sc_template.ipv4) >> 2;
+ ip->ip_tos = IPTOS_LOWDELAY;
+ /* len and id are set later. */
+ ip->ip_off = htons(IP_DF);
+ ip->ip_ttl = PFSYNC_DFLTTL;
+ ip->ip_p = IPPROTO_PFSYNC;
+ ip->ip_src.s_addr = INADDR_ANY;
+ ip->ip_dst.s_addr = sc_sin->sin_addr.s_addr;
+
+ /* Request a full state table update. */
+ if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p)
+ (*carp_demote_adj_p)(V_pfsync_carp_adj,
+ "pfsync bulk start");
+ sc->sc_flags &= ~PFSYNCF_OK;
+ if (V_pf_status.debug >= PF_DEBUG_MISC)
+ printf("pfsync: requesting bulk update\n");
+ PFSYNC_UNLOCK(sc);
+ PFSYNC_BUCKET_LOCK(&sc->sc_buckets[0]);
+ pfsync_request_update(0, 0);
+ PFSYNC_BUCKET_UNLOCK(&sc->sc_buckets[0]);
+ PFSYNC_BLOCK(sc);
+ sc->sc_ureq_sent = time_uptime;
+ callout_reset(&sc->sc_bulkfail_tmo, 5 * hz, pfsync_bulk_fail, sc);
+ PFSYNC_BUNLOCK(sc);
+ return (0);
+}
+
static void
pfsync_pointers_init(void)
{
diff --git a/sys/netpfil/pf/pfsync_nv.c b/sys/netpfil/pf/pfsync_nv.c
new file mode 100644
index 000000000000..a6a27c9461fe
--- /dev/null
+++ b/sys/netpfil/pf/pfsync_nv.c
@@ -0,0 +1,150 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2022 InnoGames GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_inet.h"
+#include "opt_inet6.h"
+
+#include <sys/param.h>
+#include <sys/errno.h>
+
+#include <netpfil/pf/pfsync_nv.h>
+
+int
+pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *nvl,
+ struct sockaddr_storage *sa)
+{
+ int af;
+
+ if (!nvlist_exists_number(nvl, "af"))
+ return (EINVAL);
+ if (!nvlist_exists_binary(nvl, "address"))
+ return (EINVAL);
+
+ af = nvlist_get_number(nvl, "af");
+
+ switch (af) {
+#ifdef INET
+ case AF_INET: {
+ struct sockaddr_in *in = (struct sockaddr_in *)sa;
+ size_t len;
+ const void *addr = nvlist_get_binary(nvl, "address", &len);
+ in->sin_family = af;
+ if (len != sizeof(*in))
+ return (EINVAL);
+
+ memcpy(in, addr, sizeof(*in));
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
+ size_t len;
+ const void *addr = nvlist_get_binary(nvl, "address", &len);
+ in6->sin6_family = af;
+ if (len != sizeof(*in6))
+ return (EINVAL);
+
+ memcpy(in6, addr, sizeof(*in6));
+ break;
+ }
+#endif
+ default:
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+nvlist_t *
+pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *sa)
+{
+ nvlist_t *nvl;
+
+ nvl = nvlist_create(0);
+ if (nvl == NULL) {
+ return (nvl);
+ }
+
+ switch (sa->ss_family) {
+#ifdef INET
+ case AF_INET: {
+ struct sockaddr_in *in = (struct sockaddr_in *)sa;
+ nvlist_add_number(nvl, "af", in->sin_family);
+ nvlist_add_binary(nvl, "address", in, sizeof(*in));
+ break;
+ }
+#endif
+#ifdef INET6
+ case AF_INET6: {
+ struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;
+ nvlist_add_number(nvl, "af", in6->sin6_family);
+ nvlist_add_binary(nvl, "address", in6, sizeof(*in6));
+ break;
+ }
+#endif
+ default:
+ return NULL;
+ }
+
+ return (nvl);
+}
+
+int
+pfsync_nvstatus_to_kstatus(const nvlist_t *nvl, struct pfsync_kstatus *status)
+{
+ struct sockaddr_storage addr;
+ int error;
+
+ if (!nvlist_exists_number(nvl, "maxupdates"))
+ return (EINVAL);
+ if (!nvlist_exists_number(nvl, "flags"))
+ return (EINVAL);
+
+ status->maxupdates = nvlist_get_number(nvl, "maxupdates");
+ status->flags = nvlist_get_number(nvl, "flags");
+
+ if (nvlist_exists_string(nvl, "syncdev"))
+ strlcpy(status->syncdev, nvlist_get_string(nvl, "syncdev"),
+ IFNAMSIZ);
+
+ if (nvlist_exists_nvlist(nvl, "syncpeer")) {
+ memset(&addr, 0, sizeof(addr));
+ if ((error = pfsync_syncpeer_nvlist_to_sockaddr(nvlist_get_nvlist(nvl, "syncpeer"), &addr)) != 0)
+ return (error);
+
+ status->syncpeer = addr;
+ } else {
+ memset(&status->syncpeer, 0, sizeof(status->syncpeer));
+ }
+
+ return (0);
+}
diff --git a/sys/netpfil/pf/pfsync_nv.h b/sys/netpfil/pf/pfsync_nv.h
new file mode 100644
index 000000000000..3464e363e3a7
--- /dev/null
+++ b/sys/netpfil/pf/pfsync_nv.h
@@ -0,0 +1,42 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2022 InnoGames GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _PFSYNC_NV_H
+#define _PFSYNC_NV_H
+
+#include <sys/nv.h>
+#include <sys/socket.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/if_pfsync.h>
+
+int pfsync_syncpeer_nvlist_to_sockaddr(const nvlist_t *, struct sockaddr_storage *);
+nvlist_t *pfsync_sockaddr_to_syncpeer_nvlist(struct sockaddr_storage *);
+int pfsync_nvstatus_to_kstatus(const nvlist_t *, struct pfsync_kstatus *);
+#endif /* !_PFSYNC_NV_H */