diff options
author | Luiz Amaral <email@luiz.eng.br> | 2022-11-09 11:40:43 +0000 |
---|---|---|
committer | Kristof Provost <kp@FreeBSD.org> | 2022-11-09 20:06:07 +0000 |
commit | 813c5b75e68073a724fdc032b24a12baeab8f6d9 (patch) | |
tree | 34131389bb7fc5ca80e69da4d3f49892993eb99f /sys/netpfil/pf | |
parent | cfbf1da0deede6b82ac197471b6cd439706a2dea (diff) | |
download | src-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.c | 404 | ||||
-rw-r--r-- | sys/netpfil/pf/pfsync_nv.c | 150 | ||||
-rw-r--r-- | sys/netpfil/pf/pfsync_nv.h | 42 |
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 */ |