summaryrefslogtreecommitdiff
blob: 484fddbd60322a9b98afe5d243e13ef9e89bab81 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
From 968dff4d576ca102525c81beddb36a623890424b Mon Sep 17 00:00:00 2001
From: Stephen Sinclair <radarsat1@gmail.com>
Date: Tue, 29 Aug 2017 14:32:24 -0300
Subject: [PATCH] Resolve hostname using getnameinfo for ipv6 support.

Iterates on interfaces, possibly searching for a pre-selected
interface, and resolves the hostname associated with non-localhost
addresses.

Fixes #56, fix compilation with --enable-ipv6.
---
 src/server.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++++++--------
 src/testlo.c |  7 ++++++
 2 files changed, 72 insertions(+), 9 deletions(-)

diff --git a/src/server.c b/src/server.c
index cf20495..4aff673 100644
--- a/src/server.c
+++ b/src/server.c
@@ -55,6 +55,10 @@
 #endif
 #include <sys/un.h>
 #include <arpa/inet.h>
+#include <netinet/in.h>
+#ifdef HAVE_GETIFADDRS
+#include <ifaddrs.h>
+#endif
 #endif
 
 #if defined(WIN32) || defined(_MSC_VER)
@@ -298,20 +302,72 @@ void lo_server_resolve_hostname(lo_server s)
     /* Set hostname to empty string */
     hostname[0] = '\0';
 
-#ifdef ENABLE_IPV6
+#if defined(ENABLE_IPV6) && defined(HAVE_GETIFADDRS)
     /* Try it the IPV6 friendly way first */
-    for (it = ai; it; it = it->ai_next) {
-        if (getnameinfo(it->ai_addr, it->ai_addrlen, hostname,
-                        sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0) {
+    do {
+        struct ifaddrs *ifa, *ifa_list;
+        if (getifaddrs(&ifa_list))
             break;
+        ifa = ifa_list;
+
+        while (ifa) {
+            if (!ifa->ifa_addr) {
+                ifa = ifa->ifa_next;
+                continue;
+            }
+
+            if (s->addr_if.iface) {
+                if (s->addr_if.size == sizeof(struct in_addr)
+                    && (ifa->ifa_addr->sa_family == AF_INET))
+                {
+                    struct sockaddr_in *sin = (struct sockaddr_in*)ifa->ifa_addr;
+                    if (memcmp(&sin->sin_addr, &s->addr_if.a.addr, sizeof(struct in_addr))!=0
+                        || (s->addr_if.iface && ifa->ifa_name
+                            && strcmp(s->addr_if.iface, ifa->ifa_name)!=0))
+                    {
+                        ifa = ifa->ifa_next;
+                        continue;
+                    }
+                }
+                else if (s->addr_if.size == sizeof(struct in6_addr)
+                         && (ifa->ifa_addr->sa_family == AF_INET6))
+                {
+                    struct sockaddr_in6 *sin = (struct sockaddr_in6*)ifa->ifa_addr;
+                    if (memcmp(&sin->sin6_addr, &s->addr_if.a.addr6,
+                               sizeof(struct in6_addr))!=0
+                        || (s->addr_if.iface && ifa->ifa_name
+                            && strcmp(s->addr_if.iface, ifa->ifa_name)!=0))
+                    {
+                        ifa = ifa->ifa_next;
+                        continue;
+                    }
+                }
+            }
+
+            if ((ifa->ifa_addr->sa_family == AF_INET
+                 && (!s->addr_if.iface || s->addr_if.size == sizeof(struct in_addr))
+                 && (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in), hostname,
+                                 sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0))
+                || (ifa->ifa_addr->sa_family == AF_INET6
+                    && (!s->addr_if.iface || s->addr_if.size == sizeof(struct in6_addr))
+                    && (getnameinfo(ifa->ifa_addr, sizeof(struct sockaddr_in6), hostname,
+                                    sizeof(hostname), NULL, 0, NI_NAMEREQD) == 0)))
+            {
+                /* check to make sure getnameinfo() didn't just set the hostname to "::".
+                   Needed on Darwin. */
+                if (hostname[0] == ':')
+                    hostname[0] = '\0';
+                else if (strcmp(hostname, "localhost")==0)
+                    hostname[0] = '\0';
+                else
+                    break;
+            }
+            ifa = ifa->ifa_next;
         }
-    }
 
-    /* check to make sure getnameinfo() didn't just set the hostname to "::".
-       Needed on Darwin. */
-    if (hostname[0] == ':') {
-        hostname[0] = '\0';
+        freeifaddrs(ifa_list);
     }
+    while (0);
 #endif
 
     /* Fallback to the oldschool (i.e. more reliable) way */
diff --git a/src/testlo.c b/src/testlo.c
index c128d10..c69570c 100644
--- a/src/testlo.c
+++ b/src/testlo.c
@@ -704,6 +704,13 @@ void test_multicast(lo_server_thread st)
 
     DOING("test_multicast");
 
+#ifdef ENABLE_IPV6
+    // Print a warning but we let it fail, prefer to actually fix IPv6
+    // support rather than just skip the test!
+    printf("WARNING: Compiled with --enable-ipv6, multicast not supported;"
+           "failure expected.\n");
+#endif
+
     /* test multicast server and sender */
     /* message is sent from st otherwise reply doesn't work */
     ms = lo_server_new_multicast("224.0.1.1", "15432", error);
-- 
2.14.1