summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruno Haible <bruno@clisp.org>2023-04-01 17:14:43 +0200
committerBruno Haible <bruno@clisp.org>2023-04-01 17:14:43 +0200
commitc5cdf41d436261b279c172753ac727335d44b9fd (patch)
tree683471c293193efb703f178b6c41b366f3fe4a02
parent2d1963afbf456ea8ac21378a814d5230f41eeb72 (diff)
downloadgettext-c5cdf41d436261b279c172753ac727335d44b9fd.tar.gz
hostname: Use more modern network APIs.
Reported by Jens Petersen <petersen@redhat.com> at <https://savannah.gnu.org/bugs/?63983>. * 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.
-rwxr-xr-xautogen.sh1
-rw-r--r--gettext-tools/src/Makefile.am1
-rw-r--r--gettext-tools/src/hostname.c231
3 files changed, 178 insertions, 55 deletions
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 <haible@clisp.cons.org>, 2001.
@@ -32,30 +32,18 @@
# define WIN32_NATIVE
#endif
-/* Get gethostname(). */
-#include <unistd.h>
-
-#ifdef WIN32_NATIVE
-/* Native Woe32 API lacks gethostname() but has GetComputerName() instead. */
-# include <windows.h>
-#else
-/* Some systems, like early Solaris versions, lack gethostname() but
- have uname() instead. */
-# if !HAVE_GETHOSTNAME
-# include <sys/utsname.h>
-# endif
-#endif
-/* Get MAXHOSTNAMELEN. */
-#if HAVE_SYS_PARAM_H
-# include <sys/param.h>
-#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 <sys/types.h>
+# include <sys/socket.h> /* defines AF_INET, AF_INET6 */
+# include <netdb.h> /* declares getaddrinfo(), getnameinfo() */
+# include <netinet/in.h> /* defines struct sockaddr_in, struct sockaddr_in6 */
/* Support for using gethostbyname(). */
-#if HAVE_GETHOSTBYNAME
+#elif HAVE_GETHOSTBYNAME
# include <sys/types.h>
# include <sys/socket.h> /* defines AF_INET, AF_INET6 */
# include <netinet/in.h> /* declares ntohs(), defines struct sockaddr_in */
@@ -78,6 +66,33 @@
# include <netdb.h> /* defines struct hostent, declares gethostbyname() */
#endif
+
+/* Do these includes after the network-related ones, because on native Windows,
+ the #include <winsock2.h> must precede the #include <windows.h>. */
+
+/* Get gethostname(). */
+#include <unistd.h>
+
+#ifdef WIN32_NATIVE
+/* Native Woe32 API lacks gethostname() but has GetComputerName() instead. */
+# include <windows.h>
+#else
+/* Some systems, like early Solaris versions, lack gethostname() but
+ have uname() instead. */
+# if !HAVE_GETHOSTNAME
+# include <sys/utsname.h>
+# endif
+#endif
+
+/* Get MAXHOSTNAMELEN. */
+#if HAVE_SYS_PARAM_H
+# include <sys/param.h>
+#endif
+#ifndef MAXHOSTNAMELEN
+# define MAXHOSTNAMELEN 64
+#endif
+
+
/* Include this after <sys/socket.h>, to avoid a syntax error on BeOS. */
#include <stdbool.h>
@@ -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.
+ <https://en.wikipedia.org/wiki/Link-local_address>. */
+ 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;