so pflow(4) shoving it's data with ip_output into the network stack
seems wrong. this converts it to use sosend(9) and might even give us
non-legacy IP support.

tests from (heavy) pflow(4) users would be appriciated.

diff --git if_pflow.c if_pflow.c
index 4f3ac5e..624fdaf 100644
--- if_pflow.c
+++ if_pflow.c
@@ -28,6 +28,8 @@
 #include <sys/timeout.h>
 #include <sys/ioctl.h>
 #include <sys/kernel.h>
+#include <sys/socket.h>
+#include <sys/socketvar.h>
 #include <sys/sysctl.h>
 
 #include <net/if.h>
@@ -94,7 +96,6 @@ int   pflow_pack_flow(struct pf_state *, struct pf_state_key 
*,
        struct pflow_softc *);
 int    pflow_pack_flow_ipfix(struct pf_state *, struct pf_state_key *,
        struct pflow_softc *);
-int    pflow_get_dynport(void);
 int    export_pflow_if(struct pf_state*, struct pf_state_key *,
        struct pflow_softc *);
 int    copy_flow_to_m(struct pflow_flow *flow, struct pflow_softc *sc);
@@ -107,6 +108,8 @@ struct if_clone     pflow_cloner =
     IF_CLONE_INITIALIZER("pflow", pflow_clone_create,
     pflow_clone_destroy);
 
+extern struct proc proc0;
+
 void
 pflowattach(int npflow)
 {
@@ -119,22 +122,51 @@ pflow_clone_create(struct if_clone *ifc, int unit)
 {
        struct ifnet            *ifp;
        struct pflow_softc      *pflowif;
+       struct socket           *so;
+       struct sockaddr_in      *sin;
+       struct mbuf             *m;
+       int                      error;
+
+       error = 0;
+       m = NULL;
+
+       error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
+       if (error)
+               return (error);
+
+       MGET(m, M_WAIT, MT_SONAME);
+       sin = mtod(m, struct sockaddr_in *);
+       sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = INADDR_ANY;
+       sin->sin_port = htons(0);
+       error = sobind(so, m, &proc0);
+       m_freem(m);
+       if (error) {
+               soclose(so);
+               pflowif->so = NULL;
+               return (error);
+       }
 
        if ((pflowif = malloc(sizeof(*pflowif),
-           M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
-               return (ENOMEM);
-
-       if ((pflowif->sc_imo.imo_membership = malloc(
-           (sizeof(struct in_multi *) * IP_MIN_MEMBERSHIPS), M_IPMOPTS,
-           M_WAITOK|M_ZERO)) == NULL) {
-               free(pflowif, M_DEVBUF, 0);
+           M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL) {
+               soclose(so);
+               pflowif->so = NULL;
                return (ENOMEM);
        }
-       pflowif->sc_imo.imo_max_memberships = IP_MIN_MEMBERSHIPS;
+
+       pflowif->so = so;
+
+       MGET(pflowif->send_nam, M_WAIT, MT_SONAME);
+       sin = mtod(pflowif->send_nam, struct sockaddr_in *);
+       sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
+       sin->sin_family = AF_INET;
+       sin->sin_addr.s_addr = INADDR_ANY;
+       sin->sin_port = 0;
+
        pflowif->sc_receiver_ip.s_addr = INADDR_ANY;
        pflowif->sc_receiver_port = 0;
        pflowif->sc_sender_ip.s_addr = INADDR_ANY;
-       pflowif->sc_sender_port = pflow_get_dynport();
        pflowif->sc_version = PFLOW_PROTO_DEFAULT;
 
        /* ipfix template init */
@@ -244,10 +276,6 @@ pflow_clone_create(struct if_clone *ifc, int unit)
        if_attach(ifp);
        if_alloc_sadl(ifp);
 
-#if NBPFILTER > 0
-       bpfattach(&pflowif->sc_if.if_bpf, ifp, DLT_RAW, 0);
-#endif
-
        /* Insert into list of pflows */
        SLIST_INSERT_HEAD(&pflowif_list, pflowif, sc_next);
        return (0);
@@ -257,9 +285,15 @@ int
 pflow_clone_destroy(struct ifnet *ifp)
 {
        struct pflow_softc      *sc = ifp->if_softc;
-       int                      s;
+       int                      s, error;
+
+       error = 0;
+       if (sc->so != NULL)
+               error = soclose(sc->so);
 
        s = splnet();
+       sc->so = NULL;
+       m_freem(sc->send_nam);
        if (timeout_initialized(&sc->sc_tmo))
                timeout_del(&sc->sc_tmo);
        if (timeout_initialized(&sc->sc_tmo6))
@@ -269,10 +303,9 @@ pflow_clone_destroy(struct ifnet *ifp)
        pflow_flush(sc);
        if_detach(ifp);
        SLIST_REMOVE(&pflowif_list, sc, pflow_softc, sc_next);
-       free(sc->sc_imo.imo_membership, M_IPMOPTS, 0);
        free(sc, M_DEVBUF, 0);
        splx(s);
-       return (0);
+       return (error);
 }
 
 /*
@@ -312,6 +345,9 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        struct pflow_softc      *sc = ifp->if_softc;
        struct ifreq            *ifr = (struct ifreq *)data;
        struct pflowreq          pflowr;
+       struct socket           *so;
+       struct sockaddr_in      *sin;
+       struct mbuf             *m;
        int                      s, error;
 
        switch (cmd) {
@@ -321,8 +357,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        case SIOCSIFFLAGS:
                if ((ifp->if_flags & IFF_UP) &&
                    sc->sc_receiver_ip.s_addr != INADDR_ANY &&
-                   sc->sc_receiver_port != 0 &&
-                   sc->sc_sender_port != 0) {
+                   sc->sc_receiver_port != 0 && sc->so != NULL) {
                        ifp->if_flags |= IFF_RUNNING;
                        sc->sc_gcounter=pflowstats.pflow_flows;
                        /* send templates on startup */
@@ -374,16 +409,49 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                                return(EINVAL);
                        }
                }
-               s = splnet();
 
+               s = splnet();
                pflow_flush(sc);
+               splx(s);
 
-               if (pflowr.addrmask & PFLOW_MASK_DSTIP)
+               if (pflowr.addrmask & PFLOW_MASK_DSTIP) {
+                       s = splnet();
                        sc->sc_receiver_ip.s_addr = pflowr.receiver_ip.s_addr;
-               if (pflowr.addrmask & PFLOW_MASK_DSTPRT)
+                       sin = mtod(sc->send_nam, struct sockaddr_in *);
+                       sin->sin_addr.s_addr = sc->sc_receiver_ip.s_addr;
+                       splx(s);
+               }
+               if (pflowr.addrmask & PFLOW_MASK_DSTPRT) {
+                       s = splnet();
                        sc->sc_receiver_port = pflowr.receiver_port;
-               if (pflowr.addrmask & PFLOW_MASK_SRCIP)
+                       sin = mtod(sc->send_nam, struct sockaddr_in *);
+                       sin->sin_port = pflowr.receiver_port;
+                       splx(s);
+               }
+               if (pflowr.addrmask & PFLOW_MASK_SRCIP) {
+                       error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
+                       if (error)
+                               return (error);
+                       
+                       MGET(m, M_WAIT, MT_SONAME);
+                       sin = mtod(m, struct sockaddr_in *);
+                       sin->sin_len = m->m_len = sizeof (struct sockaddr_in);
+                       sin->sin_family = AF_INET;
+                       sin->sin_addr.s_addr = pflowr.sender_ip.s_addr;
+                       sin->sin_port = 0;
+
+                       error = sobind(so, m, &proc0);
+                       m_freem(m);
+                       if (error)
+                               return (error);
+
+                       s = splnet();
                        sc->sc_sender_ip.s_addr = pflowr.sender_ip.s_addr;
+                       sc->so = so;
+                       splx(s);
+               }
+
+               s = splnet();
                /* error check is above */
                if (pflowr.addrmask & PFLOW_MASK_VERSION)
                        sc->sc_version = pflowr.version;
@@ -395,8 +463,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 
                if ((ifp->if_flags & IFF_UP) &&
                    sc->sc_receiver_ip.s_addr != INADDR_ANY &&
-                   sc->sc_receiver_port != 0 &&
-                   sc->sc_sender_port != 0) {
+                   sc->sc_receiver_port != 0 && sc->so != NULL) {
                        ifp->if_flags |= IFF_RUNNING;
                        sc->sc_gcounter=pflowstats.pflow_flows;
                        if (sc->sc_version == PFLOW_PROTO_10) {
@@ -1083,78 +1150,12 @@ pflow_sendout_ipfix_tmpl(struct pflow_softc *sc)
 int
 pflow_sendout_mbuf(struct pflow_softc *sc, struct mbuf *m)
 {
-       struct udpiphdr *ui;
-       u_int16_t        len = m->m_pkthdr.len;
-#if NBPFILTER > 0
-       struct ifnet    *ifp = &sc->sc_if;
-#endif
-       struct ip       *ip;
-       int              err;
-
-       /* UDP Header*/
-       M_PREPEND(m, sizeof(struct udpiphdr), M_DONTWAIT);
-       if (m == NULL) {
-               pflowstats.pflow_onomem++;
-               return (ENOBUFS);
-       }
-
-       ui = mtod(m, struct udpiphdr *);
-       ui->ui_pr = IPPROTO_UDP;
-       ui->ui_src = sc->sc_sender_ip;
-       ui->ui_sport = sc->sc_sender_port;
-       ui->ui_dst = sc->sc_receiver_ip;
-       ui->ui_dport = sc->sc_receiver_port;
-       ui->ui_ulen = htons(sizeof(struct udphdr) + len);
-       ui->ui_sum = 0;
-       m->m_pkthdr.csum_flags |= M_UDP_CSUM_OUT;
-       m->m_pkthdr.ph_rtableid = sc->sc_if.if_rdomain;
-
-       ip = (struct ip *)ui;
-       ip->ip_v = IPVERSION;
-       ip->ip_hl = sizeof(struct ip) >> 2;
-       ip->ip_id = htons(ip_randomid());
-       ip->ip_off = htons(IP_DF);
-       ip->ip_tos = IPTOS_LOWDELAY;
-       ip->ip_ttl = IPDEFTTL;
-       ip->ip_len = htons(sizeof(struct udpiphdr) + len);
-
-#if NBPFILTER > 0
-       if (ifp->if_bpf)
-               bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
-#endif
-
        sc->sc_if.if_opackets++;
        sc->sc_if.if_obytes += m->m_pkthdr.len;
 
-       if ((err = ip_output(m, NULL, NULL, IP_RAWOUTPUT, &sc->sc_imo, NULL,
-           0))) {
-               pflowstats.pflow_oerrors++;
-               sc->sc_if.if_oerrors++;
-       }
-       return (err);
-}
-
-int
-pflow_get_dynport(void)
-{
-       u_int16_t       tmp, low, high, cut;
-
-       low = ipport_hifirstauto;     /* sysctl */
-       high = ipport_hilastauto;
-
-       cut = arc4random_uniform(1 + high - low) + low;
-
-       for (tmp = cut; tmp <= high; ++(tmp)) {
-               if (!in_baddynamic(tmp, IPPROTO_UDP))
-                       return (htons(tmp));
-       }
-
-       for (tmp = cut - 1; tmp >= low; --(tmp)) {
-               if (!in_baddynamic(tmp, IPPROTO_UDP))
-                       return (htons(tmp));
-       }
-
-       return (htons(ipport_hilastauto)); /* XXX */
+       if (sc->so != NULL)
+               return (sosend(sc->so, sc->send_nam, NULL, m, NULL, 0));
+       return (EINVAL);
 }
 
 int
diff --git if_pflow.h if_pflow.h
index 7e35ddd..0929cdb 100644
--- if_pflow.h
+++ if_pflow.h
@@ -181,12 +181,12 @@ struct pflow_softc {
        unsigned int             sc_maxcount6;
        u_int64_t                sc_gcounter;
        u_int32_t                sc_sequence;
-       struct ip_moptions       sc_imo;
        struct timeout           sc_tmo;
        struct timeout           sc_tmo6;
        struct timeout           sc_tmo_tmpl;
+       struct socket           *so;
+       struct mbuf             *send_nam;
        struct in_addr           sc_sender_ip;
-       u_int16_t                sc_sender_port;
        struct in_addr           sc_receiver_ip;
        u_int16_t                sc_receiver_port;
        u_char                   sc_send_templates;


-- 
I'm not entirely sure you are real.

Reply via email to