This patch replaces our home grown (possibly old musl version based)
implementation of getifaddrs() and if_nameindex() with the
implemantation of those provided by modern version musl 1.1.24 that
uses netlink interface. The advantage is that it will also support
IPV6 once we merge the ipv6 branch.

Please note that we are applying simple header trick with __netlink.h
to counter a bug in musl netlink.c. In essence the __netlink_enumerate()
in musl netlink.c calls recv() with MSG_DONTWAIT flag may (and it does
sometimes on OSv) yield EAGAIN or EWOULDBLOCK errors and there is no
error handling logic of those. Instead of adding the error handling we
change recv call to use 0 flags by re-defining MSG_DONTWAIT as 0 to
enforce blocking call which is for example what Golang runtime does
to implement similar functionality. Eventually we should try to upstream
a patch to musl.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
---
 Makefile                    |   6 +-
 libc/network/__netlink.h    |   4 +
 libc/network/getifaddrs.c   | 252 ------------------------------------
 libc/network/if_nameindex.c |  58 ---------
 4 files changed, 8 insertions(+), 312 deletions(-)
 create mode 100644 libc/network/__netlink.h
 delete mode 100644 libc/network/getifaddrs.c
 delete mode 100644 libc/network/if_nameindex.c

diff --git a/Makefile b/Makefile
index 2d1ba6a8..ad70580c 100644
--- a/Makefile
+++ b/Makefile
@@ -1503,10 +1503,12 @@ musl += network/getservbyname_r.o
 musl += network/getservbyname.o
 musl += network/getservbyport_r.o
 musl += network/getservbyport.o
-libc += network/getifaddrs.o
-libc += network/if_nameindex.o
+musl += network/getifaddrs.o
+musl += network/if_nameindex.o
 musl += network/if_freenameindex.o
 musl += network/res_init.o
+musl += network/netlink.o
+$(out)/musl/src/network/netlink.o: CFLAGS += --include 
libc/syscall_to_function.h --include libc/network/__netlink.h
 
 musl += prng/rand.o
 musl += prng/rand_r.o
diff --git a/libc/network/__netlink.h b/libc/network/__netlink.h
new file mode 100644
index 00000000..4be572a5
--- /dev/null
+++ b/libc/network/__netlink.h
@@ -0,0 +1,4 @@
+#include <sys/socket.h>
+#undef MSG_DONTWAIT
+//Let us disable the non-blocking call to recv() netlink.c by re-defining 
MSG_DONTWAIT as 0
+#define MSG_DONTWAIT 0
diff --git a/libc/network/getifaddrs.c b/libc/network/getifaddrs.c
deleted file mode 100644
index 435c93b3..00000000
--- a/libc/network/getifaddrs.c
+++ /dev/null
@@ -1,252 +0,0 @@
-/* (C) 2013 John Spencer. released under musl's standard MIT license. */
-#undef _GNU_SOURCE
-#define _GNU_SOURCE
-#include <ifaddrs.h>
-#include <stdlib.h>
-#include <net/if.h> /* IFNAMSIZ, ifreq, ifconf */
-#include <stdio.h>
-#include <ctype.h>
-#include <string.h>
-#include <errno.h>
-#include <arpa/inet.h> /* inet_pton */
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <netpacket/packet.h>
-#include <net/if_arp.h>
-
-typedef union {
-       struct sockaddr_in6 v6;
-       struct sockaddr_in v4;
-       struct sockaddr_ll hw;
-} soa;
-
-typedef struct ifaddrs_storage {
-       struct ifaddrs ifa;
-       soa addr;
-       soa netmask;
-       soa dst;
-       char name[IFNAMSIZ+1];
-} stor;
-#define next ifa.ifa_next
-
-static stor* list_add(stor** list, stor** head, char* ifname)
-{
-       stor* curr = calloc(1, sizeof(stor));
-       if(curr) {
-               strcpy(curr->name, ifname);
-               curr->ifa.ifa_name = curr->name;
-               if(*head) (*head)->next = (struct ifaddrs*) curr;
-               *head = curr;
-               if(!*list) *list = curr;
-       }
-       return curr;
-}
-
-void freeifaddrs(struct ifaddrs *ifp)
-{
-       stor *head = (stor *) ifp;
-       while(head) {
-               void *p = head;
-               head = (stor *) head->next;
-               free(p);
-       }
-}
-
-static void ipv6netmask(unsigned prefix_length, struct sockaddr_in6 *sa)
-{
-       unsigned char* hb = sa->sin6_addr.s6_addr;
-       unsigned onebytes = prefix_length / 8;
-       unsigned bits = prefix_length % 8;
-       unsigned nullbytes = 16 - onebytes;
-       memset(hb, -1, onebytes);
-       memset(hb+onebytes, 0, nullbytes);
-       if(bits) {
-               unsigned char x = -1;
-               x <<= 8 - bits;
-               hb[onebytes] = x;
-       }
-}
-
-static void dealwithipv6(stor **list, stor** head)
-{
-       FILE* f = fopen("/proc/net/if_inet6", "r");
-       /* 00000000000000000000000000000001 01 80 10 80 lo
-          A                                B  C  D  E  F
-          all numbers in hex
-          A = addr B=netlink device#, C=prefix length,
-          D = scope value (ipv6.h) E = interface flags (rnetlink.h, addrconf.c)
-          F = if name */
-       char v6conv[32 + 7 + 1], *v6;
-       char *line, linebuf[512];
-       if(!f) return;
-       while((line = fgets(linebuf, sizeof linebuf, f))) {
-               v6 = v6conv;
-               size_t i = 0;
-               for(; i < 8; i++) {
-                       memcpy(v6, line, 4);
-                       v6+=4;
-                       *v6++=':';
-                       line+=4;
-               }
-               --v6; *v6 = 0;
-               line++;
-               unsigned b, c, d, e;
-               char name[IFNAMSIZ+1];
-               if(5 == sscanf(line, "%x %x %x %x %s", &b, &c, &d, &e, name)) {
-                       struct sockaddr_in6 sa = {0};
-                       if(1 == inet_pton(AF_INET6, v6conv, &sa.sin6_addr)) {
-                               sa.sin6_family = AF_INET6;
-                               stor* curr = list_add(list, head, name);
-                               if(!curr) goto out;
-                               curr->addr.v6 = sa;
-                               curr->ifa.ifa_addr = (struct sockaddr*) 
&curr->addr;
-                               ipv6netmask(c, &sa);
-                               curr->netmask.v6 = sa;
-                               curr->ifa.ifa_netmask = (struct sockaddr*) 
&curr->netmask;
-                               /* find ipv4 struct with the same interface 
name to copy flags */
-                               stor* scan = *list;
-                               for(;scan && strcmp(name, 
scan->name);scan=(stor*)scan->next);
-                               if(scan) curr->ifa.ifa_flags = 
scan->ifa.ifa_flags;
-                               else curr->ifa.ifa_flags = 0;
-                       } else errno = 0;
-               }
-       }
-       out:
-       fclose(f);
-}
-
-static int allocate_and_add_ifaddrs(stor **list, stor **head, struct 
if_nameindex *ii)
-{
-       size_t i;
-       for(i = 0; ii[i].if_index || ii[i].if_name; i++) {
-               stor* curr = list_add(list, head, ii[i].if_name);
-               if(!curr) {
-                       return 0;
-               }
-       }
-       return i;
-}
-
-static int fill_mac_addrs(int sock, stor *list, struct if_nameindex *ii)
-{
-       stor *head;
-       size_t i;
-
-       for(head = list, i = 0;
-           head; head = (stor*)(head->next)) {
-               struct sockaddr_ll *hw_addr = (struct sockaddr_ll *) 
&head->addr;
-               head->ifa.ifa_addr = (struct sockaddr*) &head->addr;
-               struct ifreq req;
-               int ret;
-
-               if (!ii[i].if_name) {
-                       continue;
-               }
-
-               /* zero the ifreq structure */
-               memset(&req, 0, sizeof(req));
-
-               /* fill in the interface name */
-               strlcpy(req.ifr_name, ii[i].if_name, IFNAMSIZ);
-
-               /* Get the hardware address */
-               ret = ioctl(sock, SIOCGIFHWADDR, &req);
-               if (ret == -1) {
-                       return ret;
-               }
-
-               /* Fill address, index, type, length, familly */
-               memcpy(hw_addr->sll_addr, req.ifr_hwaddr.sa_data, IFHWADDRLEN);
-               hw_addr->sll_ifindex  = ii[i].if_index;
-               hw_addr->sll_hatype = ARPHRD_ETHER;
-               hw_addr->sll_halen  = IFHWADDRLEN;
-               hw_addr->sll_family = AF_PACKET;
-
-               /* Get and fill the address flags */
-               ret = ioctl(sock, SIOCGIFFLAGS, &req);
-               if (ret == - 1) {
-                       return ret;
-               }
-               head->ifa.ifa_flags = req.ifr_flags;
-               i++;
-       }
-
-       return 0;
-}
-
-int getifaddrs(struct ifaddrs **ifap)
-{
-       stor *list = 0, *head = 0;
-       struct if_nameindex* ii = if_nameindex();
-       if(!ii) return -1;
-       int addr_count;
-       size_t i;
-       // allocate and add to the list twice the number of
-       // interface of ifaddr storage in order to have enough
-       // for MAC HW addresses that require their own location.
-       for (i = 0; i < 2; i++) {
-               addr_count =
-                       allocate_and_add_ifaddrs(&list, &head, ii);
-               if (!addr_count) {
-                       if_freenameindex(ii);
-                       goto err2;
-               }
-       }
-       if_freenameindex(ii);
-
-       int sock = socket(PF_INET, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_IP);
-       if(sock == -1) goto err2;
-       struct ifreq reqs[32]; /* arbitrary chosen boundary */
-       struct ifconf conf = {.ifc_len = sizeof reqs, .ifc_req = reqs};
-       if(-1 == ioctl(sock, SIOCGIFCONF, &conf)) goto err;
-       size_t reqitems = conf.ifc_len / sizeof(struct ifreq);
-       int j;
-       // loop and fill the INET addrs
-       for(head = list, j = 0; head && j < addr_count; head = 
(stor*)head->next, j++) {
-               for(i = 0; i < reqitems; i++) {
-                       // get SIOCGIFADDR of active interfaces.
-                       if(!strcmp(reqs[i].ifr_name, head->name)) {
-                               head->addr.v4 = *(struct 
sockaddr_in*)&reqs[i].ifr_addr;
-                               head->ifa.ifa_addr = (struct sockaddr*) 
&head->addr;
-                               break;
-                       }
-               }
-               struct ifreq req;
-               snprintf(req.ifr_name, sizeof req.ifr_name, "%s", head->name);
-               if(-1 == ioctl(sock, SIOCGIFFLAGS, &req)) goto err;
-
-               head->ifa.ifa_flags = req.ifr_flags;
-               if(head->ifa.ifa_addr) {
-                       /* or'ing flags with IFF_LOWER_UP on active interfaces 
to mimic glibc */
-                       head->ifa.ifa_flags |= IFF_LOWER_UP; 
-                       if(-1 == ioctl(sock, SIOCGIFNETMASK, &req)) goto err;
-                       head->netmask.v4 = *(struct 
sockaddr_in*)&req.ifr_netmask;
-                       head->ifa.ifa_netmask = (struct sockaddr*) 
&head->netmask;
-       
-                       if(head->ifa.ifa_flags & IFF_POINTOPOINT) {
-                               if(-1 == ioctl(sock, SIOCGIFDSTADDR, &req)) 
goto err;
-                               head->dst.v4 = *(struct 
sockaddr_in*)&req.ifr_dstaddr;
-                       } else {
-                               if(-1 == ioctl(sock, SIOCGIFBRDADDR, &req)) 
goto err;
-                               head->dst.v4 = *(struct 
sockaddr_in*)&req.ifr_broadaddr;
-                       }
-                       head->ifa.ifa_ifu.ifu_dstaddr = (struct sockaddr*) 
&head->dst;
-               }
-       }
-       if (-1 == fill_mac_addrs(sock, head, ii)) {
-               goto err;
-       }
-       close(sock);
-       void* last = 0;
-       for(head = list; head; head=(stor*)head->next) last=head;
-       head = last;
-       dealwithipv6(&list, &head);
-       *ifap = (struct ifaddrs*) list;
-       return 0;
-       err:
-       close(sock);
-       err2:
-       freeifaddrs((struct ifaddrs*) list);
-       return -1;
-}
-
diff --git a/libc/network/if_nameindex.c b/libc/network/if_nameindex.c
deleted file mode 100644
index b0a4f5c1..00000000
--- a/libc/network/if_nameindex.c
+++ /dev/null
@@ -1,58 +0,0 @@
-#define _GNU_SOURCE
-#include <net/if.h>
-#include <stdlib.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/syscall.h>
-
-#include <stdio.h>
-
-static void *do_nameindex(int s, size_t n)
-{
-       size_t i, len, k;
-       struct ifconf conf;
-       struct if_nameindex *idx;
-
-       idx = malloc(n * (sizeof(struct if_nameindex)+sizeof(struct ifreq)));
-       if (!idx) return 0;
-
-       conf.ifc_buf = (void *)&idx[n];
-       conf.ifc_len = len = n * sizeof(struct ifreq);
-       if (ioctl(s, SIOCGIFCONF, &conf) < 0) {
-               free(idx);
-               return 0;
-       }
-       if (conf.ifc_len == len) {
-               free(idx);
-               return (void *)-1;
-       }
-
-       n = conf.ifc_len / sizeof(struct ifreq);
-       for (i=k=0; i<n; i++) {
-               if (ioctl(s, SIOCGIFINDEX, &conf.ifc_req[i]) < 0) {
-                       k++;
-                       continue;
-               }
-               idx[i-k].if_index = conf.ifc_req[i].ifr_ifindex;
-               idx[i-k].if_name = conf.ifc_req[i].ifr_name;
-       }
-       idx[i-k].if_name = 0;
-       idx[i-k].if_index = 0;
-
-       return idx;
-}
-
-struct if_nameindex *if_nameindex()
-{
-       size_t n;
-       void *p = 0;
-       int s = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC, 0);
-       if (s>=0) {
-               for (n=0; (p=do_nameindex(s, n)) == (void *)-1; n++);
-               __syscall(SYS_close, s);
-       }
-       errno = ENOBUFS;
-       return p;
-}
-- 
2.35.1

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/20220606032359.279538-1-jwkozaczuk%40gmail.com.

Reply via email to