2 * nmrpflash - Netgear Unbrick Utility
3 * Copyright (C) 2016 Joseph Lehner <joseph.c.lehner@gmail.com>
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.
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.
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/>.
20 #include <sys/types.h>
29 #if defined(NMRPFLASH_WINDOWS)
30 #define NMRPFLASH_NETALIAS_PREFIX "net"
34 #include <sys/ioctl.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>
45 #define NMRPFLASH_AF_PACKET AF_LINK
46 #include <net/if_types.h>
47 #include <net/if_media.h>
55 #ifndef NMRPFLASH_WINDOWS
57 #ifdef NMRPFLASH_LINUX
68 struct ethsock_arp_undo
74 struct ethsock_ip_undo
76 #ifndef NMRPFLASH_WINDOWS
83 const char *mac_to_str(uint8_t *mac)
86 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x",
87 mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
91 static int x_pcap_findalldevs(pcap_if_t **devs)
93 char errbuf[PCAP_ERRBUF_SIZE];
94 if (pcap_findalldevs(devs, errbuf) != 0) {
95 fprintf(stderr, "%s.\n", errbuf);
102 static int systemf(const char *fmt, ...)
109 ret = vsnprintf(cmd, sizeof(cmd) - 1, fmt, va);
110 if (ret >= sizeof(cmd) - 1) {
120 #ifndef NMRPFLASH_WINDOWS
121 static inline bool sockaddr_get_hwaddr(struct sockaddr *sa, uint8_t *hwaddr)
125 if (sa->sa_family != NMRPFLASH_AF_PACKET) {
129 #ifndef NMRPFLASH_LINUX
130 if (((struct sockaddr_dl*)sa)->sdl_type != IFT_ETHER) {
133 src = LLADDR((struct sockaddr_dl*)sa);
135 src = ((struct sockaddr_ll*)sa)->sll_addr;
138 memcpy(hwaddr, src, 6);
142 #ifdef NMRPFLASH_LINUX
143 static int bridge_stp_state(const char *intf)
146 snprintf(name, sizeof(name), "/sys/class/net/%s/bridge/stp_state", intf);
147 return open(name, O_RDWR, 0644);
150 static bool bridge_stp_enabled(const char *intf)
153 int fd = bridge_stp_state(intf);
158 if (read(fd, &c, 1) != 1) {
166 static bool bridge_stp(const char *intf, bool enabled)
169 const char *s = enabled ? "1\n" : "0\n";
170 int fd = bridge_stp_state(intf);
175 ret = (write(fd, s, 2) == 2);
181 static bool xrtnl_addr_set(struct rtnl_addr *ra, uint32_t addr, int (*cb)(struct rtnl_addr*, struct nl_addr*))
184 struct nl_addr *na = nl_addr_build(AF_INET, &addr, 4);
187 xperror("nl_addr_build");
191 if ((err = cb(ra, na)) != 0 && verbosity) {
192 nl_perror(err, __func__);
199 static struct nl_sock *xnl_socket_route()
202 struct nl_sock *sk = nl_socket_alloc();
204 if (!(err = nl_connect(sk, NETLINK_ROUTE))) {
208 nl_perror(err, "nl_connect");
210 xperror("nl_socket_alloc");
216 static bool intf_add_del_ip(const char *intf, uint32_t ipaddr, uint32_t ipmask, bool add)
218 struct rtnl_addr *ra = NULL;
219 struct nl_sock *sk = NULL;
222 if (!(sk = xnl_socket_route())) {
226 if (!(ra = rtnl_addr_alloc())) {
227 xperror("rtnl_addr_alloc");
231 rtnl_addr_set_ifindex(ra, if_nametoindex(intf));
232 rtnl_addr_set_prefixlen(ra, bitcount(ipmask));
234 if (!xrtnl_addr_set(ra, (ipaddr & ipmask) | ~ipmask, &rtnl_addr_set_broadcast)
235 || !xrtnl_addr_set(ra, ipaddr, &rtnl_addr_set_local)) {
239 if ((err = add ? rtnl_addr_add(sk, ra, 0) : rtnl_addr_delete(sk, ra, 0)) < 0) {
240 if (add && err == -NLE_EXIST) {
242 } else if (add || verbosity > 1) {
243 nl_perror(err, add ? "rtnl_addr_add" : "rtnl_addr_delete");
254 static bool intf_add_del_arp(const char *intf, uint32_t ipaddr, uint8_t *hwaddr, bool add)
257 struct rtnl_neigh *neigh;
258 struct nl_addr *mac, *ip;
265 if (!(sk = xnl_socket_route())) {
269 if (!(neigh = rtnl_neigh_alloc())) {
270 xperror("rtnl_neigh_alloc");
274 if (!(mac = nl_addr_build(AF_PACKET, hwaddr, 6))) {
275 xperror("nl_addr_build");
279 if (!(ip = nl_addr_build(AF_INET, &ipaddr, 4))) {
280 xperror("nl_addr_build");
284 rtnl_neigh_set_ifindex(neigh, if_nametoindex(intf));
285 rtnl_neigh_set_dst(neigh, ip);
287 err = rtnl_neigh_delete(sk, neigh, 0);
290 rtnl_neigh_set_lladdr(neigh, mac);
291 rtnl_neigh_set_state(neigh, NUD_PERMANENT);
293 err = rtnl_neigh_add(sk, neigh, NLM_F_CREATE);
297 if (err && (add || verbosity > 1)) {
298 nl_perror(err, add ? "rtnl_neigh_add" : "rtnl_neigh_delete");
304 rtnl_neigh_put(neigh);
312 static bool intf_get_info(const char *intf, uint8_t *hwaddr, bool *bridge)
314 struct ifaddrs *ifas, *ifa;
317 if (getifaddrs(&ifas) != 0) {
318 xperror("getifaddrs");
328 for (ifa = ifas; ifa; ifa = ifa->ifa_next) {
329 if (!strcmp(ifa->ifa_name, intf)) {
330 if (sockaddr_get_hwaddr(ifa->ifa_addr, hwaddr)) {
333 *bridge = ((struct if_data*) ifa->ifa_data)->ifi_type == IFT_BRIDGE;
348 void win_perror2(const char *msg, DWORD err)
351 FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
352 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
353 NULL, err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
354 (LPTSTR)&buf, 0, NULL);
357 /* FormatMessageA terminates buf with CRLF! */
358 fprintf(stderr, "%s: %s", msg, buf);
361 fprintf(stderr, "%s: error %d\n", msg, (int)err);
365 static bool intf_get_info(const char *intf, uint8_t *hwaddr, DWORD *index)
367 PIP_ADAPTER_INFO adapters, adapter;
372 if ((ret = GetAdaptersInfo(NULL, &bufLen)) != ERROR_BUFFER_OVERFLOW) {
373 win_perror2("GetAdaptersInfo", ret);
377 adapters = malloc(bufLen);
383 if ((ret = GetAdaptersInfo(adapters, &bufLen) == NO_ERROR)) {
384 for (adapter = adapters; adapter; adapter = adapter->Next) {
385 if (adapter->Type != MIB_IF_TYPE_ETHERNET && adapter->Type != IF_TYPE_IEEE80211) {
389 /* Interface names from WinPcap are "\Device\NPF_{GUID}", while
390 * AdapterName from GetAdaptersInfo is just "{GUID}".*/
391 if (strstr(intf, adapter->AdapterName)) {
392 if (adapter->AddressLength == 6) {
393 memcpy(hwaddr, adapter->Address, 6);
395 *index = adapter->Index;
403 win_perror2("GetAdaptersInfo", ret);
410 static const char *intf_alias_to_wpcap(const char *intf)
412 static char buf[128];
413 pcap_if_t *devs, *dev;
414 unsigned i = 0, dev_num = 0;
416 if (intf[0] == '\\') {
418 } else if (sscanf(intf, NMRPFLASH_NETALIAS_PREFIX "%u", &dev_num) != 1) {
419 fprintf(stderr, "Invalid interface alias.\n");
423 if (x_pcap_findalldevs(&devs) != 0) {
427 for (dev = devs; dev; dev = dev->next, ++i) {
430 printf("%s%u: %s\n", NMRPFLASH_NETALIAS_PREFIX, i, dev->name);
432 strncpy(buf, dev->name, sizeof(buf) - 1);
433 buf[sizeof(buf) - 1] = '\0';
438 pcap_freealldevs(devs);
441 fprintf(stderr, "Interface alias not found.\n");
448 static const char *intf_get_pretty_name(const char *intf)
450 static char buf[512];
456 guid = strstr(intf, "NPF_{");
463 snprintf(buf, sizeof(buf),
464 "System\\CurrentControlSet\\Control\\Network\\"
465 "{4D36E972-E325-11CE-BFC1-08002BE10318}\\"
466 "%s\\Connection", guid);
467 err = RegOpenKeyExA(HKEY_LOCAL_MACHINE, buf, 0, KEY_READ, &hkey);
468 if (err != ERROR_SUCCESS) {
470 win_perror2("RegOpenKeyExA", err);
476 err = RegQueryValueExA(hkey, "Name", NULL, NULL, (LPBYTE)buf, &len);
477 if (err == ERROR_SUCCESS) {
481 win_perror2("RegQueryValueExA", err);
491 inline uint8_t *ethsock_get_hwaddr(struct ethsock *sock)
496 struct ethsock *ethsock_create(const char *intf, uint16_t protocol)
498 char buf[PCAP_ERRBUF_SIZE];
499 struct bpf_program bpf;
500 struct ethsock *sock;
504 #ifdef NMRPFLASH_WINDOWS
505 intf = intf_alias_to_wpcap(intf);
511 sock = malloc(sizeof(struct ethsock));
520 sock->pcap = pcap_open_live(sock->intf, BUFSIZ, 1, 1, buf);
522 fprintf(stderr, "%s.\n", buf);
527 fprintf(stderr, "Warning: %s.\n", buf);
530 if (pcap_datalink(sock->pcap) != DLT_EN10MB) {
531 fprintf(stderr, "%s is not an ethernet interface.\n",
536 #ifndef NMRPFLASH_WINDOWS
537 err = !intf_get_info(intf, sock->hwaddr, &is_bridge);
539 err = !intf_get_info(intf, sock->hwaddr, &sock->index);
542 fprintf(stderr, "Failed to get interface info.\n");
546 #ifndef NMRPFLASH_WINDOWS
547 sock->fd = pcap_get_selectable_fd(sock->pcap);
548 if (sock->fd == -1) {
549 pcap_perror(sock->pcap, "pcap_get_selectable_fd");
553 sock->handle = pcap_getevent(sock->pcap);
555 pcap_perror(sock->pcap, "pcap_getevent");
559 err = pcap_setmintocopy(sock->pcap, 1);
561 pcap_perror(sock->pcap, "pcap_setmintocopy");
566 err = pcap_setdirection(sock->pcap, PCAP_D_IN);
568 pcap_perror(sock->pcap, "pcap_setdirection");
572 snprintf(buf, sizeof(buf), "ether proto 0x%04x", protocol);
574 err = pcap_compile(sock->pcap, &bpf, buf, 0, 0);
576 pcap_perror(sock->pcap, "pcap_compile");
580 err = pcap_setfilter(sock->pcap, &bpf);
584 pcap_perror(sock->pcap, "pcap_setfilter");
588 #ifdef NMRPFLASH_LINUX
589 // nmrpflash does not work on bridge interfaces with STP enabled
590 if ((sock->stp = bridge_stp_enabled(intf))) {
591 if (!bridge_stp(intf, false)) {
592 fprintf(stderr, "Warning: failed to disable STP on %s.\n", intf);
597 fprintf(stderr, "Warning: bridge interfaces are not fully "
598 "supported on this platform.\n");
609 int select_fd(int fd, unsigned timeout)
618 tv.tv_sec = timeout / 1000;
619 tv.tv_usec = 1000 * (timeout % 1000);
621 status = select(fd + 1, &fds, NULL, NULL, &tv);
623 sock_perror("select");
629 ssize_t ethsock_recv(struct ethsock *sock, void *buf, size_t len)
631 struct pcap_pkthdr* hdr;
632 const u_char *capbuf;
634 #ifdef NMRPFLASH_WINDOWS
638 ret = WaitForSingleObject(sock->handle, sock->timeout);
639 if (ret == WAIT_TIMEOUT) {
641 } else if (ret != WAIT_OBJECT_0) {
642 win_perror2("WaitForSingleObject", ret);
648 status = select_fd(sock->fd, sock->timeout);
651 } else if (status == 0) {
657 status = pcap_next_ex(sock->pcap, &hdr, &capbuf);
660 memcpy(buf, capbuf, MIN(len, hdr->caplen));
665 pcap_perror(sock->pcap, "pcap_next_ex");
668 fprintf(stderr, "pcap_next_ex: returned %d.\n", status);
673 int ethsock_send(struct ethsock *sock, void *buf, size_t len)
675 #ifdef NMRPFLASH_WINDOWS
676 if (pcap_sendpacket(sock->pcap, buf, len) == 0) {
679 pcap_perror(sock->pcap, "pcap_sendpacket");
683 if (pcap_inject(sock->pcap, buf, len) == len) {
686 pcap_perror(sock->pcap, "pcap_inject");
692 int ethsock_close(struct ethsock *sock)
698 #ifdef NMRPFLASH_LINUX
700 bridge_stp(sock->intf, true);
704 pcap_close(sock->pcap);
711 inline int ethsock_set_timeout(struct ethsock *sock, unsigned msec)
713 sock->timeout = msec;
717 static int ethsock_arp(struct ethsock *sock, uint8_t *hwaddr, uint32_t ipaddr, struct ethsock_arp_undo **undo)
719 #if defined(NMRPFLASH_UNIX) && !defined(NMRPFLASH_LINUX)
720 struct in_addr addr = { .s_addr = ipaddr };
721 #elif defined(NMRPFLASH_WINDOWS)
724 .dwIndex = sock->index,
727 .dwType = MIB_IPNET_TYPE_STATIC
730 memcpy(arp.bPhysAddr, hwaddr, 6);
734 #if defined(NMRPFLASH_LINUX)
735 if (!intf_add_del_arp(sock->intf, ipaddr, hwaddr, true)) {
738 #elif defined(NMRPFLASH_WINDOWS)
739 err = CreateIpNetEntry(&arp);
740 if (err != NO_ERROR) {
741 win_perror2("CreateIpNetEntry", err);
745 if (systemf("arp -s %s %s", inet_ntoa(addr), mac_to_str(hwaddr)) != 0) {
750 *undo = malloc(sizeof(struct ethsock_arp_undo));
756 (*undo)->ipaddr = ipaddr;
757 memcpy((*undo)->hwaddr, hwaddr, 6);
759 #if defined(NMRPFLASH_LINUX)
760 if (!intf_add_del_arp(sock->intf, ipaddr, hwaddr, false)) {
763 #elif defined(NMRPFLASH_WINDOWS)
764 return DeleteIpNetEntry(&arp) ? 0 : -1;
766 return systemf("arp -d %s", inet_ntoa(addr);
773 int ethsock_arp_add(struct ethsock *sock, uint8_t *hwaddr, uint32_t ipaddr, struct ethsock_arp_undo **undo)
775 ethsock_arp(sock, hwaddr, ipaddr, NULL);
776 return undo ? ethsock_arp(sock, hwaddr, ipaddr, undo) : -1;
779 int ethsock_arp_del(struct ethsock *sock, struct ethsock_arp_undo **undo)
785 int ret = ethsock_arp(sock, (*undo)->hwaddr, (*undo)->ipaddr, NULL);
791 static bool get_hwaddr_from_pcap(const pcap_if_t *dev, uint8_t *hwaddr)
793 #ifndef NMRPFLASH_WINDOWS
797 for (addr = dev->addresses; addr; addr = addr->next) {
799 printf("%s: sa_family=%d, sa_data={ ", dev->name,
800 addr->addr->sa_family);
801 for (i = 0; i != sizeof(addr->addr->sa_data); ++i) {
802 printf("%02x ", addr->addr->sa_data[i] & 0xff);
807 if (sockaddr_get_hwaddr(addr->addr, hwaddr)) {
813 return intf_get_info(dev->name, hwaddr, NULL);
816 int ethsock_list_all(void)
818 pcap_if_t *devs, *dev;
821 unsigned dev_num = 0, dev_ok = 0;
822 #ifdef NMRPFLASH_WINDOWS
826 if (x_pcap_findalldevs(&devs) != 0) {
830 memset(hwaddr, 0, 6);
832 for (dev = devs; dev; dev = dev->next, ++dev_num) {
833 if (dev->flags & PCAP_IF_LOOPBACK) {
835 printf("%-15s (loopback device)\n", dev->name);
840 if (!get_hwaddr_from_pcap(dev, hwaddr)) {
842 printf("%-15s (not an ethernet device)\n",
848 #ifndef NMRPFLASH_WINDOWS
849 printf("%-15s", dev->name);
851 /* Call this here so *_perror() calls don't happen within a line */
852 pretty = intf_get_pretty_name(dev->name);
855 printf("%s%-2u", NMRPFLASH_NETALIAS_PREFIX, dev_num);
857 printf("%s", dev->name);
861 for (addr = dev->addresses; addr; addr = addr->next) {
862 if (addr->addr->sa_family == AF_INET) {
864 inet_ntoa(((struct sockaddr_in*)addr->addr)->sin_addr));
870 printf(" %-15s", "0.0.0.0");
873 printf(" %s", mac_to_str(hwaddr));
875 #ifdef NMRPFLASH_WINDOWS
877 printf(" (%s)", pretty);
878 } else if (dev->description) {
879 printf(" (%s)", dev->description);
888 printf("No suitable network interfaces found.\n");
894 int ethsock_for_each_ip(struct ethsock *sock, ethsock_ip_callback_t callback,
897 struct ethsock_ip_callback_args args;
898 pcap_if_t *devs, *dev;
902 if (x_pcap_findalldevs(&devs) != 0) {
908 for (dev = devs; dev; dev = dev->next) {
909 if (strcmp(sock->intf, dev->name)) {
913 for (addr = dev->addresses; addr; addr = addr->next) {
914 if (addr->addr->sa_family == AF_INET) {
915 args.ipaddr = &((struct sockaddr_in*)addr->addr)->sin_addr;
916 args.ipmask = &((struct sockaddr_in*)addr->netmask)->sin_addr;
918 status = callback(&args);
928 pcap_freealldevs(devs);
930 return status <= 0 ? status : 0;
933 static inline void set_addr(void *p, uint32_t addr)
935 struct sockaddr_in* sin = p;
936 sin->sin_family = AF_INET;
937 sin->sin_addr.s_addr = addr;
939 ((struct sockaddr*)p)->sa_len = sizeof(struct sockaddr_in);
943 #if !defined(NMRPFLASH_WINDOWS) && !defined(NMRPFLASH_LINUX)
944 static bool intf_up(int fd, const char *intf, bool up)
947 strncpy(ifr.ifr_name, intf, IFNAMSIZ);
949 if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
951 xperror("ioctl(SIOCGIFFLAGS)");
957 ifr.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
959 ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
962 if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
964 xperror("ioctl(SIOCSIFFLAGS)");
973 static int ethsock_ip_add_del(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo, bool add)
978 if (!(*undo = malloc(sizeof(struct ethsock_ip_undo)))) {
983 memset(*undo, 0, sizeof(**undo));
987 fd = socket(AF_INET, SOCK_DGRAM, 0);
989 sock_perror("socket");
993 #ifndef NMRPFLASH_WINDOWS
994 #ifdef NMRPFLASH_LINUX
996 (*undo)->ip[0] = ipaddr;
997 (*undo)->ip[1] = ipmask;
1000 if (!intf_add_del_ip(sock->intf, (*undo)->ip[0], (*undo)->ip[1], add)) {
1003 #else // NMRPFLASH_OSX (or any other BSD)
1004 struct ifaliasreq ifra;
1005 memset(&ifra, 0, sizeof(ifra));
1006 strncpy(ifra.ifra_name, sock->intf, IFNAMSIZ);
1008 set_addr(&ifra.ifra_addr, ipaddr);
1009 set_addr(&ifra.ifra_mask, ipmask);
1010 //set_addr(&ifra.ifra_broadaddr, (ipaddr & ipmask) | ~ipmask);
1012 if (ioctl(fd, add ? SIOCAIFADDR : SIOCDIFADDR, &ifra) != 0) {
1014 xperror("ioctl(SIOCAIFADDR");
1020 (*undo)->ip[0] = ipaddr;
1021 (*undo)->ip[1] = ipmask;
1022 intf_up(fd, ifra.ifra_name, true);
1026 #else // NMRPFLASH_WINDOWS
1027 struct sockaddr_in sin;
1030 (*undo)->context = 0;
1032 DWORD err = AddIPAddress(ipaddr, ipmask, sock->index, &(*undo)->context, &instance);
1033 if (err != NO_ERROR && err != ERROR_DUP_DOMAINNAME && err != ERROR_OBJECT_ALREADY_EXISTS) {
1034 win_perror2("AddIPAddress", err);
1038 set_addr(&sin, ipaddr);
1039 time_t beg = time_monotonic();
1041 /* Wait until the new IP has actually been added */
1043 while (bind(fd, (struct sockaddr*)&sin, sizeof(sin)) != 0) {
1044 if ((time_monotonic() - beg) >= 5) {
1045 fprintf(stderr, "Failed to bind after 5 seconds: ");
1046 sock_perror("bind");
1047 DeleteIPAddress((*undo)->context);
1055 #ifndef NMRPFLASH_WINDOWS
1060 if (ret != 0 && undo) {
1068 int ethsock_ip_add(struct ethsock *sock, uint32_t ipaddr, uint32_t ipmask, struct ethsock_ip_undo **undo)
1070 return ethsock_ip_add_del(sock, ipaddr, ipmask, undo, true);
1073 int ethsock_ip_del(struct ethsock *sock, struct ethsock_ip_undo **undo)
1081 #ifndef NMRPFLASH_WINDOWS
1082 if ((*undo)->ip[0] != INADDR_NONE) {
1083 ret = ethsock_ip_add_del(sock, (*undo)->ip[0], (*undo)->ip[1], undo, false);
1088 ret = DeleteIPAddress((*undo)->context) ? 0 : -1;