diff --git a/sbin/ifconfig/ifpfsync.c b/sbin/ifconfig/ifpfsync.c --- a/sbin/ifconfig/ifpfsync.c +++ b/sbin/ifconfig/ifpfsync.c @@ -97,7 +97,7 @@ setpfsync_syncpeer(const char *val, int d, int s, const struct afswtch *rafp) { struct pfsyncreq preq; - struct addrinfo hints, *peerres; + struct addrinfo *peerres; int ecode; bzero((char *)&preq, sizeof(struct pfsyncreq)); @@ -106,19 +106,25 @@ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1) err(1, "SIOCGETPFSYNC"); - memset(&hints, 0, sizeof(hints)); - hints.ai_family = AF_INET; - hints.ai_socktype = SOCK_DGRAM; /*dummy*/ - - if ((ecode = getaddrinfo(val, NULL, &hints, &peerres)) != 0) + if ((ecode = getaddrinfo(val, NULL, NULL, &peerres)) != 0) errx(1, "error in parsing address string: %s", gai_strerror(ecode)); - if (peerres->ai_addr->sa_family != AF_INET) - errx(1, "only IPv4 addresses supported for the syncpeer"); + switch (peerres->ai_family) { +#ifdef INET + case AF_INET: { + struct sockaddr_in *sin = (struct sockaddr_in *)peerres->ai_addr; + + if (IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) + errx(1, "syncpeer address cannot be multicast"); - preq.pfsyncr_syncpeer.s_addr = ((struct sockaddr_in *) - peerres->ai_addr)->sin_addr.s_addr; + preq.pfsyncr_syncpeer.in4 = *sin; + break; + } +#endif + default: + errx(1, "syncpeer address %s not supported", val); + } if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1) err(1, "SIOCSETPFSYNC"); @@ -137,7 +143,16 @@ if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1) err(1, "SIOCGETPFSYNC"); - preq.pfsyncr_syncpeer.s_addr = 0; + switch (preq.pfsyncr_syncpeer.sa.sa_family) { +#ifdef INET + case AF_INET: +#endif + { + bzero((char *)&preq.pfsyncr_syncpeer, + sizeof(union pfsync_sockaddr)); + break; + } + } if (ioctl(s, SIOCSETPFSYNC, (caddr_t)&ifr) == -1) err(1, "SIOCSETPFSYNC"); @@ -187,24 +202,35 @@ pfsync_status(int s) { struct pfsyncreq preq; + char syncpeer[NI_MAXHOST]; + struct sockaddr *syncpeer_sa; + int error; bzero((char *)&preq, sizeof(struct pfsyncreq)); ifr.ifr_data = (caddr_t)&preq; + syncpeer_sa = &preq.pfsyncr_syncpeer.sa; if (ioctl(s, SIOCGETPFSYNC, (caddr_t)&ifr) == -1) return; if (preq.pfsyncr_syncdev[0] != '\0' || - preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP)) - printf("\t"); + syncpeer_sa->sa_family != AF_UNSPEC) + printf("\t"); if (preq.pfsyncr_syncdev[0] != '\0') - printf("pfsync: syncdev: %s ", preq.pfsyncr_syncdev); - if (preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP)) - printf("syncpeer: %s ", inet_ntoa(preq.pfsyncr_syncpeer)); + printf("syncdev: %s ", preq.pfsyncr_syncdev); + + if (preq.pfsyncr_syncpeer.sa.sa_family != AF_UNSPEC && + preq.pfsyncr_syncpeer.in4.sin_addr.s_addr != htonl(INADDR_PFSYNC_GROUP)) { + if ((error = getnameinfo(syncpeer_sa, syncpeer_sa->sa_len, + syncpeer, sizeof(syncpeer), NULL, 0, NI_NUMERICHOST)) != 0) + errx(1, "getnameinfo: %s", gai_strerror(error)); + printf("syncpeer: %s ", syncpeer); + } if (preq.pfsyncr_syncdev[0] != '\0' || - preq.pfsyncr_syncpeer.s_addr != htonl(INADDR_PFSYNC_GROUP)) { + (preq.pfsyncr_syncpeer.sa.sa_family != AF_UNSPEC && + preq.pfsyncr_syncpeer.in4.sin_addr.s_addr != htonl(INADDR_PFSYNC_GROUP))) { printf("maxupd: %d ", preq.pfsyncr_maxupdates); printf("defer: %s\n", (preq.pfsyncr_defer & PFSYNCF_DEFER) ? "on" : "off"); diff --git a/sys/net/if_pfsync.h b/sys/net/if_pfsync.h --- a/sys/net/if_pfsync.h +++ b/sys/net/if_pfsync.h @@ -54,6 +54,7 @@ #include #include +#include #include #define PFSYNC_VERSION 5 @@ -235,16 +236,21 @@ u_int64_t pfsyncs_oacts[PFSYNC_ACT_MAX]; }; +union pfsync_sockaddr { + struct sockaddr sa; + struct sockaddr_in in4; +}; + /* * Configuration structure for SIOCSETPFSYNC SIOCGETPFSYNC */ struct pfsyncreq { - char pfsyncr_syncdev[IFNAMSIZ]; - struct in_addr pfsyncr_syncpeer; - int pfsyncr_maxupdates; + char pfsyncr_syncdev[IFNAMSIZ]; + union pfsync_sockaddr pfsyncr_syncpeer; + int pfsyncr_maxupdates; #define PFSYNCF_OK 0x00000001 #define PFSYNCF_DEFER 0x00000002 - int pfsyncr_defer; + int pfsyncr_defer; }; #define SIOCSETPFSYNC _IOW('i', 247, struct ifreq) diff --git a/sys/netpfil/pf/if_pfsync.c b/sys/netpfil/pf/if_pfsync.c --- a/sys/netpfil/pf/if_pfsync.c +++ b/sys/netpfil/pf/if_pfsync.c @@ -101,16 +101,23 @@ #include #include +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; - struct pfsync_pkt { - struct ip *ip; - struct in_addr src; +#ifdef INET + struct ip *ip4; + struct in_addr src4; +#endif + sa_family_t af; u_int8_t flags; }; @@ -212,10 +219,10 @@ struct ifnet *sc_ifp; struct ifnet *sc_sync_if; struct ip_moptions sc_imo; - struct in_addr sc_sync_peer; + union pfsync_sockaddr 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 */ @@ -622,6 +629,7 @@ return (error); } +#ifdef INET static int pfsync_input(struct mbuf **mp, int *offp __unused, int proto __unused) { @@ -688,8 +696,10 @@ } /* Cheaper to grab this now than having to mess with mbufs later */ - pkt.ip = ip; - pkt.src = ip->ip_src; + // XXX: Is this even needed? Except for flags, other values seem unused + pkt.af = AF_INET; + pkt.ip4 = ip; + pkt.src4 = ip->ip_src; pkt.flags = 0; /* @@ -727,6 +737,7 @@ m_freem(m); return (IPPROTO_DONE); } +#endif static int pfsync_in_clr(struct pfsync_pkt *pkt, struct mbuf *m, int offset, int count) @@ -1368,7 +1379,6 @@ { struct in_mfilter *imf = NULL; struct ifnet *sifp; - struct ip *ip; if ((error = priv_check(curthread, PRIV_NETINET_PF)) != 0) return (error); @@ -1383,19 +1393,19 @@ sifp = NULL; else if ((sifp = ifunit_ref(pfsyncr.pfsyncr_syncdev)) == NULL) return (EINVAL); - - if (sifp != NULL && ( - pfsyncr.pfsyncr_syncpeer.s_addr == 0 || - pfsyncr.pfsyncr_syncpeer.s_addr == - htonl(INADDR_PFSYNC_GROUP))) + if (sifp != NULL && (sc->sc_sync_peer.sa.sa_family == AF_UNSPEC)) { imf = ip_mfilter_alloc(M_WAITOK, 0, 0); + } 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; + if (sifp != NULL && (sc->sc_sync_peer.sa.sa_family == AF_UNSPEC)) { + struct sockaddr_in peer_addr; + peer_addr.sin_family = AF_INET; + peer_addr.sin_addr.s_addr = htonl(INADDR_PFSYNC_GROUP); + sc->sc_sync_peer.in4 = peer_addr; + + } else + sc->sc_sync_peer = pfsyncr.pfsyncr_syncpeer; sc->sc_maxupdates = pfsyncr.pfsyncr_maxupdates; if (pfsyncr.pfsyncr_defer & PFSYNCF_DEFER) { @@ -1428,7 +1438,7 @@ pfsync_multicast_cleanup(sc); - if (sc->sc_sync_peer.s_addr == htonl(INADDR_PFSYNC_GROUP)) { + if (sc->sc_sync_peer.in4.sin_addr.s_addr == htonl(INADDR_PFSYNC_GROUP)) { error = pfsync_multicast_setup(sc, sifp, imf); if (error) { if_rele(sifp); @@ -1441,17 +1451,26 @@ 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; + switch (sc->sc_sync_peer.sa.sa_family) { +#ifdef INET + case AF_INET: { + struct ip *ip; + 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->sc_sync_peer.in4.sin_addr.s_addr; + break; + } +#endif + } /* Request a full state table update. */ if ((sc->sc_flags & PFSYNCF_OK) && carp_demote_adj_p) @@ -1559,13 +1578,12 @@ 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__)); @@ -1588,12 +1606,23 @@ 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.sa.sa_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); @@ -1601,7 +1630,7 @@ 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 */ @@ -1674,10 +1703,10 @@ /* 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; } @@ -1830,7 +1859,13 @@ free(pd, M_PFSYNC); PFSYNC_BUCKET_UNLOCK(b); - ip_output(m, NULL, NULL, 0, NULL, NULL); + switch (sc->sc_sync_peer.sa.sa_family) { +#ifdef INET + case AF_INET: + ip_output(m, NULL, NULL, 0, NULL, NULL); + break; +#endif + } pf_release_state(st); @@ -2320,7 +2355,7 @@ 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); @@ -2345,10 +2380,21 @@ * 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.sa.sa_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++; @@ -2368,17 +2414,24 @@ 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.sa.sa_family) { +#ifdef INET + case AF_INET: + { + ip_mfilter_init(&imo->imo_head); + imo->imo_multicast_vif = -1; + if ((error = in_joingroup(ifp, &sc->sc_sync_peer.in4.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); }