Conditionally enable TFTP block rollover hack
[oweals/nmrpflash.git] / ethsock.c
1 /**
2  * nmrpflash - Netgear Unbrick Utility
3  * Copyright (C) 2016 Joseph Lehner <joseph.c.lehner@gmail.com>
4  *
5  * nmrpflash is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * nmrpflash is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with nmrpflash.  If not, see <http://www.gnu.org/licenses/>.
17  *
18  */
19
20 #include <sys/types.h>
21 #include <stdbool.h>
22 #include <stdarg.h>
23 #include <string.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include "nmrpd.h"
28
29 #if defined(NMRPFLASH_WINDOWS)
30 #define NMRPFLASH_NETALIAS_PREFIX "net"
31 #define WPCAP
32 #include <pcap.h>
33 #else
34 #include <sys/ioctl.h>
35 #include <ifaddrs.h>
36 #include <unistd.h>
37 #include <net/if.h>
38 #include <pcap.h>
39 #if defined(NMRPFLASH_LINUX)
40 #define NMRPFLASH_AF_PACKET AF_PACKET
41 #include <linux/if_packet.h>
42 #include <netlink/route/addr.h>
43 #include <netlink/route/neighbour.h>
44 #else
45 #define NMRPFLASH_AF_PACKET AF_LINK
46 #include <net/if_types.h>
47 #include <net/if_media.h>
48 #endif
49 #endif
50
51 struct ethsock
52 {
53         const char *intf;
54         pcap_t *pcap;
55 #ifndef NMRPFLASH_WINDOWS
56         int fd;
57 #ifdef NMRPFLASH_LINUX
58         bool stp;
59 #endif
60 #else
61         HANDLE handle;
62         DWORD index;
63 #endif
64         unsigned timeout;
65         uint8_t hwaddr[6];
66 };
67
68 struct ethsock_arp_undo
69 {
70         uint32_t ipaddr;
71         uint8_t hwaddr[6];
72 };
73
74 struct ethsock_ip_undo
75 {
76 #ifndef NMRPFLASH_WINDOWS
77         uint32_t ip[2];
78 #else
79         ULONG context;
80 #endif
81 };
82
83 const char *mac_to_str(uint8_t *mac)
84 {
85         static char buf[18];
86         snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
87                         mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
88         return buf;
89 }
90
91 static int x_pcap_findalldevs(pcap_if_t **devs)
92 {
93         char errbuf[PCAP_ERRBUF_SIZE];
94         if (pcap_findalldevs(devs, errbuf) != 0) {
95                 fprintf(stderr, "%s.\n", errbuf);
96                 return -1;
97         }
98
99         return 0;
100 }
101
102 #ifndef NMRPFLASH_LINUX
103 static int systemf(const char *fmt, ...)
104 {
105         char cmd[1024];
106         int ret;
107         va_list va;
108         va_start(va, fmt);
109
110         ret = vsnprintf(cmd, sizeof(cmd) - 1, fmt, va);
111         if (ret >= sizeof(cmd) - 1) {
112                 return -1;
113         }
114
115         ret = system(cmd);
116         va_end(va);
117
118         return ret;
119 }
120 #endif
121
122 #ifndef NMRPFLASH_WINDOWS
123 static inline bool sockaddr_get_hwaddr(struct sockaddr *sa, uint8_t *hwaddr)
124 {
125         void *src;
126
127         if (sa->sa_family != NMRPFLASH_AF_PACKET) {
128                 return false;
129         }
130
131 #ifndef NMRPFLASH_LINUX
132         if (((struct sockaddr_dl*)sa)->sdl_type != IFT_ETHER) {
133                 return false;
134         }
135         src = LLADDR((struct sockaddr_dl*)sa);
136 #else
137         src = ((struct sockaddr_ll*)sa)->sll_addr;
138 #endif
139
140         memcpy(hwaddr, src, 6);
141         return true;
142 }
143
144 #ifdef NMRPFLASH_LINUX
145 static int bridge_stp_state(const char *intf)
146 {
147         char name[256];
148         snprintf(name, sizeof(name), "/sys/class/net/%s/bridge/stp_state", intf);
149         return open(name, O_RDWR, 0644);
150 }
151
152 static bool bridge_stp_enabled(const char *intf)
153 {
154         char c;
155         int fd = bridge_stp_state(intf);
156         if (fd == -1) {
157                 return false;
158         }
159
160         if (read(fd, &c, 1) != 1) {
161                 c = '0';
162         }
163
164         close(fd);
165         return c == '1';
166 }
167
168 static bool bridge_stp(const char *intf, bool enabled)
169 {
170         bool ret;
171         const char *s = enabled ? "1\n" : "0\n";
172         int fd = bridge_stp_state(intf);
173         if (fd == -1) {
174                 return false;
175         }
176
177         ret = (write(fd, s, 2) == 2);
178         close(fd);
179
180         return ret;
181 }
182
183 static struct nl_addr *build_ip(uint32_t ip)
184 {
185         struct nl_addr *na = nl_addr_build(AF_INET, &ip, 4);
186         if (!na) {
187                 xperror("nl_addr_build");
188         }
189
190         return na;
191 }
192
193 static struct nl_sock *xnl_socket_route()
194 {
195         int err;
196         struct nl_sock *sk = nl_socket_alloc();
197         if (sk) {
198                 if (!(err = nl_connect(sk, NETLINK_ROUTE))) {
199                         return sk;
200                 }
201                 nl_socket_free(sk);
202                 nl_perror(err, "nl_connect");
203         } else {
204                 xperror("nl_socket_alloc");
205         }
206
207         return NULL;
208 }
209
210 static bool intf_add_del_ip(const char *intf, uint32_t ipaddr, uint32_t ipmask, bool add)
211 {
212         struct rtnl_addr *ra = NULL;
213         struct nl_sock *sk = NULL;
214         struct nl_addr *na = NULL;
215         int err = 1;
216
217         if (!(sk = xnl_socket_route())) {
218                 return false;
219         }
220
221         if (!(ra = rtnl_addr_alloc())) {
222                 xperror("rtnl_addr_alloc");
223                 goto out;
224         }
225
226         rtnl_addr_set_ifindex(ra, if_nametoindex(intf));
227
228         if (!(na = build_ip(ipaddr))) {
229                 goto out;
230         }
231
232         nl_addr_set_prefixlen(na, bitcount(ipmask));
233         rtnl_addr_set_local(ra, na);
234         nl_addr_put(na);
235
236         if (!(na = build_ip((ipaddr & ipmask) | ~ipmask))) {
237                 goto out;
238         }
239
240         rtnl_addr_set_broadcast(ra, na);
241         nl_addr_put(na);
242
243         if ((err = add ? rtnl_addr_add(sk, ra, 0) : rtnl_addr_delete(sk, ra, 0)) < 0) {
244                 if (add && err == -NLE_EXIST) {
245                         err = 0;
246                 } else if (add || verbosity > 1) {
247                         nl_perror(err, add ? "rtnl_addr_add" : "rtnl_addr_delete");
248                 }
249         }
250
251 out:
252         rtnl_addr_put(ra);
253         nl_socket_free(sk);
254
255         return !err;
256 }
257
258 static bool intf_add_del_arp(const char *intf, uint32_t ipaddr, uint8_t *hwaddr, bool add)
259 {
260 #if 0
261         struct arpreq arp;
262         memset(&arp, 0, sizeof(arp));
263         arp.arp_ha.sa_family = ARPHRD_ETHER;
264         memcpy(&arp.arp_ha.sa_data, hwaddr, 6);
265         arp.arp_flags = ATF_PERM | ATF_COM;
266
267         struct sockaddr_in *in = (struct sockaddr_in*)&req.arp_pa;
268         in->sin_addr.s_addr = htonl(ipaddr);
269         in->sin_family = AF_INET;
270
271         int fd = socket(AF_INET, SOCK_DGRAM, 0);
272         if (fd < 0) {
273                 perror("socket");
274                 return false;
275         }
276
277         bool ret = true;
278
279         if (ioctl(fd, add ? SIOCSARP : SIOCDARP, &req) < 0) {
280                 perror(add ? "ioctl(SIOCSARP)" : "ioctl(SIOCDARP");
281                 ret = false;
282         }
283
284         close(fd);
285         return ret;
286 #else
287         struct nl_sock *sk;
288         struct rtnl_neigh *neigh;
289         struct nl_addr *mac, *ip;
290         int err = 1;
291
292         sk = NULL;
293         neigh = NULL;
294         mac = ip = NULL;
295
296         if (!(sk = xnl_socket_route())) {
297                 goto out;
298         }
299
300         if (!(neigh = rtnl_neigh_alloc())) {
301                 xperror("rtnl_neigh_alloc");
302                 goto out;
303         }
304
305         if (!(mac = nl_addr_build(AF_PACKET, hwaddr, 6))) {
306                 xperror("nl_addr_build");
307                 goto out;
308         }
309
310         if (!(ip = nl_addr_build(AF_INET, &ipaddr, 4))) {
311                 xperror("nl_addr_build");
312                 goto out;
313         }
314
315         rtnl_neigh_set_ifindex(neigh, if_nametoindex(intf));
316         rtnl_neigh_set_dst(neigh, ip);
317
318         err = rtnl_neigh_delete(sk, neigh, 0);
319
320         if (add) {
321                 rtnl_neigh_set_lladdr(neigh, mac);
322                 rtnl_neigh_set_state(neigh, NUD_PERMANENT);
323                 err = rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
324         }
325
326         if (err && (add || verbosity > 1)) {
327                 nl_perror(err, add ? "rtnl_neigh_add" : "rtnl_neigh_delete");
328         }
329
330 out:
331         nl_addr_put(ip);
332         nl_addr_put(mac);
333         rtnl_neigh_put(neigh);
334         nl_socket_free(sk);
335
336         return !err;
337 #endif
338 }
339
340 #endif
341
342 static bool intf_get_info(const char *intf, uint8_t *hwaddr, bool *bridge)
343 {
344         struct ifaddrs *ifas, *ifa;
345         bool found;
346
347         if (getifaddrs(&ifas) != 0) {
348                 xperror("getifaddrs");
349                 return false;
350         }
351
352         found = false;
353
354         if (bridge) {
355                 *bridge = false;
356         }
357
358         for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
359                 if (!strcmp(ifa->ifa_name, intf)) {
360                         if (sockaddr_get_hwaddr(ifa->ifa_addr, hwaddr)) {
361 #ifdef NMRPFLASH_BSD
362                                 if (bridge) {
363                                         *bridge = ((struct if_data*) ifa->ifa_data)->ifi_type == IFT_BRIDGE;
364                                 }
365 #endif
366                                 found = true;
367                                 break;
368                         }
369                 }
370         }
371
372         freeifaddrs(ifas);
373         return found;
374 }
375
376 #else
377
378 void win_perror2(const char *msg, DWORD err)
379 {
380         char *buf = NULL;
381         FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
382                         FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
383                         NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
384                         (LPTSTR)&buf, 0, NULL);
385
386         if (buf) {
387                 /* FormatMessageA terminates buf with CRLF! */
388                 fprintf(stderr, "%s: %s", msg, buf);
389                 LocalFree(buf);
390         } else {
391                 fprintf(stderr, "%s: error %d\n", msg, (int)err);
392         }
393 }
394
395 static bool intf_get_info(const char *intf, uint8_t *hwaddr, DWORD *index)
396 {
397         PIP_ADAPTER_INFO adapters, adapter;
398         DWORD ret;
399         ULONG i, bufLen = 0;
400         bool found = false;
401
402         if ((ret = GetAdaptersInfo(NULL, &bufLen)) != ERROR_BUFFER_OVERFLOW) {
403                 win_perror2("GetAdaptersInfo", ret);
404                 return false;
405         }
406
407         adapters = malloc(bufLen);
408         if (!adapters) {
409                 xperror("malloc");
410                 return false;
411         }
412
413         if ((ret = GetAdaptersInfo(adapters, &bufLen) == NO_ERROR)) {
414                 for (adapter = adapters; adapter; adapter = adapter->Next) {
415                         if (adapter->Type != MIB_IF_TYPE_ETHERNET && adapter->Type != IF_TYPE_IEEE80211) {
416                                 continue;
417                         }
418
419                         /* Interface names from WinPcap are "\Device\NPF_{GUID}", while
420                          * AdapterName from GetAdaptersInfo is just "{GUID}".*/
421                         if (strstr(intf, adapter->AdapterName)) {
422                                 if (adapter->AddressLength == 6) {
423                                         memcpy(hwaddr, adapter->Address, 6);
424                                         if (index) {
425                                                 *index = adapter->Index;
426                                         }
427                                         found = true;
428                                         break;
429                                 }
430                         }
431                 }
432         } else {
433                 win_perror2("GetAdaptersInfo", ret);
434         }
435
436         free(adapters);
437         return found;
438 }
439
440 static const char *intf_alias_to_wpcap(const char *intf)
441 {
442         static char buf[128];
443         pcap_if_t *devs, *dev;
444         unsigned i = 0, dev_num = 0;
445
446         if (intf[0] == '\\') {
447                 return intf;
448         } else if (sscanf(intf, NMRPFLASH_NETALIAS_PREFIX "%u", &dev_num) != 1) {
449                 fprintf(stderr, "Invalid interface alias.\n");
450                 return NULL;
451         }
452
453         if (x_pcap_findalldevs(&devs) != 0) {
454                 return NULL;
455         }
456
457         for (dev = devs; dev; dev = dev->next, ++i) {
458                 if (i == dev_num) {
459                         if (verbosity) {
460                                 printf("%s%u: %s\n", NMRPFLASH_NETALIAS_PREFIX, i, dev->name);
461                         }
462                         strncpy(buf, dev->name, sizeof(buf) - 1);
463                         buf[sizeof(buf) - 1] = '\0';
464                         break;
465                 }
466         }
467
468         pcap_freealldevs(devs);
469
470         if (!dev) {
471                 fprintf(stderr, "Interface alias not found.\n");
472                 return NULL;
473         }
474
475         return buf;
476 }
477
478 static const char *intf_get_pretty_name(const char *intf)
479 {
480         static char buf[512];
481         char *guid;
482         HKEY hkey;
483         LONG err;
484         DWORD len;
485
486         guid = strstr(intf, "NPF_{");
487         if (!guid) {
488                 return NULL;
489         }
490
491         guid += 4;
492
493         snprintf(buf, sizeof(buf),
494                         "System\\CurrentControlSet\\Control\\Network\\"
495                         "{4D36E972-E325-11CE-BFC1-08002BE10318}\\"
496                         "%s\\Connection", guid);
497         err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &hkey);
498         if (err != ERROR_SUCCESS) {
499                 if (verbosity > 1) {
500                         win_perror2("RegOpenKeyExA", err);
501                 }
502                 return NULL;
503         }
504
505         len = sizeof(buf);
506         err = RegQueryValueExA(hkey, "Name", NULL, NULL, (LPBYTE)buf, &len);
507         if (err == ERROR_SUCCESS) {
508                 intf = buf;
509         } else {
510                 if (verbosity > 1) {
511                         win_perror2("RegQueryValueExA", err);
512                 }
513                 intf = NULL;
514         }
515
516         RegCloseKey(hkey);
517         return intf;
518 }
519 #endif
520
521 inline uint8_t *ethsock_get_hwaddr(struct ethsock *sock)
522 {
523         return sock->hwaddr;
524 }
525
526 struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
527 {
528         char buf[PCAP_ERRBUF_SIZE];
529         struct bpf_program fp;
530         struct ethsock *sock;
531         bool is_bridge;
532         int err;
533
534 #ifdef NMRPFLASH_WINDOWS
535         intf = intf_alias_to_wpcap(intf);
536         if (!intf) {
537                 return NULL;
538         }
539 #endif
540
541         sock = malloc(sizeof(struct ethsock));
542         if (!sock) {
543                 xperror("malloc");
544                 return NULL;
545         }
546
547         buf[0] = '\0';
548
549         sock->intf = intf;
550         sock->pcap = pcap_open_live(sock->intf, BUFSIZ, 1, 1, buf);
551         if (!sock->pcap) {
552                 fprintf(stderr, "%s.\n", buf);
553                 goto cleanup;
554         }
555
556         if (*buf) {
557                 fprintf(stderr, "Warning: %s.\n", buf);
558         }
559
560         if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
561                 fprintf(stderr, "%s is not an ethernet interface.\n",
562                                 intf);
563                 goto cleanup;
564         }
565
566 #ifndef NMRPFLASH_WINDOWS
567         err = !intf_get_info(intf, sock->hwaddr, &is_bridge);
568 #else
569         err = !intf_get_info(intf, sock->hwaddr, &sock->index);
570 #endif
571         if (err) {
572                 fprintf(stderr, "Failed to get interface info.\n");
573                 goto cleanup;
574         }
575
576 #ifndef NMRPFLASH_WINDOWS
577         sock->fd = pcap_get_selectable_fd(sock->pcap);
578         if (sock->fd == -1) {
579                 pcap_perror(sock->pcap, "pcap_get_selectable_fd");
580                 goto cleanup;
581         }
582 #else
583         sock->handle = pcap_getevent(sock->pcap);
584         if (!sock->handle) {
585                 pcap_perror(sock->pcap, "pcap_getevent");
586                 goto cleanup;
587         }
588
589         err = pcap_setmintocopy(sock->pcap, 1);
590         if (err) {
591                 pcap_perror(sock->pcap, "pcap_setmintocopy");
592                 goto cleanup;
593         }
594 #endif
595
596         snprintf(buf, sizeof(buf), "ether proto 0x%04x and not ether src %s",
597                         protocol, mac_to_str(sock->hwaddr));
598
599         err = pcap_compile(sock->pcap, &fp, buf, 0, 0);
600         if (err) {
601                 pcap_perror(sock->pcap, "pcap_compile");
602                 goto cleanup;
603         }
604
605         err = pcap_setfilter(sock->pcap, &fp);
606         pcap_freecode(&fp);
607
608         if (err) {
609                 pcap_perror(sock->pcap, "pcap_setfilter");
610                 goto cleanup;
611         }
612
613 #ifdef NMRPFLASH_LINUX
614         // nmrpflash does not work on bridge interfaces with STP enabled
615         if ((sock->stp = bridge_stp_enabled(intf))) {
616                 if (!bridge_stp(intf, false)) {
617                         fprintf(stderr, "Warning: failed to disable STP on %s.\n", intf);
618                 }
619         }
620 #else
621         if (is_bridge) {
622                 fprintf(stderr, "Warning: bridge interfaces are not fully "
623                                 "supported on this platform.\n");
624         }
625 #endif
626
627         return sock;
628
629 cleanup:
630         ethsock_close(sock);
631         return NULL;
632 }
633
634 int select_fd(int fd, unsigned timeout)
635 {
636         struct timeval tv;
637         int status;
638         fd_set fds;
639
640         FD_ZERO(&fds);
641         FD_SET(fd, &fds);
642
643         tv.tv_sec = timeout / 1000;
644         tv.tv_usec = 1000 * (timeout % 1000);
645
646         status = select(fd + 1, &fds, NULL, NULL, &tv);
647         if (status < 0) {
648                 sock_perror("select");
649         }
650
651         return status;
652 }
653
654 ssize_t ethsock_recv(struct ethsock *sock, void *buf, size_t len)
655 {
656         struct pcap_pkthdr* hdr;
657         const u_char *capbuf;
658         int status;
659 #ifdef NMRPFLASH_WINDOWS
660         DWORD ret;
661
662         if (sock->timeout) {
663                 ret = WaitForSingleObject(sock->handle, sock->timeout);
664                 if (ret == WAIT_TIMEOUT) {
665                         return 0;
666                 } else if (ret != WAIT_OBJECT_0) {
667                         win_perror2("WaitForSingleObject", ret);
668                         return -1;
669                 }
670         }
671 #else
672         if (sock->timeout) {
673                 status = select_fd(sock->fd, sock->timeout);
674                 if (status < 0) {
675                         return -1;
676                 } else if (status == 0) {
677                         return 0;
678                 }
679         }
680 #endif
681
682         status = pcap_next_ex(sock->pcap, &hdr, &capbuf);
683         switch (status) {
684                 case 1:
685                         memcpy(buf, capbuf, MIN(len, hdr->caplen));
686                         return hdr->caplen;
687                 case 0:
688                         return 0;
689                 case -1:
690                         pcap_perror(sock->pcap, "pcap_next_ex");
691                         return -1;
692                 default:
693                         fprintf(stderr, "pcap_next_ex: returned %d.\n", status);
694                         return -1;
695         }
696 }
697
698 int ethsock_send(struct ethsock *sock, void *buf, size_t len)
699 {
700 #ifdef NMRPFLASH_WINDOWS
701         if (pcap_sendpacket(sock->pcap, buf, len) == 0) {
702                 return 0;
703         } else {
704                 pcap_perror(sock->pcap, "pcap_sendpacket");
705                 return -1;
706         }
707 #else
708         if (pcap_inject(sock->pcap, buf, len) == len) {
709                 return 0;
710         } else {
711                 pcap_perror(sock->pcap, "pcap_inject");
712                 return -1;
713         }
714 #endif
715 }
716
717 int ethsock_close(struct ethsock *sock)
718 {
719         if (!sock) {
720                 return 0;
721         }
722
723 #ifdef NMRPFLASH_LINUX
724         if (sock->stp) {
725                 bridge_stp(sock->intf, true);
726         }
727 #endif
728         if (sock->pcap) {
729                 pcap_close(sock->pcap);
730         }
731
732         free(sock);
733         return 0;
734 }
735
736 inline int ethsock_set_timeout(struct ethsock *sock, unsigned msec)
737 {
738         sock->timeout = msec;
739         return 0;
740 }
741
742 static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, uint32_t ipaddr, struct ethsock_arp_undo **undo)
743 {
744 #if defined(NMRPFLASH_UNIX) && !defined(NMRPFLASH_LINUX)
745         struct in_addr addr = { .s_addr = ipaddr };
746 #elif defined(NMRPFLASH_WINDOWS)
747         DWORD err;
748         MIB_IPNETROW arp = {
749                 .dwIndex = sock->index,
750                 .dwPhysAddrLen = 6,
751                 .dwAddr = ipaddr,
752                 .dwType = MIB_IPNET_TYPE_STATIC
753         };
754
755         memcpy(arp.bPhysAddr, hwaddr, 6);
756 #endif
757
758         if (undo) {
759 #if defined(NMRPFLASH_LINUX)
760                 if (!intf_add_del_arp(sock->intf, ipaddr, hwaddr, true)) {
761                         return -1;
762                 }
763 #elif defined(NMRPFLASH_WINDOWS)
764                 err = CreateIpNetEntry(&arp);
765                 if (err != NO_ERROR) {
766                         win_perror2("CreateIpNetEntry", err);
767                         return -1;
768                 }
769 #else
770                 if (systemf("arp -s %s %s", inet_ntoa(addr), mac_to_str(hwaddr)) != 0) {
771                         return -1;
772                 }
773 #endif
774
775                 *undo = malloc(sizeof(struct ethsock_arp_undo));
776                 if (!*undo) {
777                         xperror("malloc");
778                         return -1;
779                 }
780
781                 (*undo)->ipaddr = ipaddr;
782                 memcpy((*undo)->hwaddr, hwaddr, 6);
783         } else {
784 #if defined(NMRPFLASH_LINUX)
785                 if (!intf_add_del_arp(sock->intf, ipaddr, hwaddr, false)) {
786                         return -1;
787                 }
788 #elif defined(NMRPFLASH_WINDOWS)
789                 return DeleteIpNetEntry(&arp) ? 0 : -1;
790 #else
791                 return systemf("arp -d %s", inet_ntoa(addr));
792 #endif
793         }
794
795         return 0;
796 }
797
798 int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, uint32_t ipaddr, struct ethsock_arp_undo **undo)
799 {
800         ethsock_arp(sock, hwaddr, ipaddr, NULL);
801         return undo ? ethsock_arp(sock, hwaddr, ipaddr, undo) : -1;
802 }
803
804 int ethsock_arp_del(struct ethsock *sock, struct ethsock_arp_undo **undo)
805 {
806         if (!*undo) {
807                 return 0;
808         }
809
810         int ret = ethsock_arp(sock, (*undo)->hwaddr, (*undo)->ipaddr, NULL);
811         free(*undo);
812         *undo = NULL;
813         return ret;
814 }
815
816 static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr)
817 {
818 #ifndef NMRPFLASH_WINDOWS
819         pcap_addr_t *addr;
820         int i;
821
822         for (addr = dev->addresses; addr; addr = addr->next) {
823                 if (verbosity > 1) {
824                         printf("%s: sa_family=%d, sa_data={ ", dev->name,
825                                         addr->addr->sa_family);
826                         for (i = 0; i != sizeof(addr->addr->sa_data); ++i) {
827                                 printf("%02x ", addr->addr->sa_data[i] & 0xff);
828                         }
829                         printf("}\n");
830                 }
831
832                 if (sockaddr_get_hwaddr(addr->addr, hwaddr)) {
833                         return true;
834                 }
835         }
836 #endif
837
838         return intf_get_info(dev->name, hwaddr, NULL);
839 }
840
841 int ethsock_list_all(void)
842 {
843         pcap_if_t *devs, *dev;
844         pcap_addr_t *addr;
845         uint8_t hwaddr[6];
846         unsigned dev_num = 0, dev_ok = 0;
847 #ifdef NMRPFLASH_WINDOWS
848         const char *pretty;
849 #endif
850
851         if (x_pcap_findalldevs(&devs) != 0) {
852                 return -1;
853         }
854
855         memset(hwaddr, 0, 6);
856
857         for (dev = devs; dev; dev = dev->next, ++dev_num) {
858                 if (dev->flags & PCAP_IF_LOOPBACK) {
859                         if (verbosity) {
860                                 printf("%-15s  (loopback device)\n", dev->name);
861                         }
862                         continue;
863                 }
864
865                 if (!get_hwaddr_from_pcap(dev, hwaddr)) {
866                         if (verbosity) {
867                                 printf("%-15s  (not an ethernet device)\n",
868                                                 dev->name);
869                         }
870                         continue;
871                 }
872
873 #ifndef NMRPFLASH_WINDOWS
874                 printf("%-15s", dev->name);
875 #else
876                 /* Call this here so *_perror() calls don't happen within a line */
877                 pretty = intf_get_pretty_name(dev->name);
878
879                 if (!verbosity) {
880                         printf("%s%-2u", NMRPFLASH_NETALIAS_PREFIX, dev_num);
881                 } else {
882                         printf("%s", dev->name);
883                 }
884 #endif
885
886                 for (addr = dev->addresses; addr; addr = addr->next) {
887                         if (addr->addr->sa_family == AF_INET) {
888                                 printf("  %-15s",
889                                                 inet_ntoa(((struct sockaddr_in*)addr->addr)->sin_addr));
890                                 break;
891                         }
892                 }
893
894                 if (!addr) {
895                         printf("  %-15s", "0.0.0.0");
896                 }
897
898                 printf("  %s", mac_to_str(hwaddr));
899
900 #ifdef NMRPFLASH_WINDOWS
901                 if (pretty) {
902                         printf("  (%s)", pretty);
903                 } else if (dev->description) {
904                         printf("  (%s)", dev->description);
905                 }
906
907 #endif
908                 printf("\n");
909                 ++dev_ok;
910         }
911
912         if (!dev_ok) {
913                 printf("No suitable network interfaces found.\n");
914         }
915
916         return 0;
917 }
918
919 int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback,
920                 void *arg)
921 {
922         struct ethsock_ip_callback_args args;
923         pcap_if_t *devs, *dev;
924         pcap_addr_t *addr;
925         int status = 0;
926
927         if (x_pcap_findalldevs(&devs) != 0) {
928                 return -1;
929         }
930
931         args.arg = arg;
932
933         for (dev = devs; dev; dev = dev->next) {
934                 if (strcmp(sock->intf, dev->name)) {
935                         continue;
936                 }
937
938                 for (addr = dev->addresses; addr; addr = addr->next) {
939                         if (addr->addr->sa_family == AF_INET) {
940                                 args.ipaddr = &((struct sockaddr_in*)addr->addr)->sin_addr;
941                                 args.ipmask = &((struct sockaddr_in*)addr->netmask)->sin_addr;
942
943                                 status = callback(&args);
944                                 if (status <= 0) {
945                                         break;
946                                 }
947                         }
948                 }
949
950                 break;
951         }
952
953         pcap_freealldevs(devs);
954
955         return status <= 0 ? status : 0;
956 }
957
958 static inline void set_addr(void *p, uint32_t addr)
959 {
960         struct sockaddr_in* sin = p;
961         sin->sin_family = AF_INET;
962         sin->sin_addr.s_addr = addr;
963 #ifdef NMRPFLASH_BSD
964         ((struct sockaddr*)p)->sa_len = sizeof(struct sockaddr_in);
965 #endif
966 }
967
968 #if !defined(NMRPFLASH_WINDOWS) && !defined(NMRPFLASH_LINUX)
969 static bool intf_up(int fd, const char *intf, bool up)
970 {
971         struct ifreq ifr;
972         strncpy(ifr.ifr_name, intf, IFNAMSIZ);
973
974         if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
975                 if (up) {
976                         xperror("ioctl(SIOCGIFFLAGS)");
977                 }
978                 return false;
979         }
980
981         if (!up) {
982                 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
983         } else {
984                 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
985         }
986
987         if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
988                 if (up) {
989                         xperror("ioctl(SIOCSIFFLAGS)");
990                 }
991                 return false;
992         }
993
994         return true;
995 }
996 #endif
997
998 static int ethsock_ip_add_del(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo, bool add)
999 {
1000         int ret, fd;
1001
1002         if (add && undo) {
1003                 if (!(*undo = malloc(sizeof(struct ethsock_ip_undo)))) {
1004                         xperror("malloc");
1005                         return -1;
1006                 }
1007
1008                 memset(*undo, 0, sizeof(**undo));
1009         }
1010
1011         ret = -1;
1012         fd = socket(AF_INET, SOCK_DGRAM, 0);
1013         if (fd < 0) {
1014                 sock_perror("socket");
1015                 goto out;
1016         }
1017
1018 #ifndef NMRPFLASH_WINDOWS
1019 #ifdef NMRPFLASH_LINUX
1020         if (add) {
1021                 (*undo)->ip[0] = ipaddr;
1022                 (*undo)->ip[1] = ipmask;
1023         }
1024
1025         if (!intf_add_del_ip(sock->intf, (*undo)->ip[0], (*undo)->ip[1], add)) {
1026                 goto out;
1027         }
1028 #else // NMRPFLASH_OSX (or any other BSD)
1029         struct ifaliasreq ifra;
1030         memset(&ifra, 0, sizeof(ifra));
1031         strncpy(ifra.ifra_name, sock->intf, IFNAMSIZ);
1032
1033         set_addr(&ifra.ifra_addr, ipaddr);
1034         set_addr(&ifra.ifra_mask, ipmask);
1035         //set_addr(&ifra.ifra_broadaddr, (ipaddr & ipmask) | ~ipmask);
1036
1037         if (ioctl(fd, add ? SIOCAIFADDR : SIOCDIFADDR, &ifra) != 0) {
1038                 if (add) {
1039                         xperror("ioctl(SIOCAIFADDR");
1040                 }
1041                 goto out;
1042         }
1043
1044         if (add) {
1045                 (*undo)->ip[0] = ipaddr;
1046                 (*undo)->ip[1] = ipmask;
1047                 intf_up(fd, ifra.ifra_name, true);
1048         }
1049
1050 #endif
1051 #else // NMRPFLASH_WINDOWS
1052         struct sockaddr_in sin;
1053         ULONG instance;
1054
1055         (*undo)->context = 0;
1056
1057         DWORD err = AddIPAddress(ipaddr, ipmask, sock->index, &(*undo)->context, &instance);
1058         if (err != NO_ERROR && err != ERROR_DUP_DOMAINNAME && err != ERROR_OBJECT_ALREADY_EXISTS) {
1059                 win_perror2("AddIPAddress", err);
1060                 goto out;
1061         }
1062
1063         set_addr(&sin, ipaddr);
1064         time_t beg = time_monotonic();
1065
1066         /* Wait until the new IP has actually been added */
1067
1068         while (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
1069                 if ((time_monotonic() - beg) >= 5) {
1070                         fprintf(stderr, "Failed to bind after 5 seconds: ");
1071                         sock_perror("bind");
1072                         DeleteIPAddress((*undo)->context);
1073                         goto out;
1074                 }
1075         }
1076 #endif
1077         ret = 0;
1078
1079 out:
1080 #ifndef NMRPFLASH_WINDOWS
1081         close(fd);
1082 #else
1083         closesocket(fd);
1084 #endif
1085         if (ret != 0 && undo) {
1086                 free(*undo);
1087                 *undo = NULL;
1088         }
1089
1090         return ret;
1091 }
1092
1093 int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
1094 {
1095         return ethsock_ip_add_del(sock, ipaddr, ipmask, undo, true);
1096 }
1097
1098 int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo)
1099 {
1100         if (!*undo) {
1101                 return 0;
1102         }
1103
1104         int ret;
1105
1106 #ifndef NMRPFLASH_WINDOWS
1107         if ((*undo)->ip[0] != INADDR_NONE) {
1108                 ret = ethsock_ip_add_del(sock, (*undo)->ip[0], (*undo)->ip[1], undo, false);
1109         } else {
1110                 ret = 0;
1111         }
1112 #else
1113         ret = DeleteIPAddress((*undo)->context) ? 0 : -1;
1114 #endif
1115
1116         free(*undo);
1117         *undo = NULL;
1118         return ret;
1119 }