]> www.infradead.org Git - users/dwmw2/openconnect.git/commitdiff
Accept multiple --resolve arguments
authorDavid Woodhouse <dwmw2@infradead.org>
Fri, 5 Apr 2024 16:08:40 +0000 (17:08 +0100)
committerDavid Woodhouse <dwmw2@infradead.org>
Tue, 7 Jan 2025 12:15:23 +0000 (12:15 +0000)
e.g. --resolve sockwrap:fd00:5357:5f02 --resolve sockwrap:127.0.0.2 to
try reaching the socket wrapper tests over both IPv6 and Legacy IP.

Signed-off-by: David Woodhouse <dwmw2@infradead.org>
main.c

diff --git a/main.c b/main.c
index 18d2901e2f70c1ab9fc5b96504f8b1bb4c15cfb5..33b0df7567b8e5aad5e4bc94eadef7d142f56d1b 100644 (file)
--- a/main.c
+++ b/main.c
@@ -910,23 +910,105 @@ static void print_default_vpncscript(void)
 
 static struct oc_vpn_option *gai_overrides;
 
+static struct addrinfo *gai_add_or_free(struct addrinfo *list, struct addrinfo *elem)
+{
+       struct addrinfo **lp = &list;
+
+       while (*lp) {
+               struct addrinfo *p = *lp;
+               if (p->ai_family == elem->ai_family &&
+                   p->ai_socktype == elem->ai_socktype &&
+                   p->ai_protocol == elem->ai_protocol &&
+                   p->ai_addrlen == elem->ai_addrlen &&
+                   !memcmp(p->ai_addr, elem->ai_addr, p->ai_addrlen)) {
+                       freeaddrinfo(elem);
+                       return list;
+               }
+               lp = &((*lp)->ai_next);
+       }
+       *lp = elem;
+       return list;
+}
+
+static struct addrinfo *gai_merge(struct addrinfo *list1, struct addrinfo *list2)
+{
+       while (list2) {
+               struct addrinfo *elem = list2;
+               list2 = elem->ai_next;
+               elem->ai_next = NULL;
+
+               list1 = gai_add_or_free(list1, elem);
+       }
+       return list1;
+}
+
 static int gai_override_cb(void *cbdata, const char *node,
-                           const char *service, const struct addrinfo *hints,
-                           struct addrinfo **res)
+                          const char *service, const struct addrinfo *hints,
+                          struct addrinfo **res)
 {
        struct openconnect_info *vpninfo = cbdata;
        struct oc_vpn_option *p = gai_overrides;
+       struct addrinfo *results = NULL;
+       int ret = 0;
 
        while (p) {
                if (!strcmp(node, p->option)) {
+                       struct addrinfo *this_res = NULL;
+                       int this_ret = 0;
+
                        vpn_progress(vpninfo, PRG_TRACE, _("Override hostname '%s' to '%s'\n"),
                                     node, p->value);
-                       node = p->value;
-                       break;
+
+                       this_ret = getaddrinfo(p->value, service, hints, &this_res);
+                       /*
+                        * Accumulate non-fatal results by precedence: If anything *works*,
+                        * return success. If anything returns EAI_ADDRFAMILY, return that.
+                        * Next EAI_NODATA, and finally return EAI_NONAME only if *every*
+                        * lookup returned that. Any other errors are fatal.
+                        */
+                       if (!this_ret) {
+                               /* As we process the list in reverse of the order they were
+                                * given on the command line, *prepend* results. */
+                               results = gai_merge(this_res, results);
+                               ret = 0;
+                       } else {
+#ifdef _WIN32
+                               char *errstr = openconnect__win32_strerror(this_ret);
+#else
+                               const char *errstr = gai_strerror(this_ret);
+#endif
+                               vpn_progress(vpninfo, PRG_DEBUG,
+                                            _("getaddrinfo failed for host '%s': %s\n"),
+                                            p->value, errstr);
+#ifdef _WIN32
+                               free(errstr);
+#endif
+
+#ifdef EAI_ADDRFAMILY /* Missing in MinGW */
+                               if (this_ret == EAI_ADDRFAMILY || ret == EAI_ADDRFAMILY) {
+                                       ret = EAI_ADDRFAMILY;
+                               } else
+#endif
+                               if (this_ret == EAI_NODATA || ret == EAI_NODATA) {
+                                       ret = EAI_NODATA;
+                               } else if (this_ret == EAI_NONAME || ret == EAI_NONAME) {
+                                       ret = EAI_NONAME;
+                               } else {
+                                       /* Fatal errors abort the lookup */
+                                       freeaddrinfo(results);
+                                       return this_ret;
+                               }
+                       }
                }
                p = p->next;
        }
 
+       /* Any override will set *either* 'results' on success, or 'ret' on failure. */
+       if (results || ret) {
+               *res = results;
+               return ret;
+       }
+
        return getaddrinfo(node, service, hints, res);
 }