From: John Hay Date: Thu, 14 Nov 2002 16:20:48 +0000 (+0200) Subject: First try getaddrinfo() with the AI_NUMERICHOST hint and try again as X-Git-Tag: NTP_4_1_73~26^2~4 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=3d084ac2ff0e317dbd02e131763e8ed453d1f3fe;p=thirdparty%2Fntp.git First try getaddrinfo() with the AI_NUMERICHOST hint and try again as before if it fails. This works around the "problem" on Solaris that return the "IPv4-mapped IPv6 address" if you give it an IPv4 address. bk: 3dd3cd60k7yJ0nUvVjOQV-Fmnf9aPw --- diff --git a/libntp/ntp_rfc2553.c b/libntp/ntp_rfc2553.c index 132f3d1b54..82eb2860fd 100644 --- a/libntp/ntp_rfc2553.c +++ b/libntp/ntp_rfc2553.c @@ -113,13 +113,15 @@ static char *ai_errlist[] = { }; static int ipv4_aton P((const char *, struct sockaddr_storage *)); +static int do_nodename P((const char *nodename, struct addrinfo *ai, + const struct addrinfo *hints)); int getaddrinfo (const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { + int rval; struct addrinfo *ai; - struct hostent *hp; struct sockaddr_in *sockin; ai = calloc(sizeof(struct addrinfo), 1); @@ -127,45 +129,18 @@ getaddrinfo (const char *nodename, const char *servname, return (EAI_MEMORY); if (nodename != NULL) { - ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1); - if (ai->ai_addr == NULL) - return (EAI_MEMORY); - hp = gethostbyname(nodename); - if (hp == NULL) { - if (h_errno == TRY_AGAIN) - return (EAI_AGAIN); - else { - if (ipv4_aton(nodename, - (struct sockaddr_storage *)ai->ai_addr) - == 1) { - ai->ai_family = AF_INET; - ai->ai_addrlen = - sizeof(struct sockaddr_in); - *res = ai; - return (0); - } - return (EAI_FAIL); - } - } - ai->ai_family = hp->h_addrtype; - ai->ai_addrlen = sizeof(struct sockaddr); - sockin = (struct sockaddr_in *)ai->ai_addr; - memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length); - ai->ai_addr->sa_family = hp->h_addrtype; -#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR - ai->ai_addr->sa_len = sizeof(struct sockaddr); -#endif - if (hints != NULL && hints->ai_flags & AI_CANONNAME) { - ai->ai_canonname = malloc(strlen(hp->h_name)); - if (ai->ai_canonname == NULL) - return (EAI_MEMORY); - strcpy(ai->ai_canonname, hp->h_name); + rval = do_nodename(nodename, ai, hints); + if (rval != 0) { + freeaddrinfo(ai); + return (rval); } } if (nodename == NULL && hints != NULL) { ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1); - if (ai->ai_addr == NULL) + if (ai->ai_addr == NULL) { + freeaddrinfo(ai); return (EAI_MEMORY); + } ai->ai_family = AF_INET; ai->ai_addrlen = sizeof(struct sockaddr_storage); sockin = (struct sockaddr_in *)ai->ai_addr; @@ -178,8 +153,10 @@ getaddrinfo (const char *nodename, const char *servname, if (servname != NULL) { ai->ai_family = AF_INET; ai->ai_socktype = SOCK_DGRAM; - if (strcmp(servname, "123") != 0) + if (strcmp(servname, "123") != 0) { + freeaddrinfo(ai); return (EAI_SERVICE); + } sockin = (struct sockaddr_in *)ai->ai_addr; sockin->sin_port = htons(NTP_PORT); } @@ -230,6 +207,59 @@ gai_strerror(ecode) return ai_errlist[ecode]; } +static int +do_nodename( + const char *nodename, + struct addrinfo *ai, + const struct addrinfo *hints) +{ + struct hostent *hp; + struct sockaddr_in *sockin; + + ai->ai_addr = calloc(sizeof(struct sockaddr_storage), 1); + if (ai->ai_addr == NULL) + return (EAI_MEMORY); + + if (hints != NULL && hints->ai_flags & AI_NUMERICHOST) { + if (ipv4_aton(nodename, + (struct sockaddr_storage *)ai->ai_addr) == 1) { + ai->ai_family = AF_INET; + ai->ai_addrlen = sizeof(struct sockaddr_in); + return (0); + } + return (EAI_NONAME); + } + hp = gethostbyname(nodename); + if (hp == NULL) { + if (h_errno == TRY_AGAIN) + return (EAI_AGAIN); + else { + if (ipv4_aton(nodename, + (struct sockaddr_storage *)ai->ai_addr) == 1) { + ai->ai_family = AF_INET; + ai->ai_addrlen = sizeof(struct sockaddr_in); + return (0); + } + return (EAI_FAIL); + } + } + ai->ai_family = hp->h_addrtype; + ai->ai_addrlen = sizeof(struct sockaddr); + sockin = (struct sockaddr_in *)ai->ai_addr; + memcpy(&sockin->sin_addr, hp->h_addr, hp->h_length); + ai->ai_addr->sa_family = hp->h_addrtype; +#ifdef HAVE_SA_LEN_IN_STRUCT_SOCKADDR + ai->ai_addr->sa_len = sizeof(struct sockaddr); +#endif + if (hints != NULL && hints->ai_flags & AI_CANONNAME) { + ai->ai_canonname = malloc(strlen(hp->h_name)); + if (ai->ai_canonname == NULL) + return (EAI_MEMORY); + strcpy(ai->ai_canonname, hp->h_name); + } + return (0); +} + /* * ipv4_aton - return a net number (this is crude, but careful) */ diff --git a/ntpdc/ntpdc.c b/ntpdc/ntpdc.c index 0d5fce9ca6..e1ce46ffe5 100644 --- a/ntpdc/ntpdc.c +++ b/ntpdc/ntpdc.c @@ -411,15 +411,6 @@ openhost( char name[LENHOSTNAME]; char service[5]; - memset((char *)&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = AI_CANONNAME; -#ifdef AI_ADDRCONFIG - hints.ai_flags |= AI_ADDRCONFIG; -#endif - hints.ai_family = ai_fam_templ; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_socktype = SOCK_DGRAM; - /* * We need to get by the [] if they were entered */ @@ -434,8 +425,28 @@ openhost( hname = name; } + /* + * First try to resolve it as an ip address and if that fails, + * do a fullblown (dns) lookup. That way we only use the dns + * when it is needed and work around some implementations that + * will return an "IPv4-mapped IPv6 address" address if you + * give it an IPv4 address to lookup. + */ sprintf(service, "%u", NTP_PORT); - a_info = getaddrinfo(hname, service, &hints, &ai); + memset((char *)&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = ai_fam_templ; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + + a_info = getaddrinfo(hname, service, &hints, &ai); + if (a_info == EAI_NONAME) { + hints.ai_flags = AI_CANONNAME; +#ifdef AI_ADDRCONFIG + hints.ai_flags |= AI_ADDRCONFIG; +#endif + a_info = getaddrinfo(hname, service, &hints, &ai); + } /* Some older implementations don't like AI_ADDRCONFIG. */ if (a_info == EAI_BADFLAGS) { hints.ai_flags = AI_CANONNAME; diff --git a/ntpq/ntpq.c b/ntpq/ntpq.c index c9b4af94fa..03d4a8e5a3 100644 --- a/ntpq/ntpq.c +++ b/ntpq/ntpq.c @@ -592,15 +592,6 @@ openhost( char name[LENHOSTNAME]; char service[5]; - memset((char *)&hints, 0, sizeof(struct addrinfo)); - hints.ai_flags = AI_CANONNAME; -#ifdef AI_ADDRCONFIG - hints.ai_flags |= AI_ADDRCONFIG; -#endif - hints.ai_family = ai_fam_templ; - hints.ai_protocol = IPPROTO_UDP; - hints.ai_socktype = SOCK_DGRAM; - /* * We need to get by the [] if they were entered */ @@ -615,8 +606,28 @@ openhost( hname = name; } + /* + * First try to resolve it as an ip address and if that fails, + * do a fullblown (dns) lookup. That way we only use the dns + * when it is needed and work around some implementations that + * will return an "IPv4-mapped IPv6 address" address if you + * give it an IPv4 address to lookup. + */ sprintf(service, "%u", NTP_PORT); + memset((char *)&hints, 0, sizeof(struct addrinfo)); + hints.ai_family = ai_fam_templ; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_NUMERICHOST; + a_info = getaddrinfo(hname, service, &hints, &ai); + if (a_info == EAI_NONAME) { + hints.ai_flags = AI_CANONNAME; +#ifdef AI_ADDRCONFIG + hints.ai_flags |= AI_ADDRCONFIG; +#endif + a_info = getaddrinfo(hname, service, &hints, &ai); + } /* Some older implementations don't like AI_ADDRCONFIG. */ if (a_info == EAI_BADFLAGS) { hints.ai_flags = AI_CANONNAME;