From: Bruno Haible Date: Sat, 1 Apr 2023 15:14:43 +0000 (+0200) Subject: hostname: Use more modern network APIs. X-Git-Tag: v0.22~90 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c5cdf41d436261b279c172753ac727335d44b9fd;p=thirdparty%2Fgettext.git hostname: Use more modern network APIs. Reported by Jens Petersen at . * autogen.sh (GNULIB_MODULES_TOOLS_FOR_SRC): Add getaddrinfo. * gettext-tools/src/hostname.c (HAVE_GETADDRINFO): Define to 1. Do the #includes for gethostname() after those for getaddrinfo(). (ipv4_is_linklocal, ipv6_is_linklocal): New functions. (print_hostname): For long_format and ip_format, prefer getaddrinfo over gethostbyname. * gettext-tools/src/Makefile.am (hostname_LDADD): New variable. --- diff --git a/autogen.sh b/autogen.sh index f63348ff4..76a276bdb 100755 --- a/autogen.sh +++ b/autogen.sh @@ -166,6 +166,7 @@ if ! $skip_gnulib; then full-write fwriteerror gcd + getaddrinfo getline getopt-gnu gettext diff --git a/gettext-tools/src/Makefile.am b/gettext-tools/src/Makefile.am index 59af8aaa7..0d6979fe2 100644 --- a/gettext-tools/src/Makefile.am +++ b/gettext-tools/src/Makefile.am @@ -377,6 +377,7 @@ msgfilter_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msggrep_LDADD = $(LIBGREP) libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msginit_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) msguniq_LDADD = libgettextsrc.la @INTL_MACOSX_LIBS@ $(WOE32_LDADD) +hostname_LDADD = $(LDADD) $(GETADDRINFO_LIB) # Specify when to relink the programs. msgcmp_DEPENDENCIES = libgettextsrc.la ../gnulib-lib/libgettextlib.la $(WOE32_LDADD) diff --git a/gettext-tools/src/hostname.c b/gettext-tools/src/hostname.c index e90963761..fa26b5304 100644 --- a/gettext-tools/src/hostname.c +++ b/gettext-tools/src/hostname.c @@ -1,5 +1,5 @@ /* Display hostname in various forms. - Copyright (C) 2001-2003, 2006-2007, 2012, 2014, 2018-2022 Free Software + Copyright (C) 2001-2003, 2006-2007, 2012, 2014, 2018-2023 Free Software Foundation, Inc. Written by Bruno Haible , 2001. @@ -32,30 +32,18 @@ # define WIN32_NATIVE #endif -/* Get gethostname(). */ -#include - -#ifdef WIN32_NATIVE -/* Native Woe32 API lacks gethostname() but has GetComputerName() instead. */ -# include -#else -/* Some systems, like early Solaris versions, lack gethostname() but - have uname() instead. */ -# if !HAVE_GETHOSTNAME -# include -# endif -#endif -/* Get MAXHOSTNAMELEN. */ -#if HAVE_SYS_PARAM_H -# include -#endif -#ifndef MAXHOSTNAMELEN -# define MAXHOSTNAMELEN 64 -#endif +/* We use the getaddrinfo and getnameinfo implementation from gnulib. */ +#define HAVE_GETADDRINFO 1 +/* Support for using getaddrinfo() and getnameinfo(). */ +#if HAVE_GETADDRINFO +# include +# include /* defines AF_INET, AF_INET6 */ +# include /* declares getaddrinfo(), getnameinfo() */ +# include /* defines struct sockaddr_in, struct sockaddr_in6 */ /* Support for using gethostbyname(). */ -#if HAVE_GETHOSTBYNAME +#elif HAVE_GETHOSTBYNAME # include # include /* defines AF_INET, AF_INET6 */ # include /* declares ntohs(), defines struct sockaddr_in */ @@ -78,6 +66,33 @@ # include /* defines struct hostent, declares gethostbyname() */ #endif + +/* Do these includes after the network-related ones, because on native Windows, + the #include must precede the #include . */ + +/* Get gethostname(). */ +#include + +#ifdef WIN32_NATIVE +/* Native Woe32 API lacks gethostname() but has GetComputerName() instead. */ +# include +#else +/* Some systems, like early Solaris versions, lack gethostname() but + have uname() instead. */ +# if !HAVE_GETHOSTNAME +# include +# endif +#endif + +/* Get MAXHOSTNAMELEN. */ +#if HAVE_SYS_PARAM_H +# include +#endif +#ifndef MAXHOSTNAMELEN +# define MAXHOSTNAMELEN 64 +#endif + + /* Include this after , to avoid a syntax error on BeOS. */ #include @@ -314,16 +329,31 @@ xgethostname () # endif #endif +/* Tests whether an IPv4 address is link-local. */ +static bool +ipv4_is_linklocal (const struct in_addr *addr) +{ + return (((const unsigned char *) addr)[0] == 169) + && (((const unsigned char *) addr)[1] == 254); +} + +#if HAVE_IPV6 +/* Tests whether an IPv6 address is link-local. */ +static bool +ipv6_is_linklocal (const struct in6_addr *addr) +{ + /* Cf. IN6_IS_ADDR_LINKLOCAL macro. */ + return (((const unsigned char *) addr)[0] == 0xFE) + && ((((const unsigned char *) addr)[1] & 0xC0) == 0x80); +} +#endif + /* Print the hostname according to the specified format. */ static void print_hostname () { char *hostname; char *dot; -#if HAVE_GETHOSTBYNAME - struct hostent *h; - size_t i; -#endif hostname = xgethostname (); @@ -343,44 +373,135 @@ print_hostname () break; case long_format: +#if HAVE_GETADDRINFO + /* Look for netwide usable hostname and aliases using getaddrinfo(). + getnameinfo() is not even needed. */ + { + struct addrinfo hints; + struct addrinfo *res; + int ret; + + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; /* either AF_INET or AF_INET6 is ok */ + hints.ai_socktype = SOCK_STREAM; /* or SOCK_DGRAM or 0 */ + hints.ai_protocol = 0; /* any protocol is ok */ + hints.ai_flags = AI_CANONNAME; + + ret = getaddrinfo (hostname, NULL, &hints, &res); + if (ret == 0) + { + struct addrinfo *p; + + for (p = res; p != NULL; p = p->ai_next) + { + /* Typically p->ai_socktype == SOCK_STREAM, p->ai_protocol == IPPROTO_TCP, + or p->ai_socktype == SOCK_DGRAM, p->ai_protocol == IPPROTO_UDP. */ + /* p->ai_canonname is only set on the first 'struct addrinfo'. */ + if (p->ai_canonname != NULL) + printf ("%s\n", p->ai_canonname); + } + + freeaddrinfo (res); + } + else + printf ("%s\n", hostname); + } +#elif HAVE_GETHOSTBYNAME /* Look for netwide usable hostname and aliases using gethostbyname(). */ -#if HAVE_GETHOSTBYNAME - h = gethostbyname (hostname); - if (h != NULL) - { - printf ("%s\n", h->h_name); - if (h->h_aliases != NULL) - for (i = 0; h->h_aliases[i] != NULL; i++) - printf ("%s\n", h->h_aliases[i]); - } - else + { + struct hostent *h; + size_t i; + + h = gethostbyname (hostname); + if (h != NULL) + { + printf ("%s\n", h->h_name); + if (h->h_aliases != NULL) + for (i = 0; h->h_aliases[i] != NULL; i++) + printf ("%s\n", h->h_aliases[i]); + } + else + printf ("%s\n", hostname); + } +#else + printf ("%s\n", hostname); #endif - printf ("%s\n", hostname); break; case ip_format: - /* Look for netwide usable IP addresses using gethostbyname(). */ -#if HAVE_GETHOSTBYNAME - h = gethostbyname (hostname); - if (h != NULL && h->h_addr_list != NULL) - for (i = 0; h->h_addr_list[i] != NULL; i++) +#if HAVE_GETADDRINFO + /* Look for netwide usable IP addresses using getaddrinfo() and + getnameinfo(). */ + { + struct addrinfo hints; + struct addrinfo *res; + int ret; + char host[1025]; + + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; /* either AF_INET or AF_INET6 is ok */ + hints.ai_socktype = SOCK_STREAM; /* or SOCK_DGRAM */ + hints.ai_protocol = 0; /* any protocol is ok */ + hints.ai_flags = 0; + + ret = getaddrinfo (hostname, NULL, &hints, &res); + if (ret == 0) { -#if HAVE_IPV6 - if (h->h_addrtype == AF_INET6) - { - char buffer[45+1]; - ipv6_ntop (buffer, *(const struct in6_addr*) h->h_addr_list[i]); - printf("[%s]\n", buffer); - } - else -#endif - if (h->h_addrtype == AF_INET) + struct addrinfo *p; + + for (p = res; p != NULL; p = p->ai_next) { - char buffer[15+1]; - ipv4_ntop (buffer, *(const struct in_addr*) h->h_addr_list[i]); - printf("[%s]\n", buffer); + /* Typically p->ai_socktype == SOCK_STREAM, p->ai_protocol == IPPROTO_TCP, + or p->ai_socktype == SOCK_DGRAM, p->ai_protocol == IPPROTO_UDP. */ + /* Ignore link-local addresses. + . */ + if (!((p->ai_family == AF_INET + && ipv4_is_linklocal (&((const struct sockaddr_in *) p->ai_addr)->sin_addr)) +# if HAVE_IPV6 + || (p->ai_family == AF_INET6 + && ipv6_is_linklocal (&((const struct sockaddr_in6 *) p->ai_addr)->sin6_addr)) +# endif + ) ) + if (getnameinfo (p->ai_addr, p->ai_addrlen, + host, sizeof (host), + NULL, 0, + NI_NUMERICHOST) + == 0) + { + printf ("[%.*s]\n", (int) sizeof (host), host); + } } + + freeaddrinfo (res); } + } +#elif HAVE_GETHOSTBYNAME + /* Look for netwide usable IP addresses using gethostbyname(). */ + { + struct hostent *h; + size_t i; + + h = gethostbyname (hostname); + if (h != NULL && h->h_addr_list != NULL) + for (i = 0; h->h_addr_list[i] != NULL; i++) + { +# if HAVE_IPV6 + if (h->h_addrtype == AF_INET6) + { + char buffer[45+1]; + ipv6_ntop (buffer, *(const struct in6_addr*) h->h_addr_list[i]); + printf("[%s]\n", buffer); + } + else +# endif + if (h->h_addrtype == AF_INET) + { + char buffer[15+1]; + ipv4_ntop (buffer, *(const struct in_addr*) h->h_addr_list[i]); + printf("[%s]\n", buffer); + } + } + } #endif break;