The combination of gethostname and getnameinfo does not seem to work very
well to find an IP address for a system that doesn't seem have a host
name, or for one that has IPv6 configured in the kernel without actually
using it.

Switch to a simple loop over getifaddrs which works reliably everywhere.

Signed-off-by: Christoph Hellwig <[email protected]>

diff --git a/lib/net.c b/lib/net.c
index db952dd..bebc108 100644
--- a/lib/net.c
+++ b/lib/net.c
@@ -16,6 +16,8 @@
 #include <string.h>
 #include <unistd.h>
 #include <arpa/inet.h>
+#include <ifaddrs.h>
+#include <net/if.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
 #include <sys/epoll.h>
@@ -443,54 +445,43 @@ int set_timeout(int fd)
 
 int get_local_addr(uint8_t *bytes)
 {
-       int ret;
-       char name[INET6_ADDRSTRLEN];
-       struct addrinfo hints, *res, *res0;
-
-       gethostname(name, sizeof(name));
+       struct ifaddrs *ifaddr, *ifa;
+       int ret = 0;
 
-       memset(&hints, 0, sizeof(hints));
+       if (getifaddrs(&ifaddr) == -1) {
+               eprintf("getifaddrs failed: %m\n");
+               return -1;
+       }
 
-       hints.ai_family = AF_INET;
-       hints.ai_socktype = SOCK_STREAM;
-       ret = getaddrinfo(name, NULL, &hints, &res0);
-       if (ret)
-               exit(1);
 
-       for (res = res0; res; res = res->ai_next) {
-               if (res->ai_family == AF_INET) {
-                       struct sockaddr_in *addr;
-                       addr = (struct sockaddr_in *)res->ai_addr;
+       for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) {
+               struct sockaddr_in *sin;
+               struct sockaddr_in6 *sin6;
 
-                       if (((char *) &addr->sin_addr)[0] == 127)
-                               continue;
+               if (ifa->ifa_flags & IFF_LOOPBACK)
+                       continue;
+               if (!ifa->ifa_addr)
+                       continue;
 
+               switch (ifa->ifa_addr->sa_family) {
+               case AF_INET:
+                       sin = (struct sockaddr_in *)ifa->ifa_addr;
                        memset(bytes, 0, 12);
-                       memcpy(bytes + 12, &addr->sin_addr, 4);
-                       break;
-               } else if (res->ai_family == AF_INET6) {
-                       struct sockaddr_in6 *addr;
-                       uint8_t localhost[16] = { 0, 0, 0, 0, 0, 0, 0, 0,
-                                                 0, 0, 0, 0, 0, 0, 0, 1 };
-
-                       addr = (struct sockaddr_in6 *)res->ai_addr;
-
-                       if (memcmp(&addr->sin6_addr, localhost, 16) == 0)
-                               continue;
-
-                       memcpy(bytes, &addr->sin6_addr, 16);
-                       break;
-               } else
-                       dprintf("unknown address family\n");
-       }
-
-       if (res == NULL) {
-               eprintf("failed to get address info\n");
-               return -1;
+                       memcpy(bytes + 12, &sin->sin_addr, 4);
+                       memcpy(bytes + 12, &sin->sin_addr, 4);
+                       eprintf("found IPv4 address\n");
+                       goto out;
+               case AF_INET6:
+                       sin6 = (struct sockaddr_in6 *)ifa->ifa_addr;
+                       memcpy(bytes, &sin6->sin6_addr, 16);
+                       eprintf("found IPv6 address\n");
+                       goto out;
+               }
        }
 
-       freeaddrinfo(res0);
-
-       return 0;
+       eprintf("no valid interface found\n");
+       ret = -1;
+out:
+       freeifaddrs(ifaddr);
+       return ret;
 }
-
-- 
sheepdog mailing list
[email protected]
http://lists.wpkg.org/mailman/listinfo/sheepdog

Reply via email to