1#include "../util.h"
2
3#include <arpa/inet.h>
4#include <ctype.h>
5#include <errno.h>
6#include <ifaddrs.h>
7#include <net/if.h>
8#include <net/route.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <string.h>
12#include <sys/ioctl.h>
13#include <sys/socket.h>
14#include <unistd.h>
15
16#ifdef __linux__
17#include <netpacket/packet.h>
18#else
19#include <net/if_dl.h>
20#include <sys/sysctl.h>
21#endif
22
23static void
24get_mtu_metric(const char *name, int *mtu, int *metric)
25{
26 struct ifreq ifr;
27 int sock;
28
29 *mtu = 0;
30 *metric = 0;
31 sock = socket(AF_INET, SOCK_DGRAM, 0);
32 if (sock < 0)
33 return;
34 memset(&ifr, 0, sizeof(ifr));
35 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
36 if (ioctl(sock, SIOCGIFMTU, &ifr) >= 0)
37 *mtu = ifr.ifr_mtu;
38 if (ioctl(sock, SIOCGIFMETRIC, &ifr) >= 0)
39 *metric = ifr.ifr_metric;
40 close(sock);
41}
42
43int
44net_get_interfaces(struct NetInterface **ifaces, int *count)
45{
46 struct ifaddrs *ifaddr, *ifa;
47 struct NetInterface *list = NULL;
48 struct NetInterface *iface;
49 int found_count = 0;
50 int i;
51
52 if (getifaddrs(&ifaddr) < 0)
53 return -1;
54
55 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
56 iface = NULL;
57 for (i = 0; i < found_count; i++) {
58 if (strcmp(list[i].name, ifa->ifa_name) == 0) {
59 iface = &list[i];
60 break;
61 }
62 }
63 if (!iface) {
64 list = reallocarray(list, found_count + 1, sizeof(*list));
65 if (!list) {
66 freeifaddrs(ifaddr);
67 return -1;
68 }
69 iface = &list[found_count];
70 memset(iface, 0, sizeof(*iface));
71 strlcpy(iface->name, ifa->ifa_name, sizeof(iface->name));
72 iface->flags = ifa->ifa_flags;
73 get_mtu_metric(iface->name, &iface->mtu, &iface->metric);
74 found_count++;
75 }
76
77 if (!ifa->ifa_addr)
78 continue;
79
80 if (ifa->ifa_addr->sa_family == AF_INET) {
81 memcpy(&iface->ipv4_addr, ifa->ifa_addr, sizeof(struct sockaddr_in));
82 iface->has_ipv4 = 1;
83 if (ifa->ifa_netmask)
84 memcpy(&iface->ipv4_mask, ifa->ifa_netmask, sizeof(struct sockaddr_in));
85 if (ifa->ifa_dstaddr)
86 memcpy(&iface->ipv4_brd, ifa->ifa_dstaddr, sizeof(struct sockaddr_in));
87 } else if (ifa->ifa_addr->sa_family == AF_INET6) {
88 memcpy(&iface->ipv6_addr, ifa->ifa_addr, sizeof(struct sockaddr_in6));
89 iface->has_ipv6 = 1;
90 /* scope id could be set here from sin6_scope_id */
91 }
92#ifdef __linux__
93 else if (ifa->ifa_addr->sa_family == AF_PACKET) {
94 struct sockaddr_ll *sll = (struct sockaddr_ll *)ifa->ifa_addr;
95 if (sll->sll_halen == 6) {
96 memcpy(iface->mac, sll->sll_addr, 6);
97 iface->has_mac = 1;
98 }
99 }
100#else
101 else if (ifa->ifa_addr->sa_family == AF_LINK) {
102 struct sockaddr_dl *sdl = (struct sockaddr_dl *)ifa->ifa_addr;
103 if (sdl->sdl_alen == 6) {
104 memcpy(iface->mac, LLADDR(sdl), 6);
105 iface->has_mac = 1;
106 }
107 }
108#endif
109 }
110
111 freeifaddrs(ifaddr);
112 *ifaces = list;
113 *count = found_count;
114 return 0;
115}
116
117#ifdef __linux__
118int
119net_get_stats(const char *ifname, struct NetStats *stats)
120{
121 FILE *fp;
122 char line[256];
123 char *p, *name;
124 int found = 0;
125
126 memset(stats, 0, sizeof(*stats));
127 fp = fopen("/proc/net/dev", "r");
128 if (!fp)
129 return -1;
130
131 while (fgets(line, sizeof(line), fp)) {
132 p = strchr(line, ':');
133 if (p) {
134 *p = '\0';
135 name = line;
136 while (isspace(*name))
137 name++;
138 if (strcmp(name, ifname) == 0) {
139 if (sscanf(p + 1, "%llu %llu %llu %llu %*u %*u %*u %*u %llu %llu %llu %llu",
140 &stats->rx_bytes, &stats->rx_packets, &stats->rx_errs, &stats->rx_drop,
141 &stats->tx_bytes, &stats->tx_packets, &stats->tx_errs, &stats->tx_drop) == 8) {
142 found = 1;
143 }
144 break;
145 }
146 }
147 }
148 fclose(fp);
149 return found ? 0 : -1;
150}
151#else
152int
153net_get_stats(const char *ifname, struct NetStats *stats)
154{
155 struct ifaddrs *ifaddr, *ifa;
156 int found = 0;
157
158 memset(stats, 0, sizeof(*stats));
159 if (getifaddrs(&ifaddr) < 0)
160 return -1;
161
162 for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
163 if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_LINK &&
164 strcmp(ifa->ifa_name, ifname) == 0) {
165 struct if_data *ifd = (struct if_data *)ifa->ifa_data;
166 if (ifd) {
167 stats->rx_bytes = ifd->ifi_ibytes;
168 stats->rx_packets = ifd->ifi_ipackets;
169 stats->rx_errs = ifd->ifi_ierrors;
170 stats->rx_drop = ifd->ifi_iqdrops;
171 stats->tx_bytes = ifd->ifi_obytes;
172 stats->tx_packets = ifd->ifi_opackets;
173 stats->tx_errs = ifd->ifi_oerrors;
174 stats->tx_drop = 0;
175 found = 1;
176 break;
177 }
178 }
179 }
180 freeifaddrs(ifaddr);
181 return found ? 0 : -1;
182}
183#endif
184
185#ifdef __linux__
186int
187net_set_txqueuelen(const char *name, int qlen)
188{
189 struct ifreq ifr;
190 int sock;
191
192 sock = socket(AF_INET, SOCK_DGRAM, 0);
193 if (sock < 0)
194 return -1;
195 memset(&ifr, 0, sizeof(ifr));
196 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
197 ifr.ifr_qlen = qlen;
198 if (ioctl(sock, SIOCSIFTXQLEN, &ifr) < 0) {
199 close(sock);
200 return -1;
201 }
202 close(sock);
203 return 0;
204}
205#else
206int
207net_set_txqueuelen(const char *name, int qlen)
208{
209 (void)name;
210 (void)qlen;
211 return -1;
212}
213#endif
214
215int
216net_set_flags(const char *name, unsigned int flags, int set)
217{
218 struct ifreq ifr;
219 int sock;
220
221 sock = socket(AF_INET, SOCK_DGRAM, 0);
222 if (sock < 0)
223 return -1;
224 memset(&ifr, 0, sizeof(ifr));
225 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
226 if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0) {
227 close(sock);
228 return -1;
229 }
230 if (set)
231 ifr.ifr_flags |= flags;
232 else
233 ifr.ifr_flags &= ~flags;
234 if (ioctl(sock, SIOCSIFFLAGS, &ifr) < 0) {
235 close(sock);
236 return -1;
237 }
238 close(sock);
239 return 0;
240}
241
242int
243net_set_mtu(const char *name, int mtu)
244{
245 struct ifreq ifr;
246 int sock;
247
248 sock = socket(AF_INET, SOCK_DGRAM, 0);
249 if (sock < 0)
250 return -1;
251 memset(&ifr, 0, sizeof(ifr));
252 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
253 ifr.ifr_mtu = mtu;
254 if (ioctl(sock, SIOCSIFMTU, &ifr) < 0) {
255 close(sock);
256 return -1;
257 }
258 close(sock);
259 return 0;
260}
261
262int
263net_set_mac(const char *name, const unsigned char mac[6])
264{
265#ifdef __linux__
266 struct ifreq ifr;
267 int sock;
268
269 sock = socket(AF_INET, SOCK_DGRAM, 0);
270 if (sock < 0)
271 return -1;
272 memset(&ifr, 0, sizeof(ifr));
273 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
274 ifr.ifr_hwaddr.sa_family = 1;
275 memcpy(ifr.ifr_hwaddr.sa_data, mac, 6);
276 if (ioctl(sock, SIOCSIFHWADDR, &ifr) < 0) {
277 close(sock);
278 return -1;
279 }
280 close(sock);
281 return 0;
282#else
283 (void)name;
284 (void)mac;
285 return -1;
286#endif
287}
288
289int
290net_add_addr(const char *name, const char *addr, int prefix)
291{
292 struct ifreq ifr;
293 struct sockaddr_in *sin;
294 int sock;
295 unsigned int mask;
296
297 sock = socket(AF_INET, SOCK_DGRAM, 0);
298 if (sock < 0)
299 return -1;
300
301 memset(&ifr, 0, sizeof(ifr));
302 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
303
304 sin = (struct sockaddr_in *)&ifr.ifr_addr;
305 sin->sin_family = AF_INET;
306 if (inet_pton(AF_INET, addr, &sin->sin_addr) <= 0) {
307 close(sock);
308 return -1;
309 }
310
311 if (ioctl(sock, SIOCSIFADDR, &ifr) < 0) {
312 close(sock);
313 return -1;
314 }
315
316 if (prefix >= 0) {
317 mask = 0;
318 if (prefix > 0)
319 mask = htonl(~0U << (32 - prefix));
320 sin = (struct sockaddr_in *)&ifr.ifr_netmask;
321 sin->sin_family = AF_INET;
322 sin->sin_addr.s_addr = mask;
323 if (ioctl(sock, SIOCSIFNETMASK, &ifr) < 0) {
324 close(sock);
325 return -1;
326 }
327 }
328
329 memset(&ifr, 0, sizeof(ifr));
330 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
331 if (ioctl(sock, SIOCGIFFLAGS, &ifr) >= 0) {
332 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
333 ioctl(sock, SIOCSIFFLAGS, &ifr);
334 }
335
336 close(sock);
337 return 0;
338}
339
340int
341net_del_addr(const char *name, const char *addr, int prefix)
342{
343 struct ifreq ifr;
344 struct sockaddr_in *sin;
345 int sock;
346
347 (void)prefix;
348 sock = socket(AF_INET, SOCK_DGRAM, 0);
349 if (sock < 0)
350 return -1;
351
352 memset(&ifr, 0, sizeof(ifr));
353 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
354
355 sin = (struct sockaddr_in *)&ifr.ifr_addr;
356 sin->sin_family = AF_INET;
357 if (inet_pton(AF_INET, addr, &sin->sin_addr) <= 0) {
358 close(sock);
359 return -1;
360 }
361
362 if (ioctl(sock, SIOCDIFADDR, &ifr) < 0) {
363 close(sock);
364 return -1;
365 }
366 close(sock);
367 return 0;
368}
369
370int
371net_show_routes(void)
372{
373#ifdef __linux__
374 FILE *fp;
375 char line[256];
376 char iface[16], dest[16], gateway[16], mask[16];
377 unsigned int d, g, m, flags, metric;
378
379 fp = fopen("/proc/net/route", "r");
380 if (!fp)
381 return -1;
382
383 printf("%-10s %-15s %-15s %-15s %-6s %-6s\n", "Iface", "Destination", "Gateway", "Genmask", "Flags", "Metric");
384 if (fgets(line, sizeof(line), fp)) {
385 while (fgets(line, sizeof(line), fp)) {
386 if (sscanf(line, "%15s %x %x %x %*u %*u %u %x", iface, &d, &g, &m, &metric, &flags) == 6) {
387 struct in_addr dest_addr, gw_addr, mask_addr;
388 dest_addr.s_addr = d;
389 gw_addr.s_addr = g;
390 mask_addr.s_addr = m;
391 strlcpy(dest, inet_ntoa(dest_addr), sizeof(dest));
392 strlcpy(gateway, inet_ntoa(gw_addr), sizeof(gateway));
393 strlcpy(mask, inet_ntoa(mask_addr), sizeof(mask));
394 printf("%-10s %-15s %-15s %-15s 0x%04X %-6u\n", iface, dest, gateway, mask, flags, metric);
395 }
396 }
397 }
398 fclose(fp);
399 return 0;
400#else
401 printf("route listing not implemented on this OS\n");
402 return 0;
403#endif
404}
405
406int
407net_add_route(const char *dst, const char *gateway, const char *mask, const char *dev, int metric)
408{
409 struct rtentry rt;
410 struct sockaddr_in *sin;
411 int sock;
412
413 sock = socket(AF_INET, SOCK_DGRAM, 0);
414 if (sock < 0)
415 return -1;
416
417 memset(&rt, 0, sizeof(rt));
418
419 sin = (struct sockaddr_in *)&rt.rt_dst;
420 sin->sin_family = AF_INET;
421 if (strcmp(dst, "default") == 0) {
422 sin->sin_addr.s_addr = INADDR_ANY;
423 } else {
424 if (inet_pton(AF_INET, dst, &sin->sin_addr) <= 0) {
425 close(sock);
426 return -1;
427 }
428 }
429
430 if (gateway) {
431 sin = (struct sockaddr_in *)&rt.rt_gateway;
432 sin->sin_family = AF_INET;
433 if (inet_pton(AF_INET, gateway, &sin->sin_addr) <= 0) {
434 close(sock);
435 return -1;
436 }
437 rt.rt_flags |= RTF_GATEWAY;
438 }
439
440 if (mask) {
441 sin = (struct sockaddr_in *)&rt.rt_genmask;
442 sin->sin_family = AF_INET;
443 if (inet_pton(AF_INET, mask, &sin->sin_addr) <= 0) {
444 close(sock);
445 return -1;
446 }
447 }
448
449 rt.rt_flags |= RTF_UP;
450 if (dev)
451 rt.rt_dev = (char *)dev;
452 if (metric >= 0)
453 rt.rt_metric = metric + 1;
454
455 if (ioctl(sock, SIOCADDRT, &rt) < 0) {
456 close(sock);
457 return -1;
458 }
459
460 close(sock);
461 return 0;
462}
463
464int
465net_del_route(const char *dst, const char *gateway, const char *mask, const char *dev, int metric)
466{
467 struct rtentry rt;
468 struct sockaddr_in *sin;
469 int sock;
470
471 sock = socket(AF_INET, SOCK_DGRAM, 0);
472 if (sock < 0)
473 return -1;
474
475 memset(&rt, 0, sizeof(rt));
476
477 sin = (struct sockaddr_in *)&rt.rt_dst;
478 sin->sin_family = AF_INET;
479 if (strcmp(dst, "default") == 0) {
480 sin->sin_addr.s_addr = INADDR_ANY;
481 } else {
482 if (inet_pton(AF_INET, dst, &sin->sin_addr) <= 0) {
483 close(sock);
484 return -1;
485 }
486 }
487
488 if (gateway) {
489 sin = (struct sockaddr_in *)&rt.rt_gateway;
490 sin->sin_family = AF_INET;
491 if (inet_pton(AF_INET, gateway, &sin->sin_addr) <= 0) {
492 close(sock);
493 return -1;
494 }
495 rt.rt_flags |= RTF_GATEWAY;
496 }
497
498 if (mask) {
499 sin = (struct sockaddr_in *)&rt.rt_genmask;
500 sin->sin_family = AF_INET;
501 if (inet_pton(AF_INET, mask, &sin->sin_addr) <= 0) {
502 close(sock);
503 return -1;
504 }
505 }
506
507 rt.rt_flags |= RTF_UP;
508 if (dev)
509 rt.rt_dev = (char *)dev;
510 if (metric >= 0)
511 rt.rt_metric = metric + 1;
512
513 if (ioctl(sock, SIOCDELRT, &rt) < 0) {
514 close(sock);
515 return -1;
516 }
517
518 close(sock);
519 return 0;
520}
521
522int
523net_flush_addrs(const char *dev)
524{
525 struct NetInterface *ifaces = NULL;
526 int count = 0, i, r = 0;
527
528 if (net_get_interfaces(&ifaces, &count) < 0)
529 return -1;
530
531 for (i = 0; i < count; i++) {
532 if (strcmp(ifaces[i].name, dev) == 0) {
533 if (ifaces[i].has_ipv4) {
534 char addr_str[16];
535 struct sockaddr_in *sin = &ifaces[i].ipv4_addr;
536 inet_ntop(AF_INET, &sin->sin_addr, addr_str, sizeof(addr_str));
537 if (net_del_addr(dev, addr_str, -1) < 0)
538 r = -1;
539 }
540 }
541 }
542 free(ifaces);
543 return r;
544}
545
546int
547net_set_name(const char *name, const char *newname)
548{
549#ifdef __linux__
550 struct ifreq ifr;
551 int sock;
552
553 sock = socket(AF_INET, SOCK_DGRAM, 0);
554 if (sock < 0)
555 return -1;
556 memset(&ifr, 0, sizeof(ifr));
557 strlcpy(ifr.ifr_name, name, sizeof(ifr.ifr_name));
558 strlcpy(ifr.ifr_newname, newname, sizeof(ifr.ifr_newname));
559 if (ioctl(sock, SIOCSIFNAME, &ifr) < 0) {
560 close(sock);
561 return -1;
562 }
563 close(sock);
564 return 0;
565#else
566 (void)name;
567 (void)newname;
568 return -1;
569#endif
570}