[Openvpn-devel] [XL] Change in openvpn[master]: Factor out address resolve code to a new file resolve.c

"flichtenheld \(Code Review\) via Openvpn-devel" <[email protected]>
Newsgroups net.sourceforge.lists.openvpn-devel
Message-ID <[email protected]>
Attention is currently required from: plaisthos.

Hello plaisthos,

I'd like you to do a code review.
Please visit

    http://gerrit.openvpn.net/c/openvpn/+/1846?usp=email

to review the following change.


Change subject: Factor out address resolve code to a new file resolve.c
......................................................................

Factor out address resolve code to a new file resolve.c

The code was weirdly split between socket.c, socket_util.c,
and options.c. The new structure makes more sense.

While here move some related string helper code to buffer.h.

Change-Id: I12bef330e2c8a5e5b21c2fa807584319b2b7101f
Signed-off-by: Frank Lichtenheld <[email protected]>
---
M CMakeLists.txt
M src/openvpn/Makefile.am
M src/openvpn/buffer.c
M src/openvpn/buffer.h
M src/openvpn/clinat.c
M src/openvpn/dns.c
M src/openvpn/init.c
M src/openvpn/manage.c
M src/openvpn/options.c
M src/openvpn/options.h
M src/openvpn/pool.c
M src/openvpn/ps.c
M src/openvpn/push.c
A src/openvpn/resolve.c
A src/openvpn/resolve.h
M src/openvpn/route.c
M src/openvpn/socket.c
M src/openvpn/socket.h
M src/openvpn/socket_util.c
M src/openvpn/socket_util.h
M src/openvpn/tun.c
21 files changed, 815 insertions(+), 707 deletions(-)



  git pull ssh://gerrit.openvpn.net:29418/openvpn refs/changes/46/1846/1

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6c66ebd..52728f1 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -565,6 +565,8 @@
     src/openvpn/reflect_filter.h
     src/openvpn/reliable.c
     src/openvpn/reliable.h
+    src/openvpn/resolve.c
+    src/openvpn/resolve.h
     src/openvpn/route.c
     src/openvpn/route.h
     src/openvpn/run_command.c
diff --git a/src/openvpn/Makefile.am b/src/openvpn/Makefile.am
index 182d732..ad46ed0 100644
--- a/src/openvpn/Makefile.am
+++ b/src/openvpn/Makefile.am
@@ -125,6 +125,7 @@
 	pushlist.h \
 	reflect_filter.c reflect_filter.h \
 	reliable.c reliable.h \
+	resolve.c resolve.h \
 	route.c route.h \
 	run_command.c run_command.h \
 	schedule.c schedule.h \
diff --git a/src/openvpn/buffer.c b/src/openvpn/buffer.c
index a004b60..ae290ca 100644
--- a/src/openvpn/buffer.c
+++ b/src/openvpn/buffer.c
@@ -1098,6 +1098,23 @@
     }
 }
 
+bool
+streqnull(const char *a, const char *b)
+{
+    if (a == NULL && b == NULL)
+    {
+        return true;
+    }
+    else if (a == NULL || b == NULL)
+    {
+        return false;
+    }
+    else
+    {
+        return streq(a, b);
+    }
+}
+
 char *
 string_substitute(const char *src, char from, char to, struct gc_arena *gc)
 {
diff --git a/src/openvpn/buffer.h b/src/openvpn/buffer.h
index ab8c239..fb2cd85 100644
--- a/src/openvpn/buffer.h
+++ b/src/openvpn/buffer.h
@@ -1766,6 +1766,18 @@
     return 0 == strncmp(str, prefix, strlen(prefix));
 }
 
+/** helper to work around the semantics of the strcmp() return value
+ * @return true if the strings are equal according to strcmp()
+ */
+#define streq(x, y) (!strcmp((x), (y)))
+
+/** compare two strings which might be NULL
+ * @return true if both strings are NULL, or if they are equal according to strcmp()
+ */
+bool streqnull(const char *a, const char *b);
+/** compare two strings which might be NULL, but NULL is never equal
+ * @return true if neither string is NULL and they are equal according to strcmp()
+ */
 bool string_defined_equal(const char *s1, const char *s2);
 char *string_substitute(const char *src, char from, char to, struct gc_arena *gc);
 
diff --git a/src/openvpn/clinat.c b/src/openvpn/clinat.c
index b465950..595566a 100644
--- a/src/openvpn/clinat.c
+++ b/src/openvpn/clinat.c
@@ -30,6 +30,7 @@
 #include "proto.h"
 #include "socket_util.h"
 #include "memdbg.h"
+#include "resolve.h"
 
 static bool
 add_entry(struct client_nat_option_list *dest, const struct client_nat_entry *e)
diff --git a/src/openvpn/dns.c b/src/openvpn/dns.c
index 7f4dde4..a40f3e7 100644
--- a/src/openvpn/dns.c
+++ b/src/openvpn/dns.c
@@ -27,7 +27,7 @@
 #include "syshead.h"
 
 #include "dns.h"
-#include "socket_util.h"
+#include "resolve.h"
 #include "options.h"
 #include "run_command.h"
 #include "domain_helper.h"
diff --git a/src/openvpn/init.c b/src/openvpn/init.c
index 38db7fa..223c245 100644
--- a/src/openvpn/init.c
+++ b/src/openvpn/init.c
@@ -55,6 +55,7 @@
 #include "tun_afunix.h"
 #include "schedule.h"
 #include "options_string.h"
+#include "resolve.h"
 
 #include "memdbg.h"
 
diff --git a/src/openvpn/manage.c b/src/openvpn/manage.c
index 17abfd8..857e320 100644
--- a/src/openvpn/manage.c
+++ b/src/openvpn/manage.c
@@ -44,6 +44,7 @@
 #include "dco.h"
 #include "push.h"
 #include "multi.h"
+#include "resolve.h"
 
 #include "memdbg.h"
 
diff --git a/src/openvpn/options.c b/src/openvpn/options.c
index 74b1f25..4595266 100644
--- a/src/openvpn/options.c
+++ b/src/openvpn/options.c
@@ -64,6 +64,7 @@
 #include "domain_helper.h"
 #include "mbuf.h"
 #include "check_file_access.h"
+#include "resolve.h"
 
 #include <ctype.h>
 
@@ -1055,26 +1056,6 @@
 
 #endif /* ifndef _WIN32 */
 
-static in_addr_t
-get_ip_addr(const char *ip_string, msglvl_t msglevel, bool *error)
-{
-    unsigned int flags = GETADDR_HOST_ORDER;
-    bool succeeded = false;
-    in_addr_t ret;
-
-    if (msglevel & M_FATAL)
-    {
-        flags |= GETADDR_FATAL;
-    }
-
-    ret = getaddr(flags, ip_string, 0, &succeeded, NULL);
-    if (!succeeded && error)
-    {
-        *error = true;
-    }
-    return ret;
-}
-
 /**
  * Returns newly allocated string containing address part without "/nn".
  *
@@ -1097,13 +1078,6 @@
     }
     return ret;
 }
-
-static bool
-ipv6_addr_safe_hexplusbits(const char *ipv6_prefix_spec)
-{
-    return get_ipv6_addr(ipv6_prefix_spec, NULL, NULL, M_WARN);
-}
-
 /**
  * Parses a hexstring and checks if the string has the correct length. Return
  * a verify_hash_list containing the parsed hash string.
@@ -3337,7 +3311,7 @@
     options_postprocess_verify(options);
 #ifndef ENABLE_SMALL
     options_postprocess_filechecks(options);
-#endif /* !ENABLE_SMALL */
+#endif
 }
 
 /*
diff --git a/src/openvpn/options.h b/src/openvpn/options.h
index c23d0b3..2b68a0e 100644
--- a/src/openvpn/options.h
+++ b/src/openvpn/options.h
@@ -723,8 +723,6 @@
     unsigned int imported_protocol_flags;
 };
 
-#define streq(x, y) (!strcmp((x), (y)))
-
 /*
  * Option classes.
  */
diff --git a/src/openvpn/pool.c b/src/openvpn/pool.c
index 80dec6c..33ff72b 100644
--- a/src/openvpn/pool.c
+++ b/src/openvpn/pool.c
@@ -31,6 +31,7 @@
 #include "error.h"
 #include "socket_util.h"
 #include "otime.h"
+#include "resolve.h"
 
 #include "memdbg.h"
 
diff --git a/src/openvpn/ps.c b/src/openvpn/ps.c
index 0e581e5..5b705ee 100644
--- a/src/openvpn/ps.c
+++ b/src/openvpn/ps.c
@@ -32,6 +32,7 @@
 #include "socket.h"
 #include "fdmisc.h"
 #include "crypto.h"
+#include "resolve.h"
 #include "ps.h"
 
 #include "memdbg.h"
diff --git a/src/openvpn/push.c b/src/openvpn/push.c
index c2c1914..3005a2d 100644
--- a/src/openvpn/push.c
+++ b/src/openvpn/push.c
@@ -37,6 +37,7 @@
 #include "memdbg.h"
 #include "ssl_util.h"
 #include "options_util.h"
+#include "resolve.h"
 
 /*
  * Auth username/password
diff --git a/src/openvpn/resolve.c b/src/openvpn/resolve.c
new file mode 100644
index 0000000..b8d9899
--- /dev/null
+++ b/src/openvpn/resolve.c
@@ -0,0 +1,665 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2026 OpenVPN Inc <[email protected]>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "syshead.h"
+
+#include "buffer.h"
+#include "crypto.h"
+#include "manage.h"
+#include "openvpn.h"
+#include "socket.h"
+#include "socket_util.h"
+
+#include "resolve.h"
+
+/*
+ * Convert sockflags/getaddr_flags into getaddr_flags
+ */
+unsigned int
+sf2gaf(const unsigned int getaddr_flags, const unsigned int sockflags)
+{
+    if (sockflags & SF_HOST_RANDOMIZE)
+    {
+        return getaddr_flags | GETADDR_RANDOMIZE;
+    }
+    else
+    {
+        return getaddr_flags;
+    }
+}
+
+/*
+ * Functions related to the translation of DNS names to IP addresses.
+ */
+
+/**
+ * Small helper function for openvpn_getaddrinfo to print the address
+ * family when resolving fails
+ */
+static const char *
+getaddrinfo_addr_family_name(int af)
+{
+    switch (af)
+    {
+        case AF_INET:
+            return "[AF_INET]";
+
+        case AF_INET6:
+            return "[AF_INET6]";
+    }
+    return "";
+}
+
+/*
+ * Prepend a random string to hostname to prevent DNS caching.
+ * For example, foo.bar.gov would be modified to <random-chars>.foo.bar.gov.
+ * Of course, this requires explicit support in the DNS server (wildcard).
+ */
+static const char *
+hostname_randomize(const char *hostname, struct gc_arena *gc)
+{
+#define n_rnd_bytes 6
+
+    uint8_t rnd_bytes[n_rnd_bytes];
+    const char *rnd_str;
+    struct buffer hname = alloc_buf_gc(strlen(hostname) + sizeof(rnd_bytes) * 2 + 4, gc);
+
+    prng_bytes(rnd_bytes, sizeof(rnd_bytes));
+    rnd_str = format_hex_ex(rnd_bytes, sizeof(rnd_bytes), 40, 0, NULL, gc);
+    buf_printf(&hname, "%s.%s", rnd_str, hostname);
+    return BSTR(&hname);
+#undef n_rnd_bytes
+}
+
+/*
+ * Translate IPv4/IPv6 addr or hostname into struct addrinfo
+ * If resolve error, try again for resolve_retry_seconds seconds.
+ */
+int
+openvpn_getaddrinfo(unsigned int flags, const char *hostname, const char *servname,
+                    int resolve_retry_seconds, struct signal_info *sig_info, int ai_family,
+                    struct addrinfo **res)
+{
+    struct addrinfo hints;
+    int status;
+    struct signal_info sigrec = { 0 };
+    msglvl_t msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
+    struct gc_arena gc = gc_new();
+    const char *print_hostname;
+    const char *print_servname;
+
+    ASSERT(res);
+
+    ASSERT(hostname || servname);
+    ASSERT(!(flags & GETADDR_HOST_ORDER));
+
+    if (servname)
+    {
+        print_servname = servname;
+    }
+    else
+    {
+        print_servname = "";
+    }
+
+    if (flags & GETADDR_MSG_VIRT_OUT)
+    {
+        msglevel |= M_MSG_VIRT_OUT;
+    }
+
+    if ((flags & (GETADDR_FATAL_ON_SIGNAL | GETADDR_WARN_ON_SIGNAL)) && !sig_info)
+    {
+        sig_info = &sigrec;
+    }
+
+    /* try numeric ip addr first */
+    CLEAR(hints);
+    hints.ai_flags = AI_NUMERICHOST;
+
+    if (flags & GETADDR_PASSIVE)
+    {
+        hints.ai_flags |= AI_PASSIVE;
+    }
+
+    if (flags & GETADDR_DATAGRAM)
+    {
+        hints.ai_socktype = SOCK_DGRAM;
+    }
+    else
+    {
+        hints.ai_socktype = SOCK_STREAM;
+    }
+
+    /* if hostname is not set, we want to bind to 'ANY', with
+     * the correct address family - v4-only or v6/v6-dual-stack */
+    if (!hostname)
+    {
+        hints.ai_family = ai_family;
+    }
+
+    status = getaddrinfo(hostname, servname, &hints, res);
+
+    if (status != 0)                      /* parse as numeric address failed? */
+    {
+        const int fail_wait_interval = 5; /* seconds */
+        /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */
+        int resolve_retries =
+            (flags & GETADDR_TRY_ONCE) ? 1 : ((resolve_retry_seconds + 4) / fail_wait_interval);
+        const char *fmt;
+        msglvl_t level = 0;
+
+        /* this is not a numeric IP, therefore force resolution using the
+         * provided ai_family */
+        hints.ai_family = ai_family;
+
+        if (hostname && (flags & GETADDR_RANDOMIZE))
+        {
+            hostname = hostname_randomize(hostname, &gc);
+        }
+
+        if (hostname)
+        {
+            print_hostname = hostname;
+        }
+        else
+        {
+            print_hostname = "undefined";
+        }
+
+        fmt = "RESOLVE: Cannot resolve host address: %s:%s%s (%s)";
+        if ((flags & GETADDR_MENTION_RESOLVE_RETRY) && !resolve_retry_seconds)
+        {
+            fmt = "RESOLVE: Cannot resolve host address: %s:%s%s (%s)"
+                  "(I would have retried this name query if you had "
+                  "specified the --resolv-retry option.)";
+        }
+
+        if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
+        {
+            msg(msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)", print_hostname,
+                print_servname, gai_strerror(status));
+            goto done;
+        }
+
+#ifdef ENABLE_MANAGEMENT
+        if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
+        {
+            if (management)
+            {
+                management_set_state(management, OPENVPN_STATE_RESOLVE, NULL, NULL, NULL, NULL,
+                                     NULL);
+            }
+        }
+#endif
+
+        /*
+         * Resolve hostname
+         */
+        while (true)
+        {
+#ifndef _WIN32
+            /* force resolv.conf reload */
+            res_init();
+#endif
+            /* try hostname lookup */
+            hints.ai_flags &= ~AI_NUMERICHOST;
+            dmsg(D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", flags,
+                 hints.ai_family, hints.ai_socktype);
+            status = getaddrinfo(hostname, servname, &hints, res);
+
+            if (sig_info)
+            {
+                get_signal(&sig_info->signal_received);
+                if (sig_info->signal_received) /* were we interrupted by a signal? */
+                {
+                    /* why are we overwriting SIGUSR1 ? */
+                    if (signal_reset(sig_info, SIGUSR1) == SIGUSR1) /* ignore SIGUSR1 */
+                    {
+                        msg(level, "RESOLVE: Ignored SIGUSR1 signal received during "
+                                   "DNS resolution attempt");
+                    }
+                    else
+                    {
+                        /* turn success into failure (interrupted syscall) */
+                        if (0 == status)
+                        {
+                            ASSERT(res);
+                            freeaddrinfo(*res);
+                            *res = NULL;
+                            status = EAI_AGAIN; /* = temporary failure */
+                            errno = EINTR;
+                        }
+                        goto done;
+                    }
+                }
+            }
+
+            /* success? */
+            if (0 == status)
+            {
+                break;
+            }
+
+            /* resolve lookup failed, should we
+             * continue or fail? */
+            level = msglevel;
+            if (resolve_retries > 0)
+            {
+                level = D_RESOLVE_ERRORS;
+            }
+
+            msg(level, fmt, print_hostname, print_servname, getaddrinfo_addr_family_name(ai_family),
+                gai_strerror(status));
+
+            if (--resolve_retries <= 0)
+            {
+                goto done;
+            }
+
+            management_sleep(fail_wait_interval);
+        }
+
+        ASSERT(res);
+
+        /* hostname resolve succeeded */
+
+        /*
+         * Do not choose an IP Addresse by random or change the order *
+         * of IP addresses, doing so will break RFC 3484 address selection *
+         */
+    }
+    else
+    {
+        /* IP address parse succeeded */
+        if (flags & GETADDR_RANDOMIZE)
+        {
+            msg(M_WARN, "WARNING: ignoring --remote-random-hostname because the "
+                        "hostname is an IP address");
+        }
+    }
+
+done:
+    if (sig_info && sig_info->signal_received)
+    {
+        msglvl_t level = 0;
+        if (flags & GETADDR_FATAL_ON_SIGNAL)
+        {
+            level = M_FATAL;
+        }
+        else if (flags & GETADDR_WARN_ON_SIGNAL)
+        {
+            level = M_WARN;
+        }
+        msg(level, "RESOLVE: signal received during DNS resolution attempt");
+    }
+
+    gc_free(&gc);
+    return status;
+}
+
+static int
+get_addr_generic(sa_family_t af, unsigned int flags, const char *hostname, void *network,
+                 unsigned int *netbits, int resolve_retry_seconds, struct signal_info *sig_info,
+                 msglvl_t msglevel)
+{
+    char *endp, *sep, *var_host = NULL;
+    struct addrinfo *ai = NULL;
+    unsigned long bits;
+    uint8_t max_bits;
+    int ret = -1;
+
+    if (!hostname)
+    {
+        msg(M_NONFATAL, "Can't resolve null hostname!");
+        goto out;
+    }
+
+    /* assign family specific default values */
+    switch (af)
+    {
+        case AF_INET:
+            bits = 0;
+            max_bits = sizeof(in_addr_t) * 8;
+            break;
+
+        case AF_INET6:
+            bits = 64;
+            max_bits = sizeof(struct in6_addr) * 8;
+            break;
+
+        default:
+            msg(M_WARN, "Unsupported AF family passed to getaddrinfo for %s (%d)", hostname, af);
+            goto out;
+    }
+
+    /* we need to modify the hostname received as input, but we don't want to
+     * touch it directly as it might be a constant string.
+     *
+     * Therefore, we clone the string here and free it at the end of the
+     * function */
+    var_host = strdup(hostname);
+    if (!var_host)
+    {
+        msg(M_NONFATAL | M_ERRNO, "Can't allocate hostname buffer for getaddrinfo");
+        goto out;
+    }
+
+    /* check if this hostname has a /bits suffix */
+    sep = strchr(var_host, '/');
+    if (sep)
+    {
+        bits = strtoul(sep + 1, &endp, 10);
+        if ((*endp != '\0') || (bits > max_bits))
+        {
+            msg(msglevel, "IP prefix '%s': invalid '/bits' spec (%s)", hostname, sep + 1);
+            goto out;
+        }
+        *sep = '\0';
+    }
+
+    ret = openvpn_getaddrinfo(flags & ~GETADDR_HOST_ORDER, var_host, NULL, resolve_retry_seconds,
+                              sig_info, af, &ai);
+    if ((ret == 0) && network)
+    {
+        struct in6_addr *ip6;
+        in_addr_t *ip4;
+
+        if (af != ai->ai_family)
+        {
+            msg(msglevel, "Can't parse %s as IPv%d address", var_host, (af == AF_INET) ? 4 : 6);
+            ret = -1;
+            goto out;
+        }
+
+        switch (af)
+        {
+            case AF_INET:
+                ip4 = network;
+                *ip4 = ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr;
+
+                if (flags & GETADDR_HOST_ORDER)
+                {
+                    *ip4 = ntohl(*ip4);
+                }
+                break;
+
+            case AF_INET6:
+                ip6 = network;
+                *ip6 = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
+                break;
+
+            default:
+                /* can't get here because 'af' was previously checked */
+                msg(M_WARN, "Unsupported AF family for %s (%d)", var_host, af);
+                goto out;
+        }
+    }
+
+    if (netbits)
+    {
+        *netbits = (unsigned int)bits;
+    }
+
+    /* restore '/' separator, if any */
+    if (sep)
+    {
+        *sep = '/';
+    }
+out:
+    if (ai)
+    {
+        freeaddrinfo(ai);
+    }
+    free(var_host);
+
+    return ret;
+}
+
+in_addr_t
+getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds, bool *succeeded,
+        struct signal_info *sig_info)
+{
+    in_addr_t addr = { 0 };
+    int status;
+
+    status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL, resolve_retry_seconds,
+                              sig_info, M_WARN);
+    if (status == 0)
+    {
+        if (succeeded)
+        {
+            *succeeded = true;
+        }
+        return addr;
+    }
+    else
+    {
+        if (succeeded)
+        {
+            *succeeded = false;
+        }
+        return 0;
+    }
+}
+
+in_addr_t
+get_ip_addr(const char *ip_string, msglvl_t msglevel, bool *error)
+{
+    unsigned int flags = GETADDR_HOST_ORDER;
+    bool succeeded = false;
+    in_addr_t ret;
+
+    if (msglevel & M_FATAL)
+    {
+        flags |= GETADDR_FATAL;
+    }
+
+    ret = getaddr(flags, ip_string, 0, &succeeded, NULL);
+    if (!succeeded && error)
+    {
+        *error = true;
+    }
+    return ret;
+}
+
+bool
+get_ipv6_addr(const char *hostname, struct in6_addr *network, unsigned int *netbits,
+              msglvl_t msglevel)
+{
+    if (get_addr_generic(AF_INET6, GETADDR_RESOLVE, hostname, network, netbits, 0, NULL, msglevel)
+        < 0)
+    {
+        return false;
+    }
+
+    return true; /* parsing OK, values set */
+}
+
+/*
+ * get_cached_dns_entry return 0 on success and -1
+ * otherwise. (like getaddrinfo)
+ */
+int
+get_cached_dns_entry(struct cached_dns_entry *dns_cache, const char *hostname, const char *servname,
+                     int ai_family, unsigned int resolve_flags, struct addrinfo **ai)
+{
+    struct cached_dns_entry *ph;
+    unsigned int flags;
+
+    /* Only use flags that are relevant for the structure */
+    flags = resolve_flags & GETADDR_CACHE_MASK;
+
+    for (ph = dns_cache; ph; ph = ph->next)
+    {
+        if (streqnull(ph->hostname, hostname) && streqnull(ph->servname, servname)
+            && ph->ai_family == ai_family && ph->flags == flags)
+        {
+            *ai = ph->ai;
+            return 0;
+        }
+    }
+    return -1;
+}
+
+
+static int
+do_preresolve_host(struct context *c, const char *hostname, const char *servname, const int af,
+                   const unsigned int flags)
+{
+    struct addrinfo *ai;
+    int status;
+
+    if (get_cached_dns_entry(c->c1.dns_cache, hostname, servname, af, flags, &ai) == 0)
+    {
+        /* entry already cached, return success */
+        return 0;
+    }
+
+    status = openvpn_getaddrinfo(flags, hostname, servname, c->options.resolve_retry_seconds, NULL,
+                                 af, &ai);
+    if (status == 0)
+    {
+        struct cached_dns_entry *ph;
+
+        ALLOC_OBJ_CLEAR_GC(ph, struct cached_dns_entry, &c->gc);
+        ph->ai = ai;
+        ph->hostname = hostname;
+        ph->servname = servname;
+        ph->flags = flags & GETADDR_CACHE_MASK;
+
+        if (!c->c1.dns_cache)
+        {
+            c->c1.dns_cache = ph;
+        }
+        else
+        {
+            struct cached_dns_entry *prev = c->c1.dns_cache;
+            while (prev->next)
+            {
+                prev = prev->next;
+            }
+            prev->next = ph;
+        }
+
+        gc_addspecial(ai, &gc_freeaddrinfo_callback, &c->gc);
+    }
+    return status;
+}
+
+void
+do_preresolve(struct context *c)
+{
+    struct connection_list *l = c->options.connection_list;
+    const unsigned int preresolve_flags = GETADDR_RESOLVE | GETADDR_UPDATE_MANAGEMENT_STATE
+                                          | GETADDR_MENTION_RESOLVE_RETRY | GETADDR_FATAL;
+
+
+    for (int i = 0; i < l->len; ++i)
+    {
+        int status;
+        const char *remote;
+        unsigned int flags = preresolve_flags;
+
+        struct connection_entry *ce = l->array[i];
+
+        if (proto_is_dgram(ce->proto))
+        {
+            flags |= GETADDR_DATAGRAM;
+        }
+
+        if (c->options.sockflags & SF_HOST_RANDOMIZE)
+        {
+            flags |= GETADDR_RANDOMIZE;
+        }
+
+        if (c->options.ip_remote_hint)
+        {
+            remote = c->options.ip_remote_hint;
+        }
+        else
+        {
+            remote = ce->remote;
+        }
+
+        /* HTTP remote hostname does not need to be resolved */
+        if (!ce->http_proxy_options)
+        {
+            status = do_preresolve_host(c, remote, ce->remote_port, ce->af, flags);
+            if (status != 0)
+            {
+                goto err;
+            }
+        }
+
+        /* Preresolve proxy */
+        if (ce->http_proxy_options)
+        {
+            status = do_preresolve_host(c, ce->http_proxy_options->server,
+                                        ce->http_proxy_options->port, ce->af, preresolve_flags);
+
+            if (status != 0)
+            {
+                goto err;
+            }
+        }
+
+        if (ce->socks_proxy_server)
+        {
+            status =
+                do_preresolve_host(c, ce->socks_proxy_server, ce->socks_proxy_port, ce->af, flags);
+            if (status != 0)
+            {
+                goto err;
+            }
+        }
+
+        if (ce->bind_local)
+        {
+            flags |= GETADDR_PASSIVE;
+            flags &= ~GETADDR_RANDOMIZE;
+
+            for (int j = 0; j < ce->local_list->len; j++)
+            {
+                const struct local_entry *le = ce->local_list->array[j];
+
+                if (!le->local)
+                {
+                    continue;
+                }
+
+                status = do_preresolve_host(c, le->local, le->port, ce->af, flags);
+                if (status != 0)
+                {
+                    goto err;
+                }
+            }
+        }
+    }
+    return;
+
+err:
+    throw_signal_soft(SIGHUP, "Preresolving failed");
+}
diff --git a/src/openvpn/resolve.h b/src/openvpn/resolve.h
new file mode 100644
index 0000000..9069af7
--- /dev/null
+++ b/src/openvpn/resolve.h
@@ -0,0 +1,106 @@
+/*
+ *  OpenVPN -- An application to securely tunnel IP networks
+ *             over a single TCP/UDP port, with support for SSL/TLS-based
+ *             session authentication and key exchange,
+ *             packet encryption, packet authentication, and
+ *             packet compression.
+ *
+ *  Copyright (C) 2002-2026 OpenVPN Inc <[email protected]>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2
+ *  as published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, see <https://www.gnu.org/licenses/>.
+ */
+
+/**
+ * @file
+ * DNS resolution
+ */
+#ifndef RESOLVE_H
+#define RESOLVE_H
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "syshead.h"
+
+#include "sig.h"
+
+#define GETADDR_RESOLVE                 (1u << 0)
+#define GETADDR_FATAL                   (1u << 1)
+#define GETADDR_HOST_ORDER              (1u << 2)
+#define GETADDR_MENTION_RESOLVE_RETRY   (1u << 3)
+#define GETADDR_FATAL_ON_SIGNAL         (1u << 4)
+#define GETADDR_WARN_ON_SIGNAL          (1u << 5)
+#define GETADDR_MSG_VIRT_OUT            (1u << 6)
+#define GETADDR_TRY_ONCE                (1u << 7)
+#define GETADDR_UPDATE_MANAGEMENT_STATE (1u << 8)
+#define GETADDR_RANDOMIZE               (1u << 9)
+#define GETADDR_PASSIVE                 (1u << 10)
+#define GETADDR_DATAGRAM                (1u << 11)
+
+#define GETADDR_CACHE_MASK (GETADDR_DATAGRAM | GETADDR_PASSIVE)
+
+/**
+ * Convert sockflags/getaddr_flags into getaddr_flags
+ */
+unsigned int sf2gaf(const unsigned int getaddr_flags, const unsigned int sockflags);
+
+/**
+ * Translate an IPv4 addr or hostname from string form to in_addr_t
+ *
+ * In case of resolve error, it will try again for
+ * resolve_retry_seconds seconds.
+ */
+in_addr_t getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds,
+                  bool *succeeded, struct signal_info *sig_info);
+
+in_addr_t get_ip_addr(const char *ip_string, msglvl_t msglevel, bool *error);
+
+/**
+ * Translate an IPv6 addr or hostname from string form to in6_addr
+ */
+bool get_ipv6_addr(const char *hostname, struct in6_addr *network, unsigned int *netbits,
+                   msglvl_t msglevel);
+
+static inline bool
+ipv6_addr_safe_hexplusbits(const char *ipv6_prefix_spec)
+{
+    return get_ipv6_addr(ipv6_prefix_spec, NULL, NULL, M_WARN);
+}
+
+int openvpn_getaddrinfo(unsigned int flags, const char *hostname, const char *servname,
+                        int resolve_retry_seconds, struct signal_info *sig_info, int ai_family,
+                        struct addrinfo **res);
+
+void do_preresolve(struct context *c);
+
+/* struct to hold preresolved host names */
+struct cached_dns_entry
+{
+    const char *hostname;
+    const char *servname;
+    int ai_family;
+    unsigned int flags;
+    struct addrinfo *ai;
+    struct cached_dns_entry *next;
+};
+
+/**
+ * get_cached_dns_entry return 0 on success and -1
+ * otherwise. (like getaddrinfo())
+ */
+int get_cached_dns_entry(struct cached_dns_entry *dns_cache, const char *hostname,
+                         const char *servname, int ai_family,
+                         unsigned int resolve_flags, struct addrinfo **ai);
+
+#endif /* RESOLVE_H */
diff --git a/src/openvpn/route.c b/src/openvpn/route.c
index 078bb7e..5d70472 100644
--- a/src/openvpn/route.c
+++ b/src/openvpn/route.c
@@ -42,6 +42,7 @@
 #include "options.h"
 #include "networking.h"
 #include "integer.h"
+#include "resolve.h"
 
 #include "memdbg.h"
 
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c
index 6684350..663a2b4 100644
--- a/src/openvpn/socket.c
+++ b/src/openvpn/socket.c
@@ -38,6 +38,7 @@
 #include "manage.h"
 #include "openvpn.h"
 #include "forward.h"
+#include "resolve.h"
 
 #include "memdbg.h"
 
@@ -54,366 +55,6 @@
     return false;
 }
 
-/*
- * Convert sockflags/getaddr_flags into getaddr_flags
- */
-static unsigned int
-sf2gaf(const unsigned int getaddr_flags, const unsigned int sockflags)
-{
-    if (sockflags & SF_HOST_RANDOMIZE)
-    {
-        return getaddr_flags | GETADDR_RANDOMIZE;
-    }
-    else
-    {
-        return getaddr_flags;
-    }
-}
-
-/*
- * Functions related to the translation of DNS names to IP addresses.
- */
-static int
-get_addr_generic(sa_family_t af, unsigned int flags, const char *hostname, void *network,
-                 unsigned int *netbits, int resolve_retry_seconds, struct signal_info *sig_info,
-                 msglvl_t msglevel)
-{
-    char *endp, *sep, *var_host = NULL;
-    struct addrinfo *ai = NULL;
-    unsigned long bits;
-    uint8_t max_bits;
-    int ret = -1;
-
-    if (!hostname)
-    {
-        msg(M_NONFATAL, "Can't resolve null hostname!");
-        goto out;
-    }
-
-    /* assign family specific default values */
-    switch (af)
-    {
-        case AF_INET:
-            bits = 0;
-            max_bits = sizeof(in_addr_t) * 8;
-            break;
-
-        case AF_INET6:
-            bits = 64;
-            max_bits = sizeof(struct in6_addr) * 8;
-            break;
-
-        default:
-            msg(M_WARN, "Unsupported AF family passed to getaddrinfo for %s (%d)", hostname, af);
-            goto out;
-    }
-
-    /* we need to modify the hostname received as input, but we don't want to
-     * touch it directly as it might be a constant string.
-     *
-     * Therefore, we clone the string here and free it at the end of the
-     * function */
-    var_host = strdup(hostname);
-    if (!var_host)
-    {
-        msg(M_NONFATAL | M_ERRNO, "Can't allocate hostname buffer for getaddrinfo");
-        goto out;
-    }
-
-    /* check if this hostname has a /bits suffix */
-    sep = strchr(var_host, '/');
-    if (sep)
-    {
-        bits = strtoul(sep + 1, &endp, 10);
-        if ((*endp != '\0') || (bits > max_bits))
-        {
-            msg(msglevel, "IP prefix '%s': invalid '/bits' spec (%s)", hostname, sep + 1);
-            goto out;
-        }
-        *sep = '\0';
-    }
-
-    ret = openvpn_getaddrinfo(flags & ~GETADDR_HOST_ORDER, var_host, NULL, resolve_retry_seconds,
-                              sig_info, af, &ai);
-    if ((ret == 0) && network)
-    {
-        struct in6_addr *ip6;
-        in_addr_t *ip4;
-
-        if (af != ai->ai_family)
-        {
-            msg(msglevel, "Can't parse %s as IPv%d address", var_host, (af == AF_INET) ? 4 : 6);
-            ret = -1;
-            goto out;
-        }
-
-        switch (af)
-        {
-            case AF_INET:
-                ip4 = network;
-                *ip4 = ((struct sockaddr_in *)ai->ai_addr)->sin_addr.s_addr;
-
-                if (flags & GETADDR_HOST_ORDER)
-                {
-                    *ip4 = ntohl(*ip4);
-                }
-                break;
-
-            case AF_INET6:
-                ip6 = network;
-                *ip6 = ((struct sockaddr_in6 *)ai->ai_addr)->sin6_addr;
-                break;
-
-            default:
-                /* can't get here because 'af' was previously checked */
-                msg(M_WARN, "Unsupported AF family for %s (%d)", var_host, af);
-                goto out;
-        }
-    }
-
-    if (netbits)
-    {
-        *netbits = (unsigned int)bits;
-    }
-
-    /* restore '/' separator, if any */
-    if (sep)
-    {
-        *sep = '/';
-    }
-out:
-    if (ai)
-    {
-        freeaddrinfo(ai);
-    }
-    free(var_host);
-
-    return ret;
-}
-
-in_addr_t
-getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds, bool *succeeded,
-        struct signal_info *sig_info)
-{
-    in_addr_t addr = { 0 };
-    int status;
-
-    status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL, resolve_retry_seconds,
-                              sig_info, M_WARN);
-    if (status == 0)
-    {
-        if (succeeded)
-        {
-            *succeeded = true;
-        }
-        return addr;
-    }
-    else
-    {
-        if (succeeded)
-        {
-            *succeeded = false;
-        }
-        return 0;
-    }
-}
-
-bool
-get_ipv6_addr(const char *hostname, struct in6_addr *network, unsigned int *netbits,
-              msglvl_t msglevel)
-{
-    if (get_addr_generic(AF_INET6, GETADDR_RESOLVE, hostname, network, netbits, 0, NULL, msglevel)
-        < 0)
-    {
-        return false;
-    }
-
-    return true; /* parsing OK, values set */
-}
-
-static inline bool
-streqnull(const char *a, const char *b)
-{
-    if (a == NULL && b == NULL)
-    {
-        return true;
-    }
-    else if (a == NULL || b == NULL)
-    {
-        return false;
-    }
-    else
-    {
-        return streq(a, b);
-    }
-}
-
-/*
- * get_cached_dns_entry return 0 on success and -1
- * otherwise. (like getaddrinfo)
- */
-static int
-get_cached_dns_entry(struct cached_dns_entry *dns_cache, const char *hostname, const char *servname,
-                     int ai_family, unsigned int resolve_flags, struct addrinfo **ai)
-{
-    struct cached_dns_entry *ph;
-    unsigned int flags;
-
-    /* Only use flags that are relevant for the structure */
-    flags = resolve_flags & GETADDR_CACHE_MASK;
-
-    for (ph = dns_cache; ph; ph = ph->next)
-    {
-        if (streqnull(ph->hostname, hostname) && streqnull(ph->servname, servname)
-            && ph->ai_family == ai_family && ph->flags == flags)
-        {
-            *ai = ph->ai;
-            return 0;
-        }
-    }
-    return -1;
-}
-
-
-static int
-do_preresolve_host(struct context *c, const char *hostname, const char *servname, const int af,
-                   const unsigned int flags)
-{
-    struct addrinfo *ai;
-    int status;
-
-    if (get_cached_dns_entry(c->c1.dns_cache, hostname, servname, af, flags, &ai) == 0)
-    {
-        /* entry already cached, return success */
-        return 0;
-    }
-
-    status = openvpn_getaddrinfo(flags, hostname, servname, c->options.resolve_retry_seconds, NULL,
-                                 af, &ai);
-    if (status == 0)
-    {
-        struct cached_dns_entry *ph;
-
-        ALLOC_OBJ_CLEAR_GC(ph, struct cached_dns_entry, &c->gc);
-        ph->ai = ai;
-        ph->hostname = hostname;
-        ph->servname = servname;
-        ph->flags = flags & GETADDR_CACHE_MASK;
-
-        if (!c->c1.dns_cache)
-        {
-            c->c1.dns_cache = ph;
-        }
-        else
-        {
-            struct cached_dns_entry *prev = c->c1.dns_cache;
-            while (prev->next)
-            {
-                prev = prev->next;
-            }
-            prev->next = ph;
-        }
-
-        gc_addspecial(ai, &gc_freeaddrinfo_callback, &c->gc);
-    }
-    return status;
-}
-
-void
-do_preresolve(struct context *c)
-{
-    struct connection_list *l = c->options.connection_list;
-    const unsigned int preresolve_flags = GETADDR_RESOLVE | GETADDR_UPDATE_MANAGEMENT_STATE
-                                          | GETADDR_MENTION_RESOLVE_RETRY | GETADDR_FATAL;
-
-
-    for (int i = 0; i < l->len; ++i)
-    {
-        int status;
-        const char *remote;
-        unsigned int flags = preresolve_flags;
-
-        struct connection_entry *ce = l->array[i];
-
-        if (proto_is_dgram(ce->proto))
-        {
-            flags |= GETADDR_DATAGRAM;
-        }
-
-        if (c->options.sockflags & SF_HOST_RANDOMIZE)
-        {
-            flags |= GETADDR_RANDOMIZE;
-        }
-
-        if (c->options.ip_remote_hint)
-        {
-            remote = c->options.ip_remote_hint;
-        }
-        else
-        {
-            remote = ce->remote;
-        }
-
-        /* HTTP remote hostname does not need to be resolved */
-        if (!ce->http_proxy_options)
-        {
-            status = do_preresolve_host(c, remote, ce->remote_port, ce->af, flags);
-            if (status != 0)
-            {
-                goto err;
-            }
-        }
-
-        /* Preresolve proxy */
-        if (ce->http_proxy_options)
-        {
-            status = do_preresolve_host(c, ce->http_proxy_options->server,
-                                        ce->http_proxy_options->port, ce->af, preresolve_flags);
-
-            if (status != 0)
-            {
-                goto err;
-            }
-        }
-
-        if (ce->socks_proxy_server)
-        {
-            status =
-                do_preresolve_host(c, ce->socks_proxy_server, ce->socks_proxy_port, ce->af, flags);
-            if (status != 0)
-            {
-                goto err;
-            }
-        }
-
-        if (ce->bind_local)
-        {
-            flags |= GETADDR_PASSIVE;
-            flags &= ~GETADDR_RANDOMIZE;
-
-            for (int j = 0; j < ce->local_list->len; j++)
-            {
-                const struct local_entry *le = ce->local_list->array[j];
-
-                if (!le->local)
-                {
-                    continue;
-                }
-
-                status = do_preresolve_host(c, le->local, le->port, ce->af, flags);
-                if (status != 0)
-                {
-                    goto err;
-                }
-            }
-        }
-    }
-    return;
-
-err:
-    throw_signal_soft(SIGHUP, "Preresolving failed");
-}
-
 static int
 socket_get_sndbuf(socket_descriptor_t sd)
 {
diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h
index c6bcd86..e8335d3 100644
--- a/src/openvpn/socket.h
+++ b/src/openvpn/socket.h
@@ -62,17 +62,6 @@
 /* convert a packet_size_type from network to host order */
 #define ntohps(x) ntohs(x)
 
-/* struct to hold preresolved host names */
-struct cached_dns_entry
-{
-    const char *hostname;
-    const char *servname;
-    int ai_family;
-    unsigned int flags;
-    struct addrinfo *ai;
-    struct cached_dns_entry *next;
-};
-
 /* IP addresses which are persistent across SIGUSR1s */
 struct link_socket_addr
 {
@@ -362,8 +351,6 @@
 
 void link_socket_init_phase2(struct context *c, struct link_socket *sock);
 
-void do_preresolve(struct context *c);
-
 void link_socket_close(struct link_socket *sock);
 
 #ifdef ENABLE_MANAGEMENT
diff --git a/src/openvpn/socket_util.c b/src/openvpn/socket_util.c
index 0194f38..5d405ac 100644
--- a/src/openvpn/socket_util.c
+++ b/src/openvpn/socket_util.c
@@ -490,271 +490,6 @@
     return ""; /* Make the compiler happy */
 }
 
-/**
- * Small helper function for openvpn_getaddrinfo to print the address
- * family when resolving fails
- */
-static const char *
-getaddrinfo_addr_family_name(int af)
-{
-    switch (af)
-    {
-        case AF_INET:
-            return "[AF_INET]";
-
-        case AF_INET6:
-            return "[AF_INET6]";
-    }
-    return "";
-}
-
-/*
- * Prepend a random string to hostname to prevent DNS caching.
- * For example, foo.bar.gov would be modified to <random-chars>.foo.bar.gov.
- * Of course, this requires explicit support in the DNS server (wildcard).
- */
-static const char *
-hostname_randomize(const char *hostname, struct gc_arena *gc)
-{
-#define n_rnd_bytes 6
-
-    uint8_t rnd_bytes[n_rnd_bytes];
-    const char *rnd_str;
-    struct buffer hname = alloc_buf_gc(strlen(hostname) + sizeof(rnd_bytes) * 2 + 4, gc);
-
-    prng_bytes(rnd_bytes, sizeof(rnd_bytes));
-    rnd_str = format_hex_ex(rnd_bytes, sizeof(rnd_bytes), 40, 0, NULL, gc);
-    buf_printf(&hname, "%s.%s", rnd_str, hostname);
-    return BSTR(&hname);
-#undef n_rnd_bytes
-}
-
-/*
- * Translate IPv4/IPv6 addr or hostname into struct addrinfo
- * If resolve error, try again for resolve_retry_seconds seconds.
- */
-int
-openvpn_getaddrinfo(unsigned int flags, const char *hostname, const char *servname,
-                    int resolve_retry_seconds, struct signal_info *sig_info, int ai_family,
-                    struct addrinfo **res)
-{
-    struct addrinfo hints;
-    int status;
-    struct signal_info sigrec = { 0 };
-    msglvl_t msglevel = (flags & GETADDR_FATAL) ? M_FATAL : D_RESOLVE_ERRORS;
-    struct gc_arena gc = gc_new();
-    const char *print_hostname;
-    const char *print_servname;
-
-    ASSERT(res);
-
-    ASSERT(hostname || servname);
-    ASSERT(!(flags & GETADDR_HOST_ORDER));
-
-    if (servname)
-    {
-        print_servname = servname;
-    }
-    else
-    {
-        print_servname = "";
-    }
-
-    if (flags & GETADDR_MSG_VIRT_OUT)
-    {
-        msglevel |= M_MSG_VIRT_OUT;
-    }
-
-    if ((flags & (GETADDR_FATAL_ON_SIGNAL | GETADDR_WARN_ON_SIGNAL)) && !sig_info)
-    {
-        sig_info = &sigrec;
-    }
-
-    /* try numeric ip addr first */
-    CLEAR(hints);
-    hints.ai_flags = AI_NUMERICHOST;
-
-    if (flags & GETADDR_PASSIVE)
-    {
-        hints.ai_flags |= AI_PASSIVE;
-    }
-
-    if (flags & GETADDR_DATAGRAM)
-    {
-        hints.ai_socktype = SOCK_DGRAM;
-    }
-    else
-    {
-        hints.ai_socktype = SOCK_STREAM;
-    }
-
-    /* if hostname is not set, we want to bind to 'ANY', with
-     * the correct address family - v4-only or v6/v6-dual-stack */
-    if (!hostname)
-    {
-        hints.ai_family = ai_family;
-    }
-
-    status = getaddrinfo(hostname, servname, &hints, res);
-
-    if (status != 0)                      /* parse as numeric address failed? */
-    {
-        const int fail_wait_interval = 5; /* seconds */
-        /* Add +4 to cause integer division rounding up (1 + 4) = 5, (0+4)/5=0 */
-        int resolve_retries =
-            (flags & GETADDR_TRY_ONCE) ? 1 : ((resolve_retry_seconds + 4) / fail_wait_interval);
-        const char *fmt;
-        msglvl_t level = 0;
-
-        /* this is not a numeric IP, therefore force resolution using the
-         * provided ai_family */
-        hints.ai_family = ai_family;
-
-        if (hostname && (flags & GETADDR_RANDOMIZE))
-        {
-            hostname = hostname_randomize(hostname, &gc);
-        }
-
-        if (hostname)
-        {
-            print_hostname = hostname;
-        }
-        else
-        {
-            print_hostname = "undefined";
-        }
-
-        fmt = "RESOLVE: Cannot resolve host address: %s:%s%s (%s)";
-        if ((flags & GETADDR_MENTION_RESOLVE_RETRY) && !resolve_retry_seconds)
-        {
-            fmt = "RESOLVE: Cannot resolve host address: %s:%s%s (%s)"
-                  "(I would have retried this name query if you had "
-                  "specified the --resolv-retry option.)";
-        }
-
-        if (!(flags & GETADDR_RESOLVE) || status == EAI_FAIL)
-        {
-            msg(msglevel, "RESOLVE: Cannot parse IP address: %s:%s (%s)", print_hostname,
-                print_servname, gai_strerror(status));
-            goto done;
-        }
-
-#ifdef ENABLE_MANAGEMENT
-        if (flags & GETADDR_UPDATE_MANAGEMENT_STATE)
-        {
-            if (management)
-            {
-                management_set_state(management, OPENVPN_STATE_RESOLVE, NULL, NULL, NULL, NULL,
-                                     NULL);
-            }
-        }
-#endif
-
-        /*
-         * Resolve hostname
-         */
-        while (true)
-        {
-#ifndef _WIN32
-            /* force resolv.conf reload */
-            res_init();
-#endif
-            /* try hostname lookup */
-            hints.ai_flags &= ~AI_NUMERICHOST;
-            dmsg(D_SOCKET_DEBUG, "GETADDRINFO flags=0x%04x ai_family=%d ai_socktype=%d", flags,
-                 hints.ai_family, hints.ai_socktype);
-            status = getaddrinfo(hostname, servname, &hints, res);
-
-            if (sig_info)
-            {
-                get_signal(&sig_info->signal_received);
-                if (sig_info->signal_received) /* were we interrupted by a signal? */
-                {
-                    /* why are we overwriting SIGUSR1 ? */
-                    if (signal_reset(sig_info, SIGUSR1) == SIGUSR1) /* ignore SIGUSR1 */
-                    {
-                        msg(level, "RESOLVE: Ignored SIGUSR1 signal received during "
-                                   "DNS resolution attempt");
-                    }
-                    else
-                    {
-                        /* turn success into failure (interrupted syscall) */
-                        if (0 == status)
-                        {
-                            ASSERT(res);
-                            freeaddrinfo(*res);
-                            *res = NULL;
-                            status = EAI_AGAIN; /* = temporary failure */
-                            errno = EINTR;
-                        }
-                        goto done;
-                    }
-                }
-            }
-
-            /* success? */
-            if (0 == status)
-            {
-                break;
-            }
-
-            /* resolve lookup failed, should we
-             * continue or fail? */
-            level = msglevel;
-            if (resolve_retries > 0)
-            {
-                level = D_RESOLVE_ERRORS;
-            }
-
-            msg(level, fmt, print_hostname, print_servname, getaddrinfo_addr_family_name(ai_family),
-                gai_strerror(status));
-
-            if (--resolve_retries <= 0)
-            {
-                goto done;
-            }
-
-            management_sleep(fail_wait_interval);
-        }
-
-        ASSERT(res);
-
-        /* hostname resolve succeeded */
-
-        /*
-         * Do not choose an IP Addresse by random or change the order *
-         * of IP addresses, doing so will break RFC 3484 address selection *
-         */
-    }
-    else
-    {
-        /* IP address parse succeeded */
-        if (flags & GETADDR_RANDOMIZE)
-        {
-            msg(M_WARN, "WARNING: ignoring --remote-random-hostname because the "
-                        "hostname is an IP address");
-        }
-    }
-
-done:
-    if (sig_info && sig_info->signal_received)
-    {
-        msglvl_t level = 0;
-        if (flags & GETADDR_FATAL_ON_SIGNAL)
-        {
-            level = M_FATAL;
-        }
-        else if (flags & GETADDR_WARN_ON_SIGNAL)
-        {
-            level = M_WARN;
-        }
-        msg(level, "RESOLVE: signal received during DNS resolution attempt");
-    }
-
-    gc_free(&gc);
-    return status;
-}
-
 /*
  * We do our own inet_aton because the glibc function
  * isn't very good about error checking.
diff --git a/src/openvpn/socket_util.h b/src/openvpn/socket_util.h
index add08ba..c0dcfb07 100644
--- a/src/openvpn/socket_util.h
+++ b/src/openvpn/socket_util.h
@@ -110,43 +110,6 @@
 void setenv_link_socket_actual(struct env_set *es, const char *name_prefix,
                                const struct link_socket_actual *act, const unsigned int flags);
 
-/*
- * DNS resolution
- */
-
-#define GETADDR_RESOLVE                 (1u << 0)
-#define GETADDR_FATAL                   (1u << 1)
-#define GETADDR_HOST_ORDER              (1u << 2)
-#define GETADDR_MENTION_RESOLVE_RETRY   (1u << 3)
-#define GETADDR_FATAL_ON_SIGNAL         (1u << 4)
-#define GETADDR_WARN_ON_SIGNAL          (1u << 5)
-#define GETADDR_MSG_VIRT_OUT            (1u << 6)
-#define GETADDR_TRY_ONCE                (1u << 7)
-#define GETADDR_UPDATE_MANAGEMENT_STATE (1u << 8)
-#define GETADDR_RANDOMIZE               (1u << 9)
-#define GETADDR_PASSIVE                 (1u << 10)
-#define GETADDR_DATAGRAM                (1u << 11)
-
-#define GETADDR_CACHE_MASK (GETADDR_DATAGRAM | GETADDR_PASSIVE)
-
-/**
- * Translate an IPv4 addr or hostname from string form to in_addr_t
- *
- * In case of resolve error, it will try again for
- * resolve_retry_seconds seconds.
- */
-in_addr_t getaddr(unsigned int flags, const char *hostname, int resolve_retry_seconds,
-                  bool *succeeded, struct signal_info *sig_info);
-
-/**
- * Translate an IPv6 addr or hostname from string form to in6_addr
- */
-bool get_ipv6_addr(const char *hostname, struct in6_addr *network, unsigned int *netbits,
-                   msglvl_t msglevel);
-
-int openvpn_getaddrinfo(unsigned int flags, const char *hostname, const char *servname,
-                        int resolve_retry_seconds, struct signal_info *sig_info, int ai_family,
-                        struct addrinfo **res);
 
 /* return values of openvpn_inet_aton */
 #define OIA_HOSTNAME 0
diff --git a/src/openvpn/tun.c b/src/openvpn/tun.c
index abb46af..5bc201d 100644
--- a/src/openvpn/tun.c
+++ b/src/openvpn/tun.c
@@ -39,7 +39,7 @@
 #include "fdmisc.h"
 #include "common.h"
 #include "run_command.h"
-#include "socket_util.h"
+#include "resolve.h"
 #include "manage.h"
 #include "route.h"
 #include "win32.h"

-- 
To view, visit http://gerrit.openvpn.net/c/openvpn/+/1846?usp=email
To unsubscribe, or for help writing mail filters, visit http://gerrit.openvpn.net/settings?usp=email

Gerrit-MessageType: newchange
Gerrit-Project: openvpn
Gerrit-Branch: master
Gerrit-Change-Id: I12bef330e2c8a5e5b21c2fa807584319b2b7101f
Gerrit-Change-Number: 1846
Gerrit-PatchSet: 1
Gerrit-Owner: flichtenheld <[email protected]>
Gerrit-Reviewer: plaisthos <[email protected]>
Gerrit-CC: openvpn-devel <[email protected]>
Gerrit-Attention: plaisthos <[email protected]>

_______________________________________________
Openvpn-devel mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/openvpn-devel
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.