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