From patchwork Sat Dec 2 17:14:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Antonio Quartulli X-Patchwork-Id: 120 Return-Path: Delivered-To: patchwork@openvpn.net Delivered-To: patchwork@openvpn.net Received: from director6.mail.ord1d.rsapps.net ([172.30.191.6]) by backend31.mail.ord1d.rsapps.net (Dovecot) with LMTP id K3tcCrt6I1r1fwAAgoeIoA for ; Sat, 02 Dec 2017 23:16:59 -0500 Received: from proxy3.mail.ord1d.rsapps.net ([172.30.191.6]) by director6.mail.ord1d.rsapps.net (Dovecot) with LMTP id 3YAaBbt6I1ouQAAAhgvE6Q ; Sat, 02 Dec 2017 23:16:59 -0500 Received: from smtp37.gate.ord1c ([172.30.191.6]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) by proxy3.mail.ord1d.rsapps.net (Dovecot) with LMTP id aj+MCLt6I1pzWwAA7WKfLA ; Sat, 02 Dec 2017 23:16:59 -0500 X-Spam-Threshold: 95 X-Spam-Score: 0 X-Spam-Flag: NO X-Virus-Scanned: OK X-Orig-To: openvpnslackdevel@openvpn.net X-Originating-Ip: [216.34.181.88] Authentication-Results: smtp37.gate.ord1c.rsapps.net; iprev=pass policy.iprev="216.34.181.88"; spf=pass smtp.mailfrom="openvpn-devel-bounces@lists.sourceforge.net" smtp.helo="lists.sourceforge.net"; dkim=fail (signature verification failed) header.d=sourceforge.net; dkim=fail (signature verification failed) header.d=sf.net; dmarc=none (p=nil; dis=none) header.from=unstable.cc X-Classification-ID: ce1a5da4-d7e0-11e7-9280-0026b94ab8ea-1-1 Received: from [216.34.181.88] ([216.34.181.88:61248] helo=lists.sourceforge.net) by smtp37.gate.ord1c.rsapps.net (envelope-from ) (ecelerity 4.2.1.56364 r(Core:4.2.1.14)) with ESMTPS (cipher=DHE-RSA-AES256-GCM-SHA384) id 2E/CC-08193-ABA732A5; Sat, 02 Dec 2017 23:16:59 -0500 Received: from localhost ([127.0.0.1] helo=sfs-ml-1.v29.ch3.sourceforge.com) by sfs-ml-1.v29.ch3.sourceforge.com with esmtp (Exim 4.89) (envelope-from ) id 1eLLgg-00087F-J9; Sun, 03 Dec 2017 04:15:30 +0000 Received: from sfi-mx-2.v28.ch3.sourceforge.com ([172.29.28.192] helo=mx.sourceforge.net) by sfs-ml-1.v29.ch3.sourceforge.com with esmtps (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) (envelope-from ) id 1eLLgf-000877-B3 for openvpn-devel@lists.sourceforge.net; Sun, 03 Dec 2017 04:15:29 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To: MIME-Version:Content-Type:Content-Transfer-Encoding:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=SL5oj8GeobjcfVr/rKaQQ1pAHVFnRy+wtWa9Hqd7lTE=; b=eIIQhQN881+bvlncq+aCX9XKIQ DXMgWQPfxkOrFesDfAZ1uO2Q0iVt0puyMFKsIVr88W6csk65FYrQ4gDeWbGd2j6Tp9L3trJBaL0h5 qEAFP5+3M4to7wgIsIZyE05ou51mJ7XcmfdJaXlClqG3M1HgoD520bZS4iRxMYU+8oZw=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Message-Id:Date:Subject:Cc:To:From:Sender:Reply-To:MIME-Version: Content-Type:Content-Transfer-Encoding:Content-ID:Content-Description: Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID: In-Reply-To:References:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=SL5oj8GeobjcfVr/rKaQQ1pAHVFnRy+wtWa9Hqd7lTE=; b=R7IKPnhslxNOLrz26cfc3Do0Y3 q24rCZKNPIo/BnT2v2KFOeS4UEkLR43xAzIYVBvhaL+bCGhXSZeGyhfvKG1/up6tcw50lZtua40u4 +7dnopj0DmIPTS6tAnsyhKS3hFWPwNRclbxt1+GZdEquC4os2Qhvg6Jlrw0B/adIGvmE=; Received: from s2.neomailbox.net ([5.148.176.60]) by sfi-mx-2.v28.ch3.sourceforge.com with esmtps (TLSv1.2:DHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) id 1eLLge-0007yL-4k for openvpn-devel@lists.sourceforge.net; Sun, 03 Dec 2017 04:15:29 +0000 From: Antonio Quartulli To: openvpn-devel@lists.sourceforge.net Date: Sun, 3 Dec 2017 12:14:26 +0800 Message-Id: <20171203041426.25316-1-a@unstable.cc> X-Spam-Report: Spam Filtering performed by mx.sourceforge.net. See http://spamassassin.org/tag/ for more details. -0.0 RCVD_IN_DNSWL_NONE RBL: Sender listed at http://www.dnswl.org/, no trust [5.148.176.60 listed in list.dnswl.org] -0.0 AWL AWL: Adjusted score from AWL reputation of From: address X-Headers-End: 1eLLge-0007yL-4k Subject: [Openvpn-devel] [PATCH v4] ifconfig-ipv6(-push): allow using hostnames X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Antonio Quartulli MIME-Version: 1.0 Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox Similarly to ifconfig(-push), its IPv6 counterpart is now able to accept hostnames as well instead of IP addresses in numeric form. Basically this means that the user is now allowed to specify something like this: ifconfig-ipv6-push my.hostname.cx/64 This is exactly the same behaviour that we already have with ifconfig(-push). The generic code introduced in this patch will be later used to implement the /bits parsing support for IPv4 addresses. Trac: #808 Signed-off-by: Antonio Quartulli Reviewed-by: Selva Nair Tested-by: Selva Nair Acked-by: Selva Nair --- v4: - fix variable order in debug message - fix typo in loglevel name v3: - declare 'bits' as unsigned long (will store result of strtoul()) - convert ASSERTs to plain error handling in get_addr_generic() - remove useless comment about '/' overwriting - improve debug message by printing hostname v2: - rebased on top of master - style adapted to new CodingStyle src/openvpn/options.c | 61 ---------------------- src/openvpn/options.h | 4 -- src/openvpn/socket.c | 140 +++++++++++++++++++++++++++++++++++++++++++++----- src/openvpn/socket.h | 12 +++++ 4 files changed, 140 insertions(+), 77 deletions(-) diff --git a/src/openvpn/options.c b/src/openvpn/options.c index 8e5cdf7f..767cdaeb 100644 --- a/src/openvpn/options.c +++ b/src/openvpn/options.c @@ -1033,67 +1033,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". * diff --git a/src/openvpn/options.h b/src/openvpn/options.h index 035c6d15..d67c2785 100644 --- a/src/openvpn/options.h +++ b/src/openvpn/options.h @@ -817,8 +817,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 */ diff --git a/src/openvpn/socket.c b/src/openvpn/socket.c index 0fc91f21..7f3842da 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) { diff --git a/src/openvpn/socket.h b/src/openvpn/socket.h index 2d7f2187..81e9e9ae 100644 --- a/src/openvpn/socket.h +++ b/src/openvpn/socket.h @@ -532,12 +532,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,