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.