@@ -1026,67 +1026,6 @@ get_ip_addr(const char *ip_string, int msglevel, bool *error)
return ret;
}
-/* helper: parse a text string containing an IPv6 address + netbits
- * in "standard format" (2001:dba::/32)
- * "/nn" is optional, default to /64 if missing
- *
- * return true if parsing succeeded, modify *network and *netbits
- */
-bool
-get_ipv6_addr( const char *prefix_str, struct in6_addr *network,
- unsigned int *netbits, int msglevel)
-{
- char *sep, *endp;
- int bits;
- struct in6_addr t_network;
-
- sep = strchr( prefix_str, '/' );
- if (sep == NULL)
- {
- bits = 64;
- }
- else
- {
- bits = strtol( sep+1, &endp, 10 );
- if (*endp != '\0' || bits < 0 || bits > 128)
- {
- msg(msglevel, "IPv6 prefix '%s': invalid '/bits' spec", prefix_str);
- return false;
- }
- }
-
- /* temporary replace '/' in caller-provided string with '\0', otherwise
- * inet_pton() will refuse prefix string
- * (alternative would be to strncpy() the prefix to temporary buffer)
- */
-
- if (sep != NULL)
- {
- *sep = '\0';
- }
-
- if (inet_pton( AF_INET6, prefix_str, &t_network ) != 1)
- {
- msg(msglevel, "IPv6 prefix '%s': invalid IPv6 address", prefix_str);
- return false;
- }
-
- if (sep != NULL)
- {
- *sep = '/';
- }
-
- if (netbits != NULL)
- {
- *netbits = bits;
- }
- if (network != NULL)
- {
- *network = t_network;
- }
- return true; /* parsing OK, values set */
-}
-
/**
* Returns newly allocated string containing address part without "/nn".
*
@@ -811,8 +811,4 @@ void options_string_import(struct options *options,
unsigned int *option_types_found,
struct env_set *es);
-bool get_ipv6_addr( const char *prefix_str, struct in6_addr *network,
- unsigned int *netbits, int msglevel );
-
-
#endif /* ifndef OPTIONS_H */
@@ -75,12 +75,102 @@ 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;
+ uint8_t bits, max_bits;
+ struct addrinfo *ai;
+ int ret = -1;
+
+ ASSERT(hostname);
+
+ /* 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:
+ ASSERT(0);
+ }
+
+ /* 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);
+ ASSERT(var_host);
+
+ /* 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", hostname);
+ goto out;
+ }
+ /* temporary truncate string at '/'. This allows the IP
+ * parsing routines to properly work. Will be restored later.
+ */
+ *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:
+ ASSERT(0);
+ }
+ freeaddrinfo(ai);
+ }
+
+ if (netbits)
+ {
+ *netbits = bits;
+ }
+
+ /* restore '/' separator, if any */
+ if (sep)
+ {
+ *sep = '/';
+ }
+out:
+ 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,
@@ -88,20 +178,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
{
@@ -113,6 +202,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)
{
@@ -533,12 +533,24 @@ bool unix_socket_get_peer_uid_gid(const socket_descriptor_t sd, int *uid, int *g
#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,
volatile int *signal_received);
+/**
+ * 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, int msglevel);
+
int openvpn_getaddrinfo(unsigned int flags,
const char *hostname,
const char *servname,