tisdag den 18 januari 2011 klockan 12:19 skrev Alfred M. Szmidt detta:
> 
> If something is wraped around a CPP conditional, then we can write:
> 
> (open_socket) [HAVE_DECL_GETADDRINFO && HAVE_IPV6]: ...

Good. Adapted in new patch suggestion.

> 
>    @@ -244,6 +371,10 @@ const char args_doc[] =3D "[MESSAGE]";
>     const char doc[] =3D "Send messages to syslog";
>    =20
>     static struct argp_option argp_options[] =3D {
>    +#if HAVE_IPV6
>    +  {"ipv4", '4', NULL, 0, "use IPv4 for logging to host" },
>    +  {"ipv6", '6', NULL, 0, "use IPv6 with a host target" },
>    +#endif
> 
> What do you think about issuing a warning if IPv6 is not supported,
> and falling back on IPv4?  It is nice if one can move scripts between
> systems, without having to tweak them.  Mayve skip the two short
> options, they don't seem to be very useful to me; or do other logger
> implementations support them?

This is a splendid idea. Now both are implemented, but '--ipv6' prints
a warning message to STDOUT and falls back to IPv4 if the system is
not compiled with IPv6 support.

FreeBSD implements options '-4' and '-6', but not long options.
OpenBSD, NetBSD, and bsdutils (hence Debian GNU/Linux and GNU/kFreeBSD)
are not able to send log messages to a host at all, only to UNIX sockets!
In this sense IU-logger is at the very forefront.

Doing this revision I did improve on the informative content for
the error messages that can be generated from my code. In addition,
I managed to cover for a segfault in libc-freebsd, which is forgiven
bt glibc, so the additional wark payed off very well.

A revised patch suggestion is included. Again tested on Linux, OpenBSD,
FreeBSD, and kFreeBSD. Using "#undef HAVE_IPV6" I did even simulate
crippled systems. The fallback mechanism works well.

Best regards,
  Mats
From ce65858ffdfd68ed76208f7968636a7af5d0858e Mon Sep 17 00:00:00 2001
From: Mats Erik Andersson <[email protected]>
Date: Wed, 19 Jan 2011 01:35:33 +0100
Subject: [PATCH] logger: Implement support for transport via IPv6.

---
 ChangeLog          |   11 ++++
 doc/inetutils.texi |   50 ++++++++++++-----
 src/logger.c       |  159 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 3 files changed, 201 insertions(+), 19 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c474101..110d348 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2011-01-19  Mats Erik Andersson <[email protected]>
+
+	* src/logger.c (host_family) [HAVE_DECL_GETADDRINFO]: New variable.
+	(struct logger_sockaddr) [HAVE_IPV6]: New component SINET6.
+	(open_socket) [HAVE_DECL_GETADDRINFO]: Implement new code based
+	on getaddrinfo.  Reorganize old handler of port specification.
+	(argp_options): New options `--ipv4' and `--ipv6`.
+	(parse_opt): Implement parsing of new options.
+	* doc/inetutils.texi (logger): Describe implications of
+	IPv6-support and fallback.  Small corrections to example usage.
+
 2010-12-21  Mats Erik Andersson <[email protected]>
 
 	* src/inetd.c (pidfile_option): New variable.
diff --git a/doc/inetutils.texi b/doc/inetutils.texi
index 7249bbf..19e5f88 100644
--- a/doc/inetutils.texi
+++ b/doc/inetutils.texi
@@ -287,6 +287,25 @@ logger [@var{option}@dots{}] [@var{message}]
 @end example
 
 @table @option
+@item -4
+@itemx --ipv4
+@opindex -4
+@opindex --ipv4
+Use IPv4 as transport when logging to a host.  The default behaviour
+is to use whatever IP version that matches the host.
+
+@item -6
+@itemx --ipv6
+@opindex -6
+@opindex --ipv6
+Use IPv6 as transport when logging to a host.  The option is present
+also on systems without support for IPv6, but will then issue a warning
+and then fall back to IPv4 when delivering the message.
+
+Both options are most influencial when the target host is named using
+a symbolic name, but numerical addresses for host or source must also
+match if either of @option{--ipv4} or @option{--ipv6} is stated.
+
 @item -i[@var{pid}]
 @itemx --id=[@var{pid}]
 @opindex -i
@@ -303,26 +322,29 @@ must be separated from it by exactly one equals sign.
 @opindex -h
 @opindex --host
 Send messages to the given host or socket.  The @var{host} argument
-can be either a local UNIX socket name (always starting with a
-@samp{/} or:
+can be either a local UNIX socket name (starting with a dash @samp{/}),
+or:
 
 @smallexample
 @var{host}[:@var{port}]
 @end smallexample
 
 @noindent
-where @var{host} is the remote host name or IP address (only IPv4 is
-supported so far), and optional @var{port} is a decimal port number or
-symbolic service name from @file{/etc/services}.  If @var{port} is not
-specified, the port number corresponding to the @samp{syslog} service
-is used.
+where @var{host} is the remote host name or IP address, and the
+optional @var{port} is a decimal port number or symbolic service
+name from @file{/etc/services}.  If @var{port} is not specified,
+the port number corresponding to the @samp{syslog} service is used.
+If a numerical IPv6 address is given without a port specification,
+then the address must be enclosed within brackets (like [::1]).
 
 @item -S @var{addr}
 @itemx --source=@var{addr}
 @opindex -S
 @opindex --source
 Supply the source IP address for INET connections.  This option is
-useful in conjunction with @option{--host} (see above).
+useful in conjunction with @option{--host} (see above).  The kind of
+address specified here (IPv4 or IPv6) will propagate to influence
+the resolution of the host address, if it is a symbolic name.
 
 @item -s
 @itemx --stderr
@@ -366,23 +388,23 @@ The following examples illustrate the usage of the @command{logger}
 command:
 
 @enumerate 1
-@item Log the @samp{System rebooted} message to the local syslog. Use
-the default facility and priority:
+@item Log the message @samp{System rebooted} to the local syslog.
+Use default facility and priority:
 
 @example
 logger System rebooted
 @end example
 
 @item Run command and send its error output to the channel
-@samp{local0.err} channel.  Mark each message with tag @samp{cmd}:
+@samp{local0.err}.  Mark each message with tag @samp{cmd}:
 
 @example
 command 2>&1 | logger -p local0.notice -t cmd
 @end example
 
-@item Log each line from file @file{warnings} to @samp{daemon.warn}
-channel on host @samp{logger.runasimi.org}, using the source IP
-@samp{10.10.10.1}:
+@item Log each line from file @file{warnings} to channel
+@samp{daemon.warn} on host @samp{logger.runasimi.org},
+using the source IP @samp{10.10.10.1}:
 
 @example
 logger -p daemon.warn -h logger.runasimi.org -S 10.10.10.1 --file
diff --git a/src/logger.c b/src/logger.c
index f112334..80dd7a1 100644
--- a/src/logger.c
+++ b/src/logger.c
@@ -56,6 +56,15 @@ static char *host = PATH_LOG;
 static char *source;
 static char *pidstr;
 
+#if HAVE_DECL_GETADDRINFO
+# if HAVE_IPV6
+static int host_family = AF_UNSPEC;
+# else
+/* Fall back to only IPv4.  */
+static int host_family = AF_INET;
+# endif /* !HAVE_IPV6 */
+#endif /* HAVE_DECL_GETADDRINFO */
+
 
 
 int
@@ -104,6 +113,9 @@ union logger_sockaddr
   {
     struct sockaddr sa;
     struct sockaddr_in sinet;
+#if HAVE_IPV6
+    struct sockaddr_in6 sinet6;
+#endif
     struct sockaddr_un sunix;
 };
 
@@ -115,6 +127,9 @@ open_socket (void)
   union logger_sockaddr sockaddr;
   socklen_t socklen;
   int family;
+#if HAVE_DECL_GETADDRINFO
+  int ret;
+#endif
 
   if (host[0] == '/')
     {
@@ -128,14 +143,129 @@ open_socket (void)
     }
   else
     {
+#if HAVE_DECL_GETADDRINFO
+      struct addrinfo hints, *ai, *res;
+#else
       struct hostent *hp;
       struct servent *sp;
       unsigned short port;
+#endif /* !HAVE_DECL_GETADDRINFO */
       char *p;
 
+#if HAVE_IPV6
+      /* Bare, numeric IPv6 addresses must be contained
+       * in brackets in order that an appended port not
+       * be read by mistake.  */
+      if (*host == '[')
+	{
+	  ++host;
+	  p = strchr (host, ']');
+	  if (p)
+	    {
+	      *p++ = '\0';
+	      if (*p == ':')
+		++p;
+	      else
+		p = NULL;
+	    }
+	}
+      else
+        {
+	  /* When no bracket was detected, then seek the
+	   * right-most colon character in order to correctly
+	   * parse IPv6 addresses.  */
+	  p = strrchr (host, ':');
+	  if (p)
+	    *p++ = 0;
+	}
+#else /* !HAVE_IPV6 */
       p = strchr (host, ':');
       if (p)
 	*p++ = 0;
+#endif /* !HAVE_IPV6 */
+
+      if (!p)
+	p = "syslog";
+
+#if HAVE_DECL_GETADDRINFO
+      memset (&hints, 0, sizeof (hints));
+      hints.ai_socktype = SOCK_DGRAM;
+
+      /* This falls back to AF_INET if compilation
+       * was made with !HAVE_IPV6.  */
+      hints.ai_family = host_family;
+
+# ifdef AI_ADDRCONFIG
+      hints.ai_flags = AI_ADDRCONFIG;
+# endif
+
+      /* The complete handshake is attempted within
+       * a single while-loop, since the answers from
+       * getaddrinfo() need to be checked in detail.  */
+      ret = getaddrinfo (host, p, &hints, &res);
+      if (ret < 0)
+	error (EXIT_FAILURE, 0, "%s, %s:%s.", gai_strerror(ret), host, p);
+
+      for (ai = res; ai; ai = ai->ai_next)
+        {
+	  fd = socket (ai->ai_family, ai->ai_socktype, ai->ai_protocol);
+	  if (fd < 0)
+	    continue;
+
+	  if (source)
+	    {
+	      /* Make the assumption that the source address
+	       * encodes a desired domain family and that it
+	       * be numeric.  */
+	      int ret;
+	      struct addrinfo tips, *a;
+
+	      memset (&tips, 0, sizeof (tips));
+	      tips.ai_family = ai->ai_family;
+	      tips.ai_flags = AI_NUMERICHOST;
+
+	      ret = getaddrinfo(source, NULL, &tips, &a);
+	      if (ret)
+		{
+		  close (fd);
+		  continue;
+		}
+
+	      if (bind (fd, a->ai_addr, a->ai_addrlen))
+		{
+		  freeaddrinfo (a);
+		  close (fd);
+		  continue;
+		}
+
+	      freeaddrinfo (a);
+	    }
+
+	  if (connect (fd, ai->ai_addr, ai->ai_addrlen))
+	    {
+	      close (fd);
+	      continue;
+	    }
+
+	  /* Socket standing, bound and connected.  */
+	  break;
+	}
+
+      if (res)
+	freeaddrinfo (res);
+
+      if (ai == NULL)
+	error (EXIT_FAILURE, EADDRNOTAVAIL, "%s:%s", host, p);
+
+      /* Existing socket can be returned now.
+       * This handles AF_INET and AF_INET6 in case
+       * HAVE_DECL_GETADDRINFO is true.  */
+      return;
+
+#else /* !HAVE_DECL_GETADDRINFO */
+
+      sockaddr.sinet.sin_family = AF_INET;
+      family = PF_INET;
 
       hp = gethostbyname (host);
       if (hp)
@@ -144,11 +274,6 @@ open_socket (void)
 	       != 1)
 	error (EXIT_FAILURE, 0, "unknown host name");
 
-      sockaddr.sinet.sin_family = AF_INET;
-      family = PF_INET;
-      if (!p)
-	p = "syslog";
-
       if (isdigit (*p))
 	{
 	  char *end;
@@ -163,9 +288,14 @@ open_socket (void)
 	error (EXIT_FAILURE, 0, "%s: unknown service name", p);
 
       sockaddr.sinet.sin_port = port;
+#endif /* !HAVE_DECL_GETADDRINFO */
+
       socklen = sizeof (sockaddr.sinet);
     }
 
+  /* Execution arrives here for AF_UNIX and for
+   * situations with !HAVE_DECL_GETADDRINFO.  */
+
   fd = socket (family, SOCK_DGRAM, 0);
   if (fd < 0)
     error (EXIT_FAILURE, errno, "cannot create socket");
@@ -244,6 +374,8 @@ const char args_doc[] = "[MESSAGE]";
 const char doc[] = "Send messages to syslog";
 
 static struct argp_option argp_options[] = {
+  {"ipv4", '4', NULL, 0, "use IPv4 for logging to host" },
+  {"ipv6", '6', NULL, 0, "use IPv6 with a host target" },
   { "host", 'h', "HOST", 0,
     "log to host instead of the default " PATH_LOG },
   { "source", 'S', "IP", 0,
@@ -264,6 +396,23 @@ parse_opt (int key, char *arg, struct argp_state *state)
 {
   switch (key)
     {
+    case '4':
+      host_family = AF_INET;
+      break;
+
+    case '6':
+#if HAVE_IPV6
+      host_family = AF_INET6;
+      break;
+
+#else /* !HAVE_IPV6 */
+      /* Print a warning but continue with IPv4.  */
+      error (EXIT_SUCCESS, 0, "Warning: Falling back to IPv4, "
+		"since IPv6 is disabled.");
+      /* AF_INET is set by default in this case.  */
+      break;
+#endif /* !HAVE_IPV6 */
+
     case 'h':
       host = arg;
       break;
-- 
1.7.2.3

Attachment: signature.asc
Description: Digital signature

Reply via email to