From 7f6cf3680e3fd539402c7576440cf7b1760ee088 Mon Sep 17 00:00:00 2001 From: Gleb Smirnoff Date: Sun, 14 Sep 2014 13:41:49 +0400 Subject: [PATCH] Use BSD libc API to fetch data about interface statistics instead of nosing in kernel memory. This API should work on all versions of FreeBSD/NetBSD/OpenBSD/Dragonfly. This fixes compilation on FreeBSD 11, where kernel structures have changed and protects against future breakages. It also make the file much simplier. Tested by: Daniel Engberg --- miniupnpd/bsd/getifstats.c | 139 +++++++++++-------------------------- 1 file changed, 39 insertions(+), 100 deletions(-) diff --git a/miniupnpd/bsd/getifstats.c b/miniupnpd/bsd/getifstats.c index 7238a46..7397d58 100644 --- a/miniupnpd/bsd/getifstats.c +++ b/miniupnpd/bsd/getifstats.c @@ -1,61 +1,30 @@ /* MiniUPnP project * http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/ - * author: Ryan Wagoner and Thomas Bernard + * author: Gleb Smirnoff * (c) 2006 Ryan Wagoner + * (c) 2014 Gleb Smirnoff * This software is subject to the conditions detailed * in the LICENCE file provided within the distribution */ -#include -#include -#include #include -#include -#include -#if defined(__FreeBSD__) || defined(__DragonFly__) -#ifdef __DragonFly__ -#define _KERNEL_STRUCTURES -#endif -#include -#endif -#if defined(__DragonFly__) -#include -#else -#include -#endif -#include -#include -#include -#include -#include +#include +#include #include -#include +#include + +#ifdef ENABLE_GETIFSTATS_CACHING +#include +#endif #include "../getifstats.h" #include "../config.h" -static struct nlist list[] = { - {"_ifnet", 0, 0, 0, 0}, - {NULL,0, 0, 0, 0} -}; - int -getifstats(const char * ifname, struct ifdata * data) +getifstats(const char *ifname, struct ifdata *data) { -#if defined(__FreeBSD__) || defined(__DragonFly__) - struct ifnethead ifh; -#elif defined(__OpenBSD__) || defined(__NetBSD__) - struct ifnet_head ifh; -#else - #error "Dont know if I should use struct ifnethead or struct ifnet_head" -#endif - struct ifnet ifc; - struct ifnet *ifp; - kvm_t *kd; - ssize_t n; - char errstr[_POSIX2_LINE_MAX]; + static struct ifaddrs *ifap, *ifa; #ifdef ENABLE_GETIFSTATS_CACHING - static time_t cache_timestamp = 0; - static struct ifdata cache_data; + static time_t cache_timestamp; time_t current_time; #endif if(!data) @@ -67,70 +36,40 @@ getifstats(const char * ifname, struct ifdata * data) data->ibytes = 0; if(!ifname || ifname[0]=='\0') return -1; + #ifdef ENABLE_GETIFSTATS_CACHING current_time = time(NULL); - if(current_time == ((time_t)-1)) { - syslog(LOG_ERR, "getifstats() : time() error : %m"); - } else { - if(current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) { - memcpy(data, &cache_data, sizeof(struct ifdata)); - return 0; - } - } + if (ifap != NULL && + current_time < cache_timestamp + GETIFSTATS_CACHING_DURATION) + goto copy; #endif - /*kd = kvm_open(NULL, NULL, NULL, O_RDONLY, NULL);*/ - kd = kvm_openfiles(NULL, NULL, NULL, O_RDONLY, errstr); - if(!kd) - { - syslog (LOG_ERR, "getifstats() : kvm_open(): %s", errstr); - return -1; + if (ifap != NULL) { + freeifaddrs(ifap); + ifap = NULL; } - if(kvm_nlist(kd, list) < 0) - { - syslog(LOG_ERR, "getifstats() : kvm_nlist(): FAILED"); - goto error; - } - if(!list[0].n_value) - { - syslog(LOG_ERR, "getifstats() : n_value(): FAILED"); - goto error; - } - n = kvm_read(kd, list[0].n_value, &ifh, sizeof(ifh)); - if(n<0) - { - syslog(LOG_ERR, "getifstats() : kvm_read(head): %s", kvm_geterr(kd)); - goto error; - } - for(ifp = TAILQ_FIRST(&ifh); ifp; ifp = TAILQ_NEXT(&ifc, if_list)) - { - n = kvm_read(kd, (u_long)ifp, &ifc, sizeof(ifc)); - if(n<0) - { - syslog(LOG_ERR, "getifstats() : kvm_read(element): %s", kvm_geterr(kd)); - goto error; - } - if(strcmp(ifname, ifc.if_xname) == 0) - { - /* found the right interface */ - data->opackets = ifc.if_data.ifi_opackets; - data->ipackets = ifc.if_data.ifi_ipackets; - data->obytes = ifc.if_data.ifi_obytes; - data->ibytes = ifc.if_data.ifi_ibytes; - data->baudrate = ifc.if_data.ifi_baudrate; - kvm_close(kd); + if (getifaddrs(&ifap) != 0) { + syslog (LOG_ERR, "getifstats() : getifaddrs(): %s", + strerror(errno)); + return (-1); + } + + for (ifa = ifap; ifa; ifa = ifa->ifa_next) + if (ifa->ifa_addr->sa_family == AF_LINK && + strcmp(ifa->ifa_name, ifname) == 0) { #ifdef ENABLE_GETIFSTATS_CACHING - if(current_time!=((time_t)-1)) { - cache_timestamp = current_time; - memcpy(&cache_data, data, sizeof(struct ifdata)); - } + cache_timestamp = current_time; +copy: #endif - return 0; /* ok */ +#define IFA_STAT(s) (((struct if_data *)ifa->ifa_data)->ifi_ ## s) + data->opackets = IFA_STAT(opackets); + data->ipackets = IFA_STAT(ipackets); + data->obytes = IFA_STAT(obytes); + data->ibytes = IFA_STAT(ibytes); + data->baudrate = IFA_STAT(baudrate); + return (0); } - } -error: - kvm_close(kd); - return -1; /* not found or error */ -} + return (-1); +}