diff options
author | Bernhard Schmidt <berni@debian.org> | 2019-02-20 14:11:46 +0100 |
---|---|---|
committer | Bernhard Schmidt <berni@debian.org> | 2019-02-20 14:11:46 +0100 |
commit | 87356242baf10c8b2a94d9013e436ed2a0dada53 (patch) | |
tree | dd8c5f9774af74c20cdae579ac0f2d352a835e9e /src/openvpn/socket.c | |
parent | 2c8e4bc4f9ab94e4d0b63341820d471af7c28c6c (diff) |
New upstream version 2.4.7upstream/2.4.7
Diffstat (limited to 'src/openvpn/socket.c')
-rw-r--r-- | src/openvpn/socket.c | 140 |
1 files changed, 128 insertions, 12 deletions
diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 211e744..c76d206 100644 --- a/src/openvpn/socket.c +++ b/src/openvpn/socket.c @@ -74,12 +74,116 @@ sf2gaf(const unsigned int 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, volatile int *signal_received, + int 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, signal_received, af, &ai); + if ((ret == 0) && network) + { + struct in6_addr *ip6; + in_addr_t *ip4; + + 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 = bits; + } + + /* restore '/' separator, if any */ + if (sep) + { + *sep = '/'; + } +out: + freeaddrinfo(ai); + free(var_host); + + return ret; +} -/* - * Translate IP addr or hostname to in_addr_t. - * If resolve error, try again for - * resolve_retry_seconds seconds. - */ in_addr_t getaddr(unsigned int flags, const char *hostname, @@ -87,20 +191,19 @@ getaddr(unsigned int flags, bool *succeeded, volatile int *signal_received) { - struct addrinfo *ai; + in_addr_t addr; int status; - status = openvpn_getaddrinfo(flags & ~GETADDR_HOST_ORDER, hostname, NULL, - resolve_retry_seconds, signal_received, AF_INET, &ai); + + status = get_addr_generic(AF_INET, flags, hostname, &addr, NULL, + resolve_retry_seconds, signal_received, + M_WARN); if (status==0) { - struct in_addr ia; if (succeeded) { *succeeded = true; } - ia = ((struct sockaddr_in *)ai->ai_addr)->sin_addr; - freeaddrinfo(ai); - return (flags & GETADDR_HOST_ORDER) ? ntohl(ia.s_addr) : ia.s_addr; + return addr; } else { @@ -112,6 +215,19 @@ getaddr(unsigned int flags, } } +bool +get_ipv6_addr(const char *hostname, struct in6_addr *network, + unsigned int *netbits, int 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) { |