diff -up ./lib/libswan/ttoaddress.c.getaddrinfo ./lib/libswan/ttoaddress.c --- ./lib/libswan/ttoaddress.c.getaddrinfo 2021-04-22 17:24:33.000000000 +0200 +++ ./lib/libswan/ttoaddress.c 2021-07-22 13:16:19.073745043 +0200 @@ -20,6 +20,7 @@ #include /* for gethostbyname2() */ #include "ip_address.h" +#include "ip_sockaddr.h" #include "ip_info.h" #include "lswalloc.h" /* for alloc_things(), pfree() */ #include "lswlog.h" /* for pexpect() */ @@ -75,56 +76,6 @@ static err_t ttoaddr_base(shunk_t src, } /* - * tryname - try it as a name - * - * Error return is intricate because we cannot compose a static string. - */ -static err_t tryname(const char *p, - int af, - int suggested_af, /* kind(s) of numeric addressing tried */ - ip_address *dst) -{ - struct hostent *h = gethostbyname2(p, af); - if (h != NULL) { - if (h->h_addrtype != af) { - return "address-type mismatch from gethostbyname2!!!"; - } - - return data_to_address(h->h_addr, h->h_length, aftoinfo(af), dst); - } - - if (af == AF_INET6) { - if (suggested_af == AF_INET6) { - return "not a numeric IPv6 address and name lookup failed (no validation performed)"; - } else /* AF_UNSPEC */ { - return "not a numeric IPv4 or IPv6 address and name lookup failed (no validation performed)"; - } - } - - pexpect(af == AF_INET); - - /* like, windows even has an /etc/networks? */ - struct netent *ne = getnetbyname(p); - if (ne == NULL) { - /* intricate because we cannot compose a static string */ - if (suggested_af == AF_INET) { - return "not a numeric IPv4 address and name lookup failed (no validation performed)"; - } else { - return "not a numeric IPv4 or IPv6 address and name lookup failed (no validation performed)"; - } - } - - if (ne->n_addrtype != af) { - return "address-type mismatch from getnetbyname!!!"; - } - - /* apparently .n_net is in host order */ - struct in_addr in = { htonl(ne->n_net), }; - *dst = address_from_in_addr(&in); - return NULL; -} - -/* * tryhex - try conversion as an eight-digit hex number (AF_INET only) */ @@ -401,57 +352,56 @@ err_t getpiece(const char **srcp, /* *sr err_t ttoaddress_dns(shunk_t src, const struct ip_info *afi, ip_address *dst) { + char *name = clone_hunk_as_string(src, "ttoaddress_dns"); /* must free */ + struct addrinfo *res = NULL; + const struct addrinfo hints = (struct addrinfo) { + .ai_family = afi == NULL ? AF_UNSPEC : afi->af, + }; *dst = unset_address; - if (src.len == 0) { - return "empty string"; - } - - bool was_numeric = true; - err_t err = ttoaddr_base(src, afi, &was_numeric, dst); - if (was_numeric) { - /* no-point in continuing */ - return err; - } - /* err == non-numeric */ + int eai = getaddrinfo(name, NULL, &hints, &res); + err_t err = NULL; - for (const char *cp = src.ptr, *end = cp + src.len; cp < end; cp++) { + if (eai != 0) { /* - * Legal ASCII characters in a domain name. - * Underscore technically is not, but is a common - * misunderstanding. Non-ASCII characters are simply - * exempted from checking at the moment, to allow for - * UTF-8 encoded stuff; the purpose of this check is - * merely to catch blatant errors. - * - * XXX: Suspect the ISASCII() check can be dropped - - * utf-8 isn't allowed in DNS names and without a - * utf-8 parser the check is flawed. + * return system-supplied diagnostic + * except where it is particularly confusing. + * "Name or service not unknown." is terrible. */ - static const char namechars[] = - "abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-_."; -#define ISASCII(c) (((c) & 0x80) == 0) - if (ISASCII(*cp) && strchr(namechars, *cp) == NULL) { - return "illegal (non-DNS-name) character in name"; + err = eai == EAI_NONAME ? "NAME is unknown" : gai_strerror(eai); + } else if (res == NULL) { + err = "not a numeric IP address and name lookup failed (no validation performed)"; + } else { + /* always choose IPv4 result if there is one */ + struct addrinfo *winner = res; + + for (struct addrinfo *r = res; r!= NULL; r = r->ai_next) { + if (r->ai_family == AF_INET) { + winner = r; + break; + } + } + + ip_port mbz = { .hport = 0 }; + ip_sockaddr sa = { + .len = winner->ai_addrlen, + }; + passert(sizeof(sa.sa) >= winner->ai_addrlen); + memcpy(&sa.sa, winner->ai_addr, winner->ai_addrlen); + passert(sa.sa.sa.sa_family == winner->ai_family); + /* boneheaded getaddrinfo(3) leaves port field uninitialized */ + if (winner->ai_family == AF_INET) { + sa.sa.sin.sin_port = 0; + } else if (winner->ai_family == AF_INET6) { + sa.sa.sin6.sin6_port = 0; + } else { + bad_case(winner->ai_family); } + err = sockaddr_to_address_port(sa, dst, &mbz); + passert(hport(mbz) == 0); } - /* - * need a guarenteed null terminated string - */ - char *name = clone_hunk_as_string(src, "ttoaddress_dns"); /* must free */ - int suggested_af = afi == NULL ? AF_UNSPEC : afi->af; - err_t v4err = NULL, v6err = NULL; - if (err && (suggested_af == AF_UNSPEC || suggested_af == AF_INET)) { - err = v4err = tryname(name, AF_INET, suggested_af, dst); - } - if (err && (suggested_af == AF_UNSPEC || suggested_af == AF_INET6)) { - err = v6err = tryname(name, AF_INET6, suggested_af, dst); - } - /* prefer the IPv4 error */ - if (err != NULL && v4err != NULL) { - err = v4err; - } + freeaddrinfo(res); pfree(name); return err; }