vnstat  2.9
About: vnStat is a console-based network traffic monitor (using the /proc filesystem).
  Fossies Dox: vnstat-2.9.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

ifinfo.c
Go to the documentation of this file.
1#include "common.h"
2#include "ibw.h"
3#include "ifinfo.h"
4
5int getifinfo(const char *iface)
6{
7 char inface[32];
8
9 ifinfo.filled = 0;
10 ifinfo.timestamp = 0;
11
12#if defined(__linux__) && HAVE_LINUX_RTNETLINK_H
13 if (cfg.is64bit == -2) {
14#if HAVE_DECL_IFLA_STATS64
15 ifinfo.is64bit = 1;
16#else
17 ifinfo.is64bit = 0;
18#endif
19 } else {
20 ifinfo.is64bit = (short)cfg.is64bit;
21 }
22#else
23 if (cfg.is64bit < 0) {
24 ifinfo.is64bit = -1;
25 } else {
26 ifinfo.is64bit = (short)cfg.is64bit;
27 }
28#endif
29
30 if (strcmp(iface, "default") == 0) {
31 strncpy_nt(inface, cfg.iface, 32);
32 } else {
33 strncpy_nt(inface, iface, 32);
34 }
35
36#if defined(__linux__) || defined(CHECK_VNSTAT)
37 /* try getting interface info from /proc */
38 if (readproc(inface) == 1) {
39 ifinfo.timestamp = time(NULL);
40 return 1;
41 } else {
42 if (debug)
43 printf("Failed to use %s as source.\n", PROCNETDEV);
44 }
45
46 /* try getting interface info from /sys */
47 if (readsysclassnet(inface) == 1) {
48 ifinfo.timestamp = time(NULL);
49 return 1;
50 }
51
52#elif defined(BSD_VNSTAT)
53 if (readifaddrs(inface) == 1) {
54 ifinfo.timestamp = time(NULL);
55 return 1;
56 }
57#endif
58
59 snprintf(errorstring, 1024, "Unable to get interface \"%s\" statistics.", inface);
61 return 0;
62}
63
64int getifliststring(char **ifacelist, int showspeed)
65{
66 char temp[64];
67 iflist *ifl = NULL, *ifl_iterator = NULL;
68
69 /* initialize list string */
70 *ifacelist = (char *)malloc(sizeof(char));
71 if (*ifacelist == NULL) {
72 panicexit(__FILE__, __LINE__);
73 }
74 *ifacelist[0] = '\0';
75
76 if (getiflist(&ifl, showspeed, 1) > 0) {
77
78 ifl_iterator = ifl;
79
80 while (ifl_iterator != NULL) {
81 *ifacelist = (char *)realloc(*ifacelist, ((strlen(*ifacelist) + strlen(ifl_iterator->interface) + 2) * sizeof(char)));
82 if (*ifacelist == NULL) {
83 panicexit(__FILE__, __LINE__);
84 }
85 strcat(*ifacelist, ifl_iterator->interface);
86 strcat(*ifacelist, " ");
87
88 if (showspeed && ifl_iterator->bandwidth > 0) {
89 snprintf(temp, 64, "(%u Mbit) ", ifl_iterator->bandwidth);
90 *ifacelist = (char *)realloc(*ifacelist, ((strlen(*ifacelist) + strlen(temp) + 1) * sizeof(char)));
91 if (*ifacelist == NULL) {
92 panicexit(__FILE__, __LINE__);
93 }
94 strcat(*ifacelist, temp);
95 }
96
97 ifl_iterator = ifl_iterator->next;
98 }
99
100 iflistfree(&ifl);
101 return 1;
102 }
103
104 iflistfree(&ifl);
105 return 0;
106}
107
108int getiflist(iflist **ifl, const int getspeed, const int validate)
109{
110 int result = 0;
111 int32_t maxbw = cfg.maxbw;
112
113 /* disable MaxBandwidth during list creation to avoid having it being set as the default value when nothing is detected */
114 cfg.maxbw = 0;
115#if defined(__linux__) || defined(CHECK_VNSTAT)
116 result = getiflist_linux(ifl, getspeed, validate);
117#elif defined(BSD_VNSTAT)
118 result = getiflist_bsd(ifl, getspeed, validate);
119#else
120#error vnStat only supports Linux and BSD like systems
121#endif
122 cfg.maxbw = maxbw;
123 return result;
124}
125
126#if defined(__linux__) || defined(CHECK_VNSTAT)
127int getiflist_linux(iflist **ifl, const int getspeed, const int validate)
128{
129 char temp[64];
130 char interface[32];
131 FILE *fp;
132 DIR *dp;
133 struct dirent *di;
134 char procline[512];
135 uint32_t bwlimit = 0;
136
137 if ((fp = fopen(PROCNETDEV, "r")) != NULL) {
138
139 /* make list of interfaces */
140 while (fgets(procline, 512, fp) != NULL) {
141 sscanf(procline, "%63s", temp);
142 if (strlen(temp) > 0 && (isdigit(temp[(strlen(temp) - 1)]) || temp[(strlen(temp) - 1)] == ':')) {
143 sscanf(temp, "%31[^':']s", interface);
144 if (validate && !isifvalid(interface)) {
145 continue;
146 }
147 bwlimit = 0;
148 if (getspeed && ibwget(interface, &bwlimit)) {
149 iflistadd(ifl, interface, bwlimit);
150 } else {
151 iflistadd(ifl, interface, 0);
152 }
153 }
154 }
155
156 fclose(fp);
157 return 1;
158
159 } else {
160
161 if ((dp = opendir(SYSCLASSNET)) != NULL) {
162
163 /* make list of interfaces */
164 while ((di = readdir(dp))) {
165 if (di->d_name[0] == '.' || strlen(di->d_name) > 31) {
166 continue;
167 }
168 if (validate && !isifvalid(di->d_name)) {
169 continue;
170 }
171 bwlimit = 0;
172 if (getspeed && ibwget(di->d_name, &bwlimit)) {
173 iflistadd(ifl, di->d_name, bwlimit);
174 } else {
175 iflistadd(ifl, di->d_name, 0);
176 }
177 }
178
179 closedir(dp);
180 return 1;
181 }
182 }
183
184 return 0;
185}
186#elif defined(BSD_VNSTAT)
187int getiflist_bsd(iflist **ifl, const int getspeed, const int validate)
188{
189 struct ifaddrs *ifap, *ifa;
190 uint32_t bwlimit = 0;
191
192 if (getifaddrs(&ifap) >= 0) {
193
194 /* make list of interfaces */
195 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
196 if (ifa->ifa_addr->sa_family != AF_LINK || strlen(ifa->ifa_name) > 31) {
197 continue;
198 }
199 if (validate && !isifvalid(ifa->ifa_name)) {
200 continue;
201 }
202 bwlimit = 0;
203 if (getspeed && ibwget(ifa->ifa_name, &bwlimit)) {
204 iflistadd(ifl, ifa->ifa_name, getifspeed(ifa->ifa_name));
205 } else {
206 iflistadd(ifl, ifa->ifa_name, 0);
207 }
208 }
209
210 freeifaddrs(ifap);
211 return 1;
212 }
213
214 return 0;
215}
216#endif
217
218int readproc(const char *iface)
219{
220 FILE *fp;
221 char temp[4][64], procline[512], *proclineptr, ifaceid[33];
222 int check;
223
224 if ((fp = fopen(PROCNETDEV, "r")) == NULL) {
225 if (debug)
226 printf("Error (debug): Unable to read %s: %s\n", PROCNETDEV, strerror(errno));
227 return 0;
228 }
229
230 strncpy_nt(ifaceid, iface, 32);
231 strcat(ifaceid, ":");
232
233 check = 0;
234 while (fgets(procline, 512, fp) != NULL) {
235 sscanf(procline, "%63s", temp[0]);
236 if (strncmp(ifaceid, temp[0], strlen(ifaceid)) == 0) {
237 /* if (debug)
238 printf("\n%s\n", procline); */
239 check = 1;
240 break;
241 }
242 }
243 fclose(fp);
244
245 if (check == 0) {
246 if (debug)
247 printf("Requested interface \"%s\" not found.\n", iface);
248 return 0;
249 } else {
250
251 strncpy_nt(ifinfo.name, iface, 32);
252
253 /* get rx and tx from procline */
254 proclineptr = strchr(procline, ':');
255 sscanf(proclineptr + 1, "%63s %63s %*s %*s %*s %*s %*s %*s %63s %63s", temp[0], temp[1], temp[2], temp[3]);
256
257 ifinfo.rx = strtoull(temp[0], (char **)NULL, 0);
258 ifinfo.tx = strtoull(temp[2], (char **)NULL, 0);
259
260 /* daemon doesn't need packet data */
261 if (!noexit) {
262 ifinfo.rxp = strtoull(temp[1], (char **)NULL, 0);
263 ifinfo.txp = strtoull(temp[3], (char **)NULL, 0);
264 }
265
266 ifinfo.filled = 1;
267 }
268
269 return 1;
270}
271
272int readsysclassnet(const char *iface)
273{
274 FILE *fp;
275 char path[64], file[76], buffer[64];
276
277 strncpy_nt(ifinfo.name, iface, 32);
278
279 snprintf(path, 64, "%s/%s/statistics", SYSCLASSNET, iface);
280
281 if (debug)
282 printf("path: %s\n", path);
283
284 /* rx bytes */
285 snprintf(file, 76, "%s/rx_bytes", path);
286 if ((fp = fopen(file, "r")) == NULL) {
287 if (debug)
288 printf("Unable to read: %s - %s\n", file, strerror(errno));
289 return 0;
290 } else {
291 if (fgets(buffer, 64, fp) != NULL) {
292 ifinfo.rx = strtoull(buffer, (char **)NULL, 0);
293 } else {
294 fclose(fp);
295 return 0;
296 }
297 }
298 fclose(fp);
299
300 /* tx bytes */
301 snprintf(file, 76, "%s/tx_bytes", path);
302 if ((fp = fopen(file, "r")) == NULL) {
303 if (debug)
304 printf("Unable to read: %s - %s\n", file, strerror(errno));
305 return 0;
306 } else {
307 if (fgets(buffer, 64, fp) != NULL) {
308 ifinfo.tx = strtoull(buffer, (char **)NULL, 0);
309 } else {
310 fclose(fp);
311 return 0;
312 }
313 }
314 fclose(fp);
315
316 /* daemon doesn't need packet data */
317 if (!noexit) {
318
319 /* rx packets */
320 snprintf(file, 76, "%s/rx_packets", path);
321 if ((fp = fopen(file, "r")) == NULL) {
322 if (debug)
323 printf("Unable to read: %s - %s\n", file, strerror(errno));
324 return 0;
325 } else {
326 if (fgets(buffer, 64, fp) != NULL) {
327 ifinfo.rxp = strtoull(buffer, (char **)NULL, 0);
328 } else {
329 fclose(fp);
330 return 0;
331 }
332 }
333 fclose(fp);
334
335 /* tx packets */
336 snprintf(file, 76, "%s/tx_packets", path);
337 if ((fp = fopen(file, "r")) == NULL) {
338 if (debug)
339 printf("Unable to read: %s - %s\n", file, strerror(errno));
340 return 0;
341 } else {
342 if (fgets(buffer, 64, fp) != NULL) {
343 ifinfo.txp = strtoull(buffer, (char **)NULL, 0);
344 } else {
345 fclose(fp);
346 return 0;
347 }
348 }
349 fclose(fp);
350 }
351
352 ifinfo.filled = 1;
353
354 return 1;
355}
356
357#if defined(BSD_VNSTAT)
358int getifdata(const char *iface, struct if_data *ifd)
359{
360 struct ifaddrs *ifap, *ifa;
361 int check = 0;
362
363 if (getifaddrs(&ifap) < 0) {
364 if (debug)
365 printf("readifaddrs:getifaddrs() failed.\n");
366 return 0;
367 }
368 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
369 if ((strcmp(ifa->ifa_name, iface) == 0) && (ifa->ifa_addr->sa_family == AF_LINK)) {
370 if (ifa->ifa_data != NULL) {
371 memcpy(ifd, ifa->ifa_data, sizeof(struct if_data));
372 check = 1;
373 }
374 break;
375 }
376 }
377 freeifaddrs(ifap);
378
379 return check;
380}
381
382int readifaddrs(const char *iface)
383{
384 struct if_data ifd;
385
386 if (!getifdata(iface, &ifd)) {
387 if (debug)
388 printf("Requested interface \"%s\" not found.\n", iface);
389 return 0;
390 } else {
391 strncpy_nt(ifinfo.name, iface, 32);
392 ifinfo.rx = ifd.ifi_ibytes;
393 ifinfo.tx = ifd.ifi_obytes;
394 ifinfo.rxp = ifd.ifi_ipackets;
395 ifinfo.txp = ifd.ifi_opackets;
396 ifinfo.filled = 1;
397
398 if (cfg.is64bit == -2) {
399 if (sizeof(ifd.ifi_ibytes) == 8) {
400 ifinfo.is64bit = 1;
401 } else {
402 ifinfo.is64bit = 0;
403 }
404 }
405 }
406
407 return 1;
408}
409#endif
410
411uint32_t getifspeed(const char *iface)
412{
413 uint64_t speed = 0;
414
415#if defined(__linux__)
416
417 FILE *fp;
418 char file[64], buffer[64];
419
420 snprintf(file, 64, "%s/%s/speed", SYSCLASSNET, iface);
421
422 if ((fp = fopen(file, "r")) == NULL) {
423 if (debug)
424 printf("Unable to open: %s - %s\n", file, strerror(errno));
425 return 0;
426 } else {
427 if (fgets(buffer, 64, fp) != NULL) {
428 speed = strtoull(buffer, (char **)NULL, 0);
429 } else {
430 if (debug)
431 printf("Unable to read: %s - %s\n", file, strerror(errno));
432 fclose(fp);
433 return 0;
434 }
435 }
436 fclose(fp);
437
438#elif defined(BSD_VNSTAT)
439
440 struct if_data ifd;
441
442 if (!getifdata(iface, &ifd)) {
443 if (debug)
444 printf("Requested interface \"%s\" not found.\n", iface);
445 return 0;
446 } else {
447 speed = (uint64_t)ifd.ifi_baudrate;
448 }
449
450#endif
451
452 if (debug)
453 printf("getifspeed: \"%s\": %" PRIu64 "\n", iface, speed);
454
455 if (speed > 1000000) {
456 speed = 0;
457 }
458 return (uint32_t)speed;
459}
460
461int isifavailable(const char *iface)
462{
463 int ret = 0, printstatus;
464
465 printstatus = disableprints;
466 disableprints = 1;
467 ret = getifinfo(iface);
468 disableprints = printstatus;
469
470 return ret;
471}
472
473int isifvalid(const char *iface)
474{
475 if (strstr(iface, ":") != NULL) {
476 return 0;
477 } else if (strcmp(iface, "lo") == 0) {
478 return 0;
479 } else if (strcmp(iface, "lo0") == 0) {
480 return 0;
481 } else if (strcmp(iface, "sit0") == 0) {
482 return 0;
483 }
484 return 1;
485}
486
487/* tun interfaces have speed hardcoded as 10 in the Linux kernel regardless of used interface and can't
488be trusted to provide correct details as a result even if the information is available:
489https://github.com/torvalds/linux/blob/9d31d2338950293ec19d9b095fbaa9030899dcb4/drivers/net/tun.c#L3456 */
490int istun(const char *iface)
491{
492#if defined(__linux__)
493 if (strlen(iface) > 3 && strncmp(iface, "tun", 3) == 0) {
494 if (isdigit(iface[3])) {
495 return 1;
496 }
497 }
498#endif
499 return 0;
500}
int noexit
Definition: common.c:9
int disableprints
Definition: common.c:12
IFINFO ifinfo
Definition: common.c:5
void panicexit(const char *sourcefile, const int sourceline)
Definition: common.c:277
char errorstring[1024]
Definition: common.c:6
int printe(const PrintType type)
Definition: common.c:14
int debug
Definition: common.c:8
CFG cfg
Definition: common.c:4
char * strncpy_nt(char *dest, const char *src, size_t n)
Definition: common.c:253
#define PROCNETDEV
Definition: common.h:223
@ PT_Error
Definition: common.h:353
#define SYSCLASSNET
Definition: common.h:228
int ibwget(const char *iface, uint32_t *limit)
Definition: ibw.c:97
int istun(const char *iface)
Definition: ifinfo.c:490
int getiflist(iflist **ifl, const int getspeed, const int validate)
Definition: ifinfo.c:108
int getifliststring(char **ifacelist, int showspeed)
Definition: ifinfo.c:64
int readsysclassnet(const char *iface)
Definition: ifinfo.c:272
int getifinfo(const char *iface)
Definition: ifinfo.c:5
int readproc(const char *iface)
Definition: ifinfo.c:218
int isifvalid(const char *iface)
Definition: ifinfo.c:473
uint32_t getifspeed(const char *iface)
Definition: ifinfo.c:411
int isifavailable(const char *iface)
Definition: ifinfo.c:461
void iflistfree(iflist **ifl)
Definition: iflist.c:43
int iflistadd(iflist **ifl, const char *iface, const uint32_t bandwidth)
Definition: iflist.c:4
char iface[32]
Definition: common.h:308
int32_t maxbw
Definition: common.h:315
int32_t is64bit
Definition: common.h:316
time_t timestamp
Definition: common.h:337
uint64_t txp
Definition: common.h:336
short filled
Definition: common.h:331
short is64bit
Definition: common.h:332
char name[32]
Definition: common.h:330
uint64_t rx
Definition: common.h:333
uint64_t tx
Definition: common.h:334
uint64_t rxp
Definition: common.h:335
Definition: iflist.h:4