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 <daniel.engberg.lists pyret.net>
This commit is contained in:
parent
0436d03757
commit
7f6cf3680e
|
@ -1,61 +1,30 @@
|
|||
/* MiniUPnP project
|
||||
* http://miniupnp.free.fr/ or http://miniupnp.tuxfamily.org/
|
||||
* author: Ryan Wagoner and Thomas Bernard
|
||||
* author: Gleb Smirnoff <glebius@FreeBSD.org>
|
||||
* (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 <syslog.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <net/if.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__)
|
||||
#ifdef __DragonFly__
|
||||
#define _KERNEL_STRUCTURES
|
||||
#endif
|
||||
#include <net/if_var.h>
|
||||
#endif
|
||||
#if defined(__DragonFly__)
|
||||
#include <net/pf/pfvar.h>
|
||||
#else
|
||||
#include <net/pfvar.h>
|
||||
#endif
|
||||
#include <kvm.h>
|
||||
#include <fcntl.h>
|
||||
#include <nlist.h>
|
||||
#include <sys/queue.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <ifaddrs.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include <syslog.h>
|
||||
|
||||
#ifdef ENABLE_GETIFSTATS_CACHING
|
||||
#include <time.h>
|
||||
#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)
|
||||
{
|
||||
#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));
|
||||
}
|
||||
copy:
|
||||
#endif
|
||||
return 0; /* ok */
|
||||
}
|
||||
}
|
||||
error:
|
||||
kvm_close(kd);
|
||||
return -1; /* not found or error */
|
||||
#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);
|
||||
}
|
||||
|
||||
return (-1);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue