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?
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..42766d1 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_storage *, 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 */
@@ -275,6 +268,24 @@ pflow_clone_destroy(struct ifnet *ifp)
}
int
+pflowvalidsockaddr(const struct sockaddr_storage *ss, int ignore_port)
+{
+ struct sockaddr_in6 *sin6;
+ struct sockaddr_in *sin;
+ switch(ss->ss_family) {
+ case AF_INET:
+ sin = (struct sockaddr_in*) ss;
+ return (sin->sin_addr.s_addr != INADDR_ANY &&
+ (ignore_port || sin->sin_port != 0));
+ case AF_INET6:
+ sin6 = (struct sockaddr_in6*) ss;
+ 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;
@@ -318,9 +329,8 @@ 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;
+ pflowr.flowsrc = sc->sc_flowsrc;
+ pflowr.flowdst = sc->sc_flowdst;
pflowr.version = sc->sc_version;
if ((error = copyout(&pflowr, ifr->ifr_data,
@@ -348,17 +358,45 @@ 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;
+ sc->sc_flowdst = pflowr.flowdst;
+ switch(sc->sc_flowdst.ss_family) {
+ case AF_INET:
+ sc->sc_flowdst.ss_len = sizeof(struct
+ sockaddr_in);
+ break;
+ case AF_INET6:
+ sc->sc_flowdst.ss_len = sizeof(struct
+ sockaddr_in6);
+ break;
+ default:
+ sc->sc_flowdst.ss_len = 0;
+ sc->sc_flowdst.ss_family = 0;
+ break;
+ }
+
+ sc->send_nam->m_len = sc->sc_flowdst.ss_len;
+ /* XXX */
sin = mtod(sc->send_nam, struct sockaddr_in *);
- sin->sin_port = pflowr.receiver_port;
+ memcpy(sin, &sc->sc_flowdst, sc->sc_flowdst.ss_len);
}
+
if (pflowr.addrmask & PFLOW_MASK_SRCIP) {
- sc->sc_sender_ip.s_addr = pflowr.sender_ip.s_addr;
+ sc->sc_flowsrc = pflowr.flowsrc;
+ switch(sc->sc_flowsrc.ss_family) {
+ case AF_INET:
+ sc->sc_flowsrc.ss_len = sizeof(struct
+ sockaddr_in);
+ break;
+ case AF_INET6:
+ sc->sc_flowsrc.ss_len = sizeof(struct
+ sockaddr_in6);
+ break;
+ default:
+ sc->sc_flowsrc.ss_len = 0;
+ sc->sc_flowsrc.ss_family = 0;
+ break;
+
+ }
if (sc->so != NULL) {
soclose(sc->so);
sc->so = NULL;
@@ -366,23 +404,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.ss_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);
+ m->m_len = sc->sc_flowsrc.ss_len;
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;
+ memcpy(sin, &sc->sc_flowsrc,
+ sc->sc_flowsrc.ss_len);
error = sobind(so, m, p);
m_freem(m);
@@ -395,8 +429,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..e9772a6 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_storage sc_flowsrc;
+ struct sockaddr_storage 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.