On Sun, Sep 13, 2015 at 03:25:16PM +0000, Florian Obser wrote:
> I don't really like to store struct sockaddr_storage since it's so
> big. I played around with a union like pf does, but looked
> complicated.
> Thoughts?
> 
> Also with this you can specify a source port.
> Since I was touching all those lines anyway I renamed sender to
> flowsrc and receiver to flowdst like the ifconfig keywords. I found
> the names of these struct members always confusing.
> Test, comments, OKs?
> 

second version, now uses a pointer to struct sockaddr + malloc of the
correct size.

diff --git sbin/ifconfig/ifconfig.8 sbin/ifconfig/ifconfig.8
index 85244d3..b3851aa 100644
--- sbin/ifconfig/ifconfig.8
+++ sbin/ifconfig/ifconfig.8
@@ -1277,7 +1277,7 @@ network.
 .Nm ifconfig
 .Ar pflow-interface
 .Op Oo Fl Oc Ns Cm flowdst Ar addr : Ns Ar port
-.Op Oo Fl Oc Ns Cm flowsrc Ar addr
+.Op Oo Fl Oc Ns Cm flowsrc Ar addr Oo : Ns Ar port Oc
 .Op Cm pflowproto Ar n
 .Ek
 .nr nS 0
@@ -1298,7 +1298,7 @@ is the port number of the flow collector.
 Pflow data will be sent to this address/port.
 .It Fl flowdst
 Unset the receiver address and stop sending pflow data.
-.It Cm flowsrc Ar addr
+.It Cm flowsrc Ar addr Oo : Ns Ar port Oc
 Set the source IP address for pflow packets.
 .Ar addr
 is the IP address used as sender of the UDP packets and may be used to
diff --git sbin/ifconfig/ifconfig.c sbin/ifconfig/ifconfig.c
index 63f6956..bee5dc2 100644
--- sbin/ifconfig/ifconfig.c
+++ sbin/ifconfig/ifconfig.c
@@ -265,6 +265,7 @@ void        setifpowersave(const char *, int);
 void   setifmetric(const char *, int);
 void   notrailers(const char *, int);
 void   pflow_status(void);
+void   pflow_addr(const char*, struct sockaddr_storage *);
 void   setpflow_sender(const char *, int);
 void   unsetpflow_sender(const char *, int);
 void   setpflow_receiver(const char *, int);
@@ -4280,7 +4281,11 @@ pfsync_status(void)
 void
 pflow_status(void)
 {
-       struct pflowreq preq;
+       struct pflowreq          preq;
+       struct sockaddr_in      *sin;
+       struct sockaddr_in6     *sin6;
+       int                      error;
+       char                     buf[INET6_ADDRSTRLEN];
 
        bzero(&preq, sizeof(struct pflowreq));
        ifr.ifr_data = (caddr_t)&preq;
@@ -4288,47 +4293,135 @@ pflow_status(void)
        if (ioctl(s, SIOCGETPFLOW, (caddr_t)&ifr) == -1)
                 return;
 
+       if (preq.flowsrc.ss_family == AF_INET || preq.flowsrc.ss_family ==
+           AF_INET6) {
+               error = getnameinfo((struct sockaddr*)&preq.flowsrc,
+                   preq.flowsrc.ss_len, buf, sizeof(buf), NULL, 0,
+                   NI_NUMERICHOST);
+               if (error)
+                       err(1, "sender: %s", gai_strerror(error));
+       }
+
        printf("\tpflow: ");
-       if (preq.sender_ip.s_addr != INADDR_ANY)
-               printf("sender: %s ", inet_ntoa(preq.sender_ip));
-       printf("receiver: %s:", preq.receiver_ip.s_addr != INADDR_ANY ?
-           inet_ntoa(preq.receiver_ip) : "INVALID");
-       if (preq.receiver_port == 0)
-               printf("%s ", "INVALID");
-       else
-               printf("%u ", ntohs(preq.receiver_port));
+       switch (preq.flowsrc.ss_family) {
+       case AF_INET:
+               sin = (struct sockaddr_in*) &preq.flowsrc;
+               if (sin->sin_addr.s_addr != INADDR_ANY) {
+                       printf("sender: %s", buf);
+                       if (sin->sin_port != 0)
+                               printf(":%u", ntohs(sin->sin_port));
+                       printf(" ");
+               }
+               break;
+       case AF_INET6:
+               sin6 = (struct sockaddr_in6*) &preq.flowsrc;
+               if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+                       printf("sender: [%s]", buf);
+                       if (sin6->sin6_port != 0)
+                               printf(":%u", ntohs(sin6->sin6_port));
+                       printf(" ");
+               }
+       default:
+               break;
+       }
+       if (preq.flowdst.ss_family == AF_INET || preq.flowdst.ss_family ==
+           AF_INET6) {
+               error = getnameinfo((struct sockaddr*)&preq.flowdst,
+                   preq.flowdst.ss_len, buf, sizeof(buf), NULL, 0,
+                   NI_NUMERICHOST);
+               if (error)
+                       err(1, "receiver: %s", gai_strerror(error));
+       }
+       switch (preq.flowdst.ss_family) {
+       case AF_INET:
+               sin = (struct sockaddr_in*)&preq.flowdst;
+               printf("receiver: %s:", sin->sin_addr.s_addr != INADDR_ANY ?
+                   buf : "INVALID");   
+               if (sin->sin_port == 0)
+                       printf("%s ", "INVALID");
+               else
+                       printf("%u ", ntohs(sin->sin_port));
+               break;
+       case AF_INET6:
+               sin6 = (struct sockaddr_in6*) &preq.flowdst;
+               printf("receiver: [%s]:",
+                   !IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) ? buf :
+                   "INVALID"); 
+               if (sin6->sin6_port == 0)
+                       printf("%s ", "INVALID");
+               else
+                       printf("%u ", ntohs(sin6->sin6_port));
+               break;
+       default:
+               printf("receiver: INVALID:INVALID ");
+               break;
+       }
        printf("version: %d\n", preq.version);
 }
 
-/* ARGSUSED */
 void
-setpflow_sender(const char *val, int d)
-{
-       struct pflowreq preq;
-       struct addrinfo hints, *sender;
-       int ecode;
+pflow_addr(const char *val, struct sockaddr_storage *ss) {
+       struct addrinfo hints, *res0;
+       int error, flag;
+       char *cp, *ip, *port, buf[HOST_NAME_MAX+1 + sizeof (":65535")];
+
+       if (strlcpy(buf, val, sizeof(buf)) >= sizeof(buf))
+               errx(1, "%s bad value", val);
+
+       port = NULL;
+       cp = buf;
+       if (*cp == '[')
+               flag = 1;
+       else
+               flag = 0;
+
+       for(; *cp; ++cp) {
+               if (*cp == ']' && *(cp + 1) == ':' && flag) {
+                       *cp = '\0';
+                       *(cp + 1) = '\0';
+                       port = cp + 2;
+                       break;
+               }
+               if (*cp == ']' && *(cp + 1) == '\0' && flag) {
+                       *cp = '\0';
+                       port = NULL;
+                       break;
+               }
+               if (*cp == ':' && !flag) {
+                       *cp = '\0';
+                       port = cp + 1;
+                       break;
+               }
+       }
+
+       ip = buf;
+       if (flag)
+               ip++;
 
        bzero(&hints, sizeof(hints));
-       hints.ai_family = AF_INET;
+       hints.ai_family = AF_UNSPEC;
        hints.ai_socktype = SOCK_DGRAM; /*dummy*/
 
-       if ((ecode = getaddrinfo(val, NULL, &hints, &sender)) != 0)
+       if ((error = getaddrinfo(ip, port, &hints, &res0)) != 0)
                errx(1, "error in parsing address string: %s",
-                   gai_strerror(ecode));
+                   gai_strerror(error));
 
-       if (sender->ai_addr->sa_family != AF_INET)
-               errx(1, "only IPv4 addresses supported for the sender");
+       memcpy(ss, res0->ai_addr, res0->ai_addr->sa_len);
+       freeaddrinfo(res0);
+}
+
+void
+setpflow_sender(const char *val, int d)
+{
+       struct pflowreq preq;
 
        bzero(&preq, sizeof(struct pflowreq));
        ifr.ifr_data = (caddr_t)&preq;
        preq.addrmask |= PFLOW_MASK_SRCIP;
-       preq.sender_ip.s_addr = ((struct sockaddr_in *)
-           sender->ai_addr)->sin_addr.s_addr;
+       pflow_addr(val, &preq.flowsrc);
 
        if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
                err(1, "SIOCSETPFLOW");
-
-       freeaddrinfo(sender);
 }
 
 void
@@ -4343,47 +4436,18 @@ unsetpflow_sender(const char *val, int d)
                err(1, "SIOCSETPFLOW");
 }
 
-/* ARGSUSED */
 void
 setpflow_receiver(const char *val, int d)
 {
        struct pflowreq preq;
-       struct addrinfo hints, *receiver;
-       int ecode;
-       char *ip, *port, buf[HOST_NAME_MAX+1 + sizeof (":65535")];
-
-       if (strchr (val, ':') == NULL)
-               errx(1, "%s bad value", val);
-
-       if (strlcpy(buf, val, sizeof(buf)) >= sizeof(buf))
-               errx(1, "%s bad value", val);
-       port = strchr(buf, ':');
-       *port++ = '\0';
-       ip = buf;
-
-       bzero(&hints, sizeof(hints));
-       hints.ai_family = AF_INET;
-       hints.ai_socktype = SOCK_DGRAM; /*dummy*/
-
-       if ((ecode = getaddrinfo(ip, port, &hints, &receiver)) != 0)
-               errx(1, "error in parsing address string: %s",
-                   gai_strerror(ecode));
-
-       if (receiver->ai_addr->sa_family != AF_INET)
-               errx(1, "only IPv4 addresses supported for the receiver");
 
        bzero(&preq, sizeof(struct pflowreq));
        ifr.ifr_data = (caddr_t)&preq;
-       preq.addrmask |= PFLOW_MASK_DSTIP | PFLOW_MASK_DSTPRT;
-       preq.receiver_ip.s_addr = ((struct sockaddr_in *)
-           receiver->ai_addr)->sin_addr.s_addr;
-       preq.receiver_port = (u_int16_t) ((struct sockaddr_in *)
-           receiver->ai_addr)->sin_port;
+       preq.addrmask |= PFLOW_MASK_DSTIP;
+       pflow_addr(val, &preq.flowdst);
 
        if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
                err(1, "SIOCSETPFLOW");
-
-       freeaddrinfo(receiver);
 }
 
 void
@@ -4393,7 +4457,7 @@ unsetpflow_receiver(const char *val, int d)
 
        bzero(&preq, sizeof(struct pflowreq));
        ifr.ifr_data = (caddr_t)&preq;
-       preq.addrmask |= PFLOW_MASK_DSTIP | PFLOW_MASK_DSTPRT;
+       preq.addrmask |= PFLOW_MASK_DSTIP;
        if (ioctl(s, SIOCSETPFLOW, (caddr_t)&ifr) == -1)
                err(1, "SIOCSETPFLOW");
 }
diff --git sys/net/if_pflow.c sys/net/if_pflow.c
index bf2a246..5bb9f76 100644
--- sys/net/if_pflow.c
+++ sys/net/if_pflow.c
@@ -70,6 +70,7 @@ int   pflow_clone_destroy(struct ifnet *);
 void   pflow_init_timeouts(struct pflow_softc *);
 int    pflow_calc_mtu(struct pflow_softc *, int, int);
 void   pflow_setmtu(struct pflow_softc *, int);
+int    pflowvalidsockaddr(const struct sockaddr *, int);
 int    pflowioctl(struct ifnet *, u_long, caddr_t);
 
 struct mbuf    *pflow_get_mbuf(struct pflow_softc *, u_int16_t);
@@ -117,21 +118,13 @@ pflow_clone_create(struct if_clone *ifc, int unit)
 {
        struct ifnet            *ifp;
        struct pflow_softc      *pflowif;
-       struct sockaddr_in      *sin;
 
        if ((pflowif = malloc(sizeof(*pflowif),
            M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
                return (ENOMEM);
 
        MGET(pflowif->send_nam, M_WAIT, MT_SONAME);
-       sin = mtod(pflowif->send_nam, struct sockaddr_in *);
-       memset(sin, 0 , sizeof(*sin));
-       sin->sin_len = pflowif->send_nam->m_len = sizeof (struct sockaddr_in);
-       sin->sin_family = AF_INET;
-
-       pflowif->sc_receiver_ip.s_addr = INADDR_ANY;
-       pflowif->sc_receiver_port = 0;
-       pflowif->sc_sender_ip.s_addr = INADDR_ANY;
+
        pflowif->sc_version = PFLOW_PROTO_DEFAULT;
 
        /* ipfix template init */
@@ -267,6 +260,10 @@ pflow_clone_destroy(struct ifnet *ifp)
                error = soclose(sc->so);
                sc->so = NULL;
        }
+       if (sc->sc_flowdst != NULL)
+               free(sc->sc_flowdst, M_DEVBUF, sc->sc_flowdst->sa_len);
+       if (sc->sc_flowsrc != NULL)
+               free(sc->sc_flowsrc, M_DEVBUF, sc->sc_flowsrc->sa_len);
        if_detach(ifp);
        SLIST_REMOVE(&pflowif_list, sc, pflow_softc, sc_next);
        free(sc, M_DEVBUF, sizeof(*sc));
@@ -275,6 +272,27 @@ pflow_clone_destroy(struct ifnet *ifp)
 }
 
 int
+pflowvalidsockaddr(const struct sockaddr *sa, int ignore_port)
+{
+       struct sockaddr_in6     *sin6;
+       struct sockaddr_in      *sin;
+
+       if (sa == NULL)
+               return (0);
+       switch(sa->sa_family) {
+       case AF_INET:
+               sin = (struct sockaddr_in*) sa;
+               return (sin->sin_addr.s_addr != INADDR_ANY &&
+                   (ignore_port || sin->sin_port != 0));
+       case AF_INET6:
+               sin6 = (struct sockaddr_in6*) sa;
+               return (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr) &&
+                   (ignore_port || sin6->sin6_port != 0));
+       default:
+               return (0);
+       }
+}
+int
 pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
 {
        struct proc             *p = curproc;
@@ -282,7 +300,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        struct ifreq            *ifr = (struct ifreq *)data;
        struct pflowreq          pflowr;
        struct socket           *so;
-       struct sockaddr_in      *sin;
+       struct sockaddr         *sa;
        struct mbuf             *m;
        int                      s, error;
 
@@ -318,9 +336,12 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
        case SIOCGETPFLOW:
                bzero(&pflowr, sizeof(pflowr));
 
-               pflowr.sender_ip = sc->sc_sender_ip;
-               pflowr.receiver_ip = sc->sc_receiver_ip;
-               pflowr.receiver_port = sc->sc_receiver_port;
+               if (sc->sc_flowsrc != NULL)
+                       memcpy(&pflowr.flowsrc, sc->sc_flowsrc,
+                           sc->sc_flowsrc->sa_len);
+               if (sc->sc_flowdst != NULL)
+                       memcpy(&pflowr.flowdst, sc->sc_flowdst,
+                           sc->sc_flowdst->sa_len);
                pflowr.version = sc->sc_version;
 
                if ((error = copyout(&pflowr, ifr->ifr_data,
@@ -348,17 +369,99 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                pflow_flush(sc);
 
                if (pflowr.addrmask & PFLOW_MASK_DSTIP) {
-                       sc->sc_receiver_ip.s_addr = pflowr.receiver_ip.s_addr;
-                       sin = mtod(sc->send_nam, struct sockaddr_in *);
-                       sin->sin_addr.s_addr = sc->sc_receiver_ip.s_addr;
-               }
-               if (pflowr.addrmask & PFLOW_MASK_DSTPRT) {
-                       sc->sc_receiver_port = pflowr.receiver_port;
-                       sin = mtod(sc->send_nam, struct sockaddr_in *);
-                       sin->sin_port = pflowr.receiver_port;
+                       if (sc->sc_flowdst != NULL &&
+                           sc->sc_flowdst->sa_family !=
+                           pflowr.flowdst.ss_family) {
+                               free(sc->sc_flowdst, M_DEVBUF,
+                                   sc->sc_flowdst->sa_len);
+                               sc->sc_flowdst = NULL;
+                               if (sc->so != NULL) {
+                                       soclose(so);
+                                       sc->so = NULL;
+                               }
+                       }
+
+                       if (sc->sc_flowdst == NULL) {
+                               switch(pflowr.flowdst.ss_family) {
+                               case AF_INET:
+                                       if ((sc->sc_flowdst = malloc(
+                                           sizeof(struct sockaddr_in),
+                                           M_DEVBUF,  M_NOWAIT)) == NULL) {
+                                               splx(s);
+                                               return (ENOMEM);
+                                       }
+                                       memcpy(sc->sc_flowdst, &pflowr.flowdst,
+                                           sizeof(struct sockaddr_in));
+                                       sc->sc_flowdst->sa_len = sizeof(struct
+                                           sockaddr_in);
+                                       break;
+                               case AF_INET6:
+                                       if ((sc->sc_flowdst = malloc(
+                                           sizeof(struct sockaddr_in6),
+                                           M_DEVBUF, M_NOWAIT)) == NULL) {
+                                               splx(s);
+                                               return (ENOMEM);
+                                       }
+                                       memcpy(sc->sc_flowdst, &pflowr.flowdst,
+                                           sizeof(struct sockaddr_in6));
+                                       sc->sc_flowdst->sa_len = sizeof(struct
+                                           sockaddr_in6);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
+                       if (sc->sc_flowdst != NULL) {
+                               sc->send_nam->m_len = sc->sc_flowdst->sa_len;
+                               sa = mtod(sc->send_nam, struct sockaddr *);
+                               memcpy(sa, sc->sc_flowdst,
+                                   sc->sc_flowdst->sa_len);
+                       }
                }
+
                if (pflowr.addrmask & PFLOW_MASK_SRCIP) {
-                       sc->sc_sender_ip.s_addr = pflowr.sender_ip.s_addr;
+                       if (sc->sc_flowsrc != NULL &&
+                           sc->sc_flowsrc->sa_family !=
+                           pflowr.flowsrc.ss_family) {
+                               free(sc->sc_flowsrc, M_DEVBUF,
+                                   sc->sc_flowsrc->sa_len);
+                               sc->sc_flowsrc = NULL;
+                               if (sc->so != NULL) {
+                                       soclose(so);
+                                       sc->so = NULL;
+                               }
+                       }
+
+                       if (sc->sc_flowsrc == NULL) {
+                               switch(pflowr.flowsrc.ss_family) {
+                               case AF_INET:
+                                       if ((sc->sc_flowsrc = malloc(
+                                           sizeof(struct sockaddr_in),
+                                           M_DEVBUF, M_NOWAIT)) == NULL) {
+                                               splx(s);
+                                               return (ENOMEM);
+                                       }
+                                       memcpy(sc->sc_flowsrc, &pflowr.flowsrc,
+                                           sizeof(struct sockaddr_in));
+                                       sc->sc_flowsrc->sa_len = sizeof(struct
+                                           sockaddr_in);
+                                       break;
+                               case AF_INET6:
+                                       if ((sc->sc_flowsrc = malloc(
+                                           sizeof(struct sockaddr_in6),
+                                           M_DEVBUF, M_NOWAIT)) == NULL) {
+                                               splx(s);
+                                               return (ENOMEM);
+                                       }
+                                       memcpy(sc->sc_flowsrc, &pflowr.flowsrc,
+                                           sizeof(struct sockaddr_in6));
+                                       sc->sc_flowsrc->sa_len = sizeof(struct
+                                           sockaddr_in6);
+                                       break;
+                               default:
+                                       break;
+                               }
+                       }
                        if (sc->so != NULL) {
                                soclose(sc->so);
                                sc->so = NULL;
@@ -366,23 +469,19 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                }
 
                if (sc->so == NULL) {
-                       if (sc->sc_receiver_ip.s_addr != INADDR_ANY &&
-                           sc->sc_receiver_port != 0) {
-                               error = socreate(AF_INET, &so, SOCK_DGRAM, 0);
+                       if (pflowvalidsockaddr(sc->sc_flowdst, 0)) {
+                               error = socreate(sc->sc_flowdst->sa_family,
+                                   &so, SOCK_DGRAM, 0);
                                if (error) {
                                        splx(s);
                                        return (error);
                                }
-                               if (sc->sc_sender_ip.s_addr != INADDR_ANY) {
+                               if (pflowvalidsockaddr(sc->sc_flowsrc, 1)) {
                                        MGET(m, M_WAIT, MT_SONAME);
-                                       sin = mtod(m, struct sockaddr_in *);
-                                       memset(sin, 0 , sizeof(*sin));
-                                       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;
+                                       m->m_len = sc->sc_flowsrc->sa_len;
+                                       sa = mtod(m, struct sockaddr *);
+                                       memcpy(sa, sc->sc_flowsrc,
+                                           sc->sc_flowsrc->sa_len);
 
                                        error = sobind(so, m, p);
                                        m_freem(m);
@@ -395,8 +494,7 @@ pflowioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
                                sc->so = so;
                        }
                } else {
-                       if (sc->sc_receiver_ip.s_addr == INADDR_ANY ||
-                           sc->sc_receiver_port == 0) {
+                       if (!pflowvalidsockaddr(sc->sc_flowdst, 0)) {
                                soclose(sc->so);
                                sc->so = NULL;
                        }
diff --git sys/net/if_pflow.h sys/net/if_pflow.h
index 18b9f21..ff81906 100644
--- sys/net/if_pflow.h
+++ sys/net/if_pflow.h
@@ -186,9 +186,8 @@ struct pflow_softc {
        struct timeout           sc_tmo_tmpl;
        struct socket           *so;
        struct mbuf             *send_nam;
-       struct in_addr           sc_sender_ip;
-       struct in_addr           sc_receiver_ip;
-       u_int16_t                sc_receiver_port;
+       struct sockaddr         *sc_flowsrc;
+       struct sockaddr         *sc_flowdst;
        u_char                   sc_send_templates;
        struct pflow_ipfix_tmpl  sc_tmpl_ipfix;
        u_int8_t                 sc_version;
@@ -254,15 +253,13 @@ struct pflow_protos {
  * Configuration structure for SIOCSETPFLOW SIOCGETPFLOW
  */
 struct pflowreq {
-       struct in_addr          sender_ip;
-       struct in_addr          receiver_ip;
-       u_int16_t               receiver_port;
+       struct sockaddr_storage flowsrc;
+       struct sockaddr_storage flowdst;
        u_int16_t               addrmask;
        u_int8_t                version;
 #define PFLOW_MASK_SRCIP       0x01
 #define PFLOW_MASK_DSTIP       0x02
-#define PFLOW_MASK_DSTPRT      0x04
-#define PFLOW_MASK_VERSION     0x08
+#define PFLOW_MASK_VERSION     0x04
 };
 
 #ifdef _KERNEL


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

Reply via email to