bug-inetutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[bug-inetutils] New IPv6 patch for inetutils


From: Jeroen Dekkers
Subject: [bug-inetutils] New IPv6 patch for inetutils
Date: Wed, 07 Jul 2004 00:20:55 +0200
User-agent: Wanderlust/2.10.1 (Watching The Wheels) SEMI/1.14.6 (Maruoka) FLIM/1.14.6 (Marutamachi) APEL/10.6 Emacs/21.3.50 (i686-pc-linux-gnu) MULE/5.0 (SAKAKI)

Hey,

Here is a new IPv6 patch for inetutils. It's actually the same except
that this patch also adds ping6. Comments/suggestions/bugfixes/etc are
welcome. 


2004-07-06  Jeroen Dekkers  <address@hidden>

        * acinclude.m4 (IU_ENABLE_FOO): Use AS_HELP_STRING.
        (IU_CHECK_KRB5): Quote correctly.
        
        * configure.ac: Add checks for IPv6.

doc/
2004-07-06  Jeroen Dekkers  <address@hidden>

        * inetd.texi (inetd): Document IPv6 configuration options.

inetd/
2004-07-06  Jeroen Dekkers  <address@hidden>

        * inetd.c: Move global variable sp to...
        (nextconfig): Here. Only use the getservbyname code when
        [!IPV6]. Remove unused variable i.
        (struct servtab): Change type of to pid_t. Add se_family.
        [IPV6] Add se_v4mapped. Change se_ctrladdr to struct
        sockaddr_storage.
        (setup): Add support for IPv6.
        (INETD_FIELDS_MIN): Define to 6.
        (getconfigent): Add support for IPv6. Remove unused variable arg.
        (set_proc_title): Add support for IPv6.
        (echo_dg): Likewise.
        (chargen_dg): Likewise.
        (machtime_dg): Likewise.
        (daytime_dg): Likewise.

ping/
2004-07-06  Jeroen Dekkers  <address@hidden>

        * Makefile.am: Add ping6.
        (ping_SOURCES): Add ping_common.c and ping_common.h.
        * ping6.c: New file.
        * ping6.h: Likewise.
        * ping_common.c: Likewise.
        * ping_common.h: Likewise.
        * ping.c: Include "ping_common.h". Remove __P macro in
        prototypes.
        (ping_cvt_number, init_data_buffer,
         decode_pattern, show_license): Move to ...
        * ping_common.c: ... here.
        * ping_echo.c: Include "ping_common.h".
        (tvsub, nabs, nsqrt): Move to ...
        * ping_common.c: ... here.

telnet/
2004-07-06  Jeroen Dekkers  <address@hidden>

        * commands.c: Include <arpa/telnet.h>. Remove variable tos and
        _hostname.
        (tn): Rewritten. Removed support for source routing and added
        support for IPv6.
        (sourceroute): Function removed.
        * main.c (help): Add "-4" and "-6", remove "-S".
        (long_options): Add "ipv4" and "ipv6", remove "tos".
        (main): New variable family. Implement "-4" and "-6" options and
        remove "-S" option.

telnetd/
2004-07-06  Jeroen Dekkers  <address@hidden>

        * telnetd.c (telnetd_setup): Add support for IPv6.

Index: acinclude.m4
===================================================================
RCS file: /cvsroot/inetutils/inetutils/acinclude.m4,v
retrieving revision 1.11
diff -u -p -r1.11 acinclude.m4
--- acinclude.m4        30 Jan 2004 13:14:54 -0000      1.11
+++ acinclude.m4        6 Jul 2004 22:06:43 -0000
@@ -1,6 +1,6 @@
 dnl Autoconf macros used by inetutils
 dnl
-dnl Copyright (C) 1996, 1997, 1998, 2002 Free Software Foundation, Inc.
+dnl Copyright (C) 1996, 1997, 1998, 2002, 2004 Free Software Foundation, Inc.
 dnl
 dnl Mostly written by Miles Bader <address@hidden>
 dnl
@@ -457,7 +457,7 @@ EOF
   AC_SUBST_FILE([$3])])
 
 AC_DEFUN([IU_ENABLE_FOO],
- [AC_ARG_ENABLE($1, [  --disable-$1               don't compile $1], ,
+ [AC_ARG_ENABLE($1, AS_HELP_STRING([--disable-$1], [don't compile $1]), ,
                 [enable_]$1[=$enable_]$2)
 [if test "$enable_$1" = yes; then 
    $1_BUILD=$1
@@ -558,7 +558,7 @@ dnl if it is set and not "yes".
 dnl VERSION should be either 4 or 5
 dnl Defines KRB_CFLAGS and KRB_LIBS if found.
 dnl Defines KRB_IMPL to "Heimdal", "MIT", or "OldMIT", or "none" if not found
-AC_DEFUN(IU_CHECK_KRB5,
+AC_DEFUN([IU_CHECK_KRB5],
 [
  if test "x$iu_cv_lib_krb5_libs" = x; then
   cache=""
Index: configure.ac
===================================================================
RCS file: /cvsroot/inetutils/inetutils/configure.ac,v
retrieving revision 1.19
diff -u -p -r1.19 configure.ac
--- configure.ac        30 Jan 2004 13:15:24 -0000      1.19
+++ configure.ac        6 Jul 2004 22:06:43 -0000
@@ -1,6 +1,6 @@
 # Configuration for inetutils
 #
-# Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002 Free Software 
Foundation, Inc.
+# Copyright (C) 1995, 1996, 1997, 1998, 2000, 2001, 2002, 2004 Free Software 
Foundation, Inc.
 #
 # Written by Miles Bader <address@hidden>
 #
@@ -74,6 +74,7 @@ IU_ENABLE_SERVER(uucpd)
 
 IU_ENABLE_CLIENT(ftp)
 IU_ENABLE_CLIENT(ping)
+IU_ENABLE_CLIENT(ping6)
 IU_ENABLE_CLIENT(rcp)
 IU_ENABLE_CLIENT(rlogin)
 IU_ENABLE_CLIENT(rsh)
@@ -282,6 +283,111 @@ if test ".$LIBAUTH" != .; then
                    [Define to one if you want encryption.])
 fi
 
+dnl Checks for IPv6 support.
+
+AC_ARG_ENABLE(ipv6,
+  AS_HELP_STRING([--disable-ipv6], [disable IPv6 support]),
+  [case "${enable_ipv6}" in
+  no)
+    AC_MSG_NOTICE([Disabling IPv6 at user request])
+    ipv6=no
+    ;;
+  *)
+    ipv6=yes
+    ;;
+  esac],
+  [ipv6=auto]
+)
+
+working_ipv6=yes
+if test ! "X$ipv6" = "Xno" -a "X$working_ipv6" = "Xyes"; then
+  IU_CHECK_MACRO(AF_INET6, [#include <sys/socket.h>], , , working_ipv6=no)
+fi
+
+if test ! "X$ipv6" = "Xno" -a "X$working_ipv6" = "Xyes"; then
+  IU_CHECK_MACRO(IPV6_V6ONLY, [#include <netinet/in.h>], , , working_ipv6=no)
+fi
+
+if test ! "X$ipv6" = "Xno" -a "X$working_ipv6" = "Xyes"; then
+  AC_CHECK_TYPE(struct sockaddr_storage, , working_ipv6=no, [#include 
<sys/socket.h>])
+fi
+
+if test ! "X$ipv6" = "Xno" -a "X$working_ipv6" = "Xyes"; then
+  AC_CHECK_TYPE(struct sockaddr_in6, , working_ipv6=no, [#include 
<netinet/in.h>])
+fi
+
+if test ! "X$ipv6" = "Xno" -a "X$working_ipv6" = "Xyes"; then
+  AC_CHECK_TYPE(struct addrinfo, , working_ipv6=no, [#include <netdb.h>])
+fi
+
+if test ! "X$ipv6" = "Xno" -a "X$working_ipv6" = "Xyes"; then
+  AC_CHECK_FUNC(getaddrinfo, ,working_ipv6=no, [#include <netdb.h>])
+fi
+
+if test ! "X$ipv6" = "Xno" -a "X$working_ipv6" = "Xyes"; then
+  AC_CHECK_FUNC(getnameinfo, ,working_ipv6=no, [#include <netdb.h>])
+fi
+
+if test ! "X$ipv6" = "Xno" -a "X$working_ipv6" = "Xyes"; then
+  AC_DEFINE(IPV6, 1, [Define to one if you want IPv6.])
+else 
+  if test "X$ipv6" = "Xyes"; then
+    AC_MSG_FAILURE([IPv6 support not available])
+  else 
+    if test "X$ipv6" = "Xauto"; then
+      AC_MSG_WARN([IPv6 support not available, disabling IPv6])
+    fi
+  fi
+fi
+
+if test "X$ipv6" = "Xno" -o "X$working_ipv6" = "Xno";then
+  ping6_BUILD=''
+else
+  working_icmp6=yes
+
+  AC_CHECK_HEADER(netinet/icmp6.h, , working_icmp6=no)
+
+  if test "X$working_icmp6" = "Xyes"; then
+    AC_CHECK_HEADER(netinet/ip6.h, , working_icmp6=no)
+  fi
+
+  if test "X$working_icmp6" = "Xyes"; then
+    AC_CHECK_TYPE(struct icmp6_filter, , working_icmp6=no, [#include 
<netinet/icmp6.h>])
+  fi
+
+  if test "X$working_icmp6" = "Xyes"; then
+    AC_CHECK_TYPE(struct icmp6_hdr, , working_icmp6=no, [#include 
<netinet/icmp6.h>])
+  fi
+
+  if test "X$working_icmp6" = "Xyes"; then
+    IU_CHECK_MACRO(IPV6_RECVHOPLIMIT, [#include <netinet/in.h>], ,
+                  [have_recvhoplimt=yes], [have_recvhoplimt=no])
+    if test "X$have_recvhoplimt" = "Xno"; then
+      IU_CHECK_MACRO(IPV6_HOPLIMIT, [#include <netinet/in.h>], , [
+        AC_DEFINE(IPV6_RECVHOPLIMIT, IPV6_HOPLIMIT,
+                  [Define to IPV6_HOPLIMIT if not available])
+      ], [working_icmp6=no])
+    fi
+  fi
+
+  if test "X$working_icmp6" = "Xyes"; then
+    IU_CHECK_MACRO(ICMP6_DST_UNREACH_BEYONDSCOPE, [#include 
<netinet/icmp6.h>], ,
+                  [have_beyondscope=yes], [have_beyondscope=no])
+    if test "X$have_beyondscope" = "Xno"; then
+      IU_CHECK_MACRO(ICMP6_DST_UNREACH_NOTNEIGHBOR, [#include 
<netinet/icmp6.h>], , [
+        AC_DEFINE(ICMP6_DST_UNREACH_BEYONDSCOPE, ICMP6_DST_UNREACH_NOTNEIGHBOR,
+                  [Define to ICMP6_DST_UNREACH_NOTNEIGHBOR if not available])
+      ], [working_icmp6=no])
+    fi
+  fi
+
+  if test "X$working_icmp6" = "Xno"; then
+    AC_MSG_WARN([ICMPv6 support not available, disabling ping6])
+    ping6_BUILD=''
+  fi
+fi
+
+
 dnl Check if they want support for Wrap.  Certain daemons like
 dnl ftpd have support for it.
 
Index: doc/inetd.texi
===================================================================
RCS file: /cvsroot/inetutils/inetutils/doc/inetd.texi,v
retrieving revision 1.1
diff -u -p -r1.1 inetd.texi
--- doc/inetd.texi      11 Nov 2001 03:07:23 -0000      1.1
+++ doc/inetd.texi      6 Jul 2004 22:06:43 -0000
@@ -78,8 +78,13 @@ or ``seqpacket'', depending on whether t
 raw, reliably delivered message, or sequenced packet socket.  TCPMUX services
 must use ``stream''.
 
-The protocol must be a valid protocol as given in /etc/protocols. Examples
-might be ``tcp'' or ``udp''. TCPMUX services must use ``tcp''.
+The protocol must be a valid protocol as given in /etc/protocols.
+Examples might be ``tcp'' or ``udp''.  TCPMUX services must use
+``tcp''.  If IPv6 support is enabled the sockets will accept both IPv4
+and IPv6 connections if that is supported by the OS.  If inetd should only
+accept IPv4 or IPv6 connections, add ``4'' or ``6'' to the protocol.
+For example ``tcp4'' will only accept IPv4 tcp connections and
+``udp6'' will only accept IPv6 udp connections.
 
 The wait/nowait entry specifies whether the server that is invoked by inetd
 will take over the socket associated with the service access point,
Index: inetd/inetd.c
===================================================================
RCS file: /cvsroot/inetutils/inetutils/inetd/inetd.c,v
retrieving revision 1.27
diff -u -p -r1.27 inetd.c
--- inetd/inetd.c       11 Nov 2003 15:16:32 -0000      1.27
+++ inetd/inetd.c       6 Jul 2004 22:06:43 -0000
@@ -1,5 +1,24 @@
+/* Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+
+   This file is part of GNU Inetutils.
+
+   GNU Inetutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU Inetutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Inetutils; see the file COPYING.  If not, write to
+   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
 /*
- * Copyright (c) 1983, 1991, 1993, 1994, 2002
+ * Copyright (c) 1983, 1991, 1993, 1994
  *     The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -144,13 +163,12 @@ fd_set    allsock;
 int    options;
 int    timingout;
 int    toomany = TOOMANY;
-struct servent *sp;
 
 struct servtab {
   char *se_service;            /* name of service */
   int  se_socktype;            /* type of socket to use */
   char *se_proto;              /* protocol used */
-  short        se_wait;                /* single threaded server */
+  pid_t        se_wait;                /* single threaded server */
   short        se_checked;             /* looked at during merge */
   char *se_user;               /* user name to run as */
   struct biltin *se_bi;                /* if built-in, description */
@@ -159,7 +177,13 @@ struct     servtab {
   size_t se_argc;               /* number of arguments */
   int  se_fd;                  /* open descriptor */
   int  se_type;                /* type */
+  sa_family_t se_family;       /* address family of the socket */
+  char se_v4mapped;            /* 1 = accept v4mapped connection, 0 = don't */
+#ifdef IPV6
+  struct sockaddr_storage se_ctrladdr;/* bound address */
+#else
   struct sockaddr_in se_ctrladdr;/* bound address */
+#endif
   int  se_count;               /* number started since se_time */
   struct       timeval se_time;        /* start of se_count */
   struct       servtab *se_next;
@@ -218,7 +242,7 @@ struct biltin {
   { "discard", SOCK_STREAM,    1, 0,   discard_stream },
   { "discard", SOCK_DGRAM,     0, 0,   discard_dg },
 
-  /* Return 32 bit time since 1970 */
+  /* Return 32 bit time since 1900 */
   { "time",    SOCK_STREAM,    0, 0,   machtime_stream },
   { "time",    SOCK_DGRAM,     0, 0,   machtime_dg },
 
@@ -267,7 +291,7 @@ signal_set_handler (int signo, RETSIGTYP
   struct sigvec sv;
   memset (&sv, 0, sizeof(sv));
   sv.sv_mask = SIGBLOCK;
-  sv.sv_handler = retry;
+  sv.sv_handler = handler;
   sigvec (signo, &sv, NULL);
 #else /* !HAVE_SIGVEC */
   signal (signo, handler);
@@ -708,6 +732,9 @@ config (int signo)
 void
 nextconfig (const char *file)
 {
+#ifndef IPV6
+  struct servent *sp;
+#endif
   struct servtab *sep, *cp, **sepp;
   struct passwd *pwd;
   FILE * fconfig;
@@ -737,8 +764,6 @@ nextconfig (const char *file)
          break;
       if (sep != 0)
        {
-         int i;
-
          signal_block (&sigstatus);
          /*
           * sep->se_wait may be holding the pid of a daemon
@@ -776,6 +801,7 @@ nextconfig (const char *file)
          sep->se_fd = -1;
          continue;
        }
+#ifndef IPV6 /* This code is moved to setup() for IPV6.  */
       sp = getservbyname (sep->se_service, sep->se_proto);
       if (sp == 0)
        {
@@ -791,6 +817,7 @@ nextconfig (const char *file)
          if (sep->se_fd >= 0)
            close_sep (sep);
        }
+#endif
       if (sep->se_fd == -1)
        setup (sep);
     }
@@ -833,27 +860,132 @@ retry (int signo)
 void
 setup (struct servtab *sep)
 {
-  int on = 1;
+  int err;
+  const int on = 1;
+#ifdef IPV6
+  const int off = 0;
+  struct addrinfo *result, hints;
+  struct protoent *proto;
 
-  if ((sep->se_fd = socket (AF_INET, sep->se_socktype, 0)) < 0)
+ tryagain:
+#endif
+  sep->se_fd = socket (sep->se_family, sep->se_socktype, 0);
+  if (sep->se_fd < 0)
     {
+#ifdef IPV6
+      /* If we don't support creating AF_INET6 sockets, create AF_INET
+        sockets.  */
+      if (errno == EAFNOSUPPORT && sep->se_family == AF_INET6 && 
sep->se_v4mapped)
+       {
+         /* Fall back to IPv6 silently.  */
+         sep->se_family = AF_INET;
+         goto tryagain;
+       }
+#endif
+      
       if (debug)
        fprintf (stderr, "socket failed on %s/%s: %s\n",
                 sep->se_service, sep->se_proto, strerror (errno));
       syslog(LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto);
       return;
     }
-#define        turnon(fd, opt) \
-setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
-  if (strcmp (sep->se_proto, "tcp") == 0 && (options & SO_DEBUG)
-      && turnon(sep->se_fd, SO_DEBUG) < 0)
-    syslog (LOG_ERR, "setsockopt (SO_DEBUG): %m");
-  if (turnon (sep->se_fd, SO_REUSEADDR) < 0)
-    syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
-#undef turnon
-  if (bind (sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
-           sizeof (sep->se_ctrladdr)) < 0)
+
+#ifdef IPV6
+  /* Make sure that tcp6 etc also work.  */
+  if (strncmp (sep->se_proto, "tcp", 3) == 0)
+    proto = getprotobyname ("tcp");
+  else if (strncmp (sep->se_proto, "udp", 3) == 0)
+    proto = getprotobyname ("udp");
+  else
+    proto = getprotobyname (sep->se_proto);
+   
+  if (!proto)
+    {
+      syslog (LOG_ERR, "%s: Unknown protocol", sep->se_proto);
+      close (sep->se_fd);
+      sep->se_fd = -1;
+      return;
+    }
+  
+  memset (&hints, 0, sizeof (hints));
+
+  hints.ai_flags = AI_PASSIVE;
+  hints.ai_family = sep->se_family;
+  hints.ai_socktype = sep->se_socktype;
+  hints.ai_protocol = proto->p_proto;
+
+  err = getaddrinfo (NULL, sep->se_service, &hints, &result);
+  if (err)
+    {
+      const char *errmsg;
+
+      if (err == EAI_FAMILY && sep->se_family == AF_INET6 && sep->se_v4mapped)
+       {
+         /* Fall back to IPv6 silently.  */
+         sep->se_family = AF_INET;
+         close (sep->se_fd);
+         goto tryagain;
+       }
+
+      if (err == EAI_SYSTEM)
+       errmsg = strerror (errno);
+      else
+       errmsg = gai_strerror (err);
+      
+      syslog (LOG_ERR, "%s/%s: getaddrinfo: %s",
+             sep->se_service, sep->se_proto, errmsg);
+      
+      close (sep->se_fd);
+      sep->se_fd = -1;
+      return;
+    }
+
+  memcpy (&sep->se_ctrladdr, result->ai_addr, result->ai_addrlen);
+
+  freeaddrinfo (result);
+
+  if (sep->se_family == AF_INET6)
+    {
+      if (sep->se_v4mapped)
+       err = setsockopt (sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY,
+                         (char *)&off, sizeof(off));
+      else
+       err = setsockopt (sep->se_fd, IPPROTO_IPV6, IPV6_V6ONLY,
+                         (char *)&on, sizeof(on));
+      
+      if (err < 0)
+       syslog (LOG_ERR, "setsockopt (IPV6_V6ONLY): %m");
+    }
+#endif
+  
+  if (strncmp (sep->se_proto, "tcp", 3) == 0 && (options & SO_DEBUG))
     {
+      err = setsockopt(sep->se_fd, SOL_SOCKET, SO_DEBUG,
+                      (char *)&on, sizeof (on));
+      if (err < 0)
+       syslog (LOG_ERR, "setsockopt (SO_DEBUG): %m");
+    }
+  
+  err = setsockopt(sep->se_fd, SOL_SOCKET, SO_REUSEADDR,
+                  (char *)&on, sizeof (on));
+  if (err < 0)
+    syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
+
+  err = bind (sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
+             sizeof (sep->se_ctrladdr));
+  if (err < 0)
+    {
+#ifdef IPV6
+      /* If we can't bind with AF_INET6 try again with AF_INET.  */
+      if ((errno == EADDRNOTAVAIL || errno == EAFNOSUPPORT)
+         && sep->se_family == AF_INET6 && sep->se_v4mapped)
+       {       
+         /* Fall back to IPv6 silently.  */
+         sep->se_family = AF_INET;
+         close (sep->se_fd);
+         goto tryagain;
+       }
+#endif
       if (debug)
        fprintf (stderr, "bind failed on %s/%s: %s\n",
                 sep->se_service, sep->se_proto, strerror (errno));
@@ -952,7 +1084,7 @@ endconfig (FILE *fconfig)
 #define INETD_SERVER_PATH  5   /* server program path */ 
 #define INETD_SERVER_ARGS  6   /* server program arguments */
 
-#define INETD_FIELDS_MIN   7   /* Minimum number of fields in entry */
+#define INETD_FIELDS_MIN   6   /* Minimum number of fields in entry */
 
 struct servtab *
 getconfigent (FILE *fconfig, const char *file, size_t *line)
@@ -960,7 +1092,7 @@ getconfigent (FILE *fconfig, const char 
   struct servtab *sep = &serv;
   size_t argc = 0, i;
   char **argv = NULL;
-  char *cp, *arg;
+  char *cp;
   static char TCPMUX_TOKEN[] = "tcpmux/";
 #define MUX_LEN                (sizeof(TCPMUX_TOKEN)-1)
 
@@ -1025,6 +1157,37 @@ getconfigent (FILE *fconfig, const char 
       
       sep->se_proto = newstr (argv[INETD_PROTOCOL]);
 
+#ifdef IPV6
+      /* We default to IPv6, in setup() we'll fall back to IPv4 if
+        it doesn't work.  */
+      sep->se_family = AF_INET6;
+      sep->se_v4mapped = 1;
+      
+      if ((strncmp (sep->se_proto, "tcp", 3) == 0)
+         || (strncmp (sep->se_proto, "udp", 3) == 0))
+       {
+         if (sep->se_proto[3] == '6')
+           {
+             sep->se_family = AF_INET6;
+             sep->se_v4mapped = 0;
+           }
+         else if (sep->se_proto[3] == '4')
+           {
+             sep->se_family = AF_INET;
+           }
+       }
+#else
+      if ((strncmp (sep->se_proto, "tcp6", 4) == 0)
+         || (strncmp (sep->se_proto, "udp6", 4) == 0))
+       {
+         syslog (LOG_ERR, "%s:%lu: %s: IPv6 support isn't eneabled",
+                 file, (unsigned long) *line, sep->se_proto);
+         continue;
+       }
+      
+      sep->se_family = AF_INET;
+#endif
+      
       if (strcmp (argv[INETD_WAIT], "wait") == 0)
        sep->se_wait = 1;
       else if (strcmp (argv[INETD_WAIT], "nowait") == 0)
@@ -1043,7 +1206,7 @@ getconfigent (FILE *fconfig, const char 
           */
          sep->se_wait = 0;
          
-         if (strcmp (sep->se_proto, "tcp"))
+         if (strncmp (sep->se_proto, "tcp", 3))
            {
              syslog (LOG_ERR, "%s:%lu: bad protocol for tcpmux service %s",
                      file, (unsigned long) *line, sep->se_service);
@@ -1103,8 +1266,6 @@ getconfigent (FILE *fconfig, const char 
 void
 freeconfig (struct servtab *cp)
 {
-  int i;
-
   if (cp->se_service)
     free (cp->se_service);
   if (cp->se_proto)
@@ -1144,13 +1305,31 @@ set_proc_title (char *a, int s)
 {
   int size;
   char *cp;
-  struct sockaddr_in lsin;
+#ifdef IPV6
+  struct sockaddr_storage saddr;
+#else
+  struct sockaddr_in saddr;
+#endif
   char buf[80];
 
   cp = Argv[0];
-  size = sizeof lsin;
-  if (getpeername (s, (struct sockaddr *)&lsin, &size) == 0)
-    snprintf (buf, sizeof buf, "-%s [%s]", a, inet_ntoa (lsin.sin_addr));
+  size = sizeof saddr;
+  if (getpeername (s, (struct sockaddr *)&saddr, &size) == 0)
+    {
+#ifdef IPV6
+      int err;
+      char buf2[80];
+
+      err = getnameinfo ((struct sockaddr *) &saddr, sizeof (saddr), buf2,
+                        sizeof (buf2), NULL, 0, NI_NUMERICHOST);
+      if (!err)
+       snprintf (buf, sizeof buf, "-%s [%s]", a, buf2);
+      else
+       snprintf (buf, sizeof buf, "-%s", a);
+#else
+      snprintf (buf, sizeof buf, "-%s [%s]", a, inet_ntoa (saddr.sin_addr));
+#endif
+    }
   else
     snprintf (buf, sizeof buf, "-%s", a);
   strncpy (cp, buf, LastArg - cp);
@@ -1186,13 +1365,18 @@ echo_dg (int s, struct servtab *sep)
 {
   char buffer[BUFSIZE];
   int i, size;
+#ifdef IPV6
+  struct sockaddr_storage sa;
+#else
   struct sockaddr sa;
+#endif
 
   (void)sep;
   size = sizeof sa;
-  if ((i = recvfrom (s, buffer, sizeof buffer, 0, &sa, &size)) < 0)
+  i = recvfrom (s, buffer, sizeof buffer, 0, (struct sockaddr *)&sa, &size);
+  if (i < 0)
     return;
-  sendto (s, buffer, i, 0, &sa, sizeof sa);
+  sendto (s, buffer, i, 0, (struct sockaddr *) &sa, sizeof sa);
 }
 
 /* ARGSUSED */
@@ -1281,7 +1465,11 @@ chargen_stream (int s, struct servtab *s
 void
 chargen_dg (int s, struct servtab *sep)
 {
+#ifdef IPV6
+  struct sockaddr_storage sa;
+#else
   struct sockaddr sa;
+#endif
   static char *rs;
   int len, size;
   char text[LINESIZ+2];
@@ -1294,7 +1482,7 @@ chargen_dg (int s, struct servtab *sep)
     }
 
   size = sizeof sa;
-  if (recvfrom (s, text, sizeof text, 0, &sa, &size) < 0)
+  if (recvfrom (s, text, sizeof text, 0, (struct sockaddr *)&sa, &size) < 0)
     return;
 
   if ((len = endring - rs) >= LINESIZ)
@@ -1308,7 +1496,7 @@ chargen_dg (int s, struct servtab *sep)
     rs = ring;
   text[LINESIZ] = '\r';
   text[LINESIZ + 1] = '\n';
-  sendto (s, text, sizeof text, 0, &sa, sizeof sa);
+  sendto (s, text, sizeof text, 0, (struct sockaddr *)&sa, sizeof sa);
 }
 
 /*
@@ -1351,15 +1539,21 @@ void
 machtime_dg (int s, struct servtab *sep)
 {
   long result;
+#ifdef IPV6
+  struct sockaddr_storage sa;
+#else
   struct sockaddr sa;
+#endif
   int size;
 
   (void)sep; /* shutup gcc */
   size = sizeof sa;
-  if (recvfrom (s, (char *)&result, sizeof result, 0, &sa, &size) < 0)
+  if (recvfrom (s, (char *)&result, sizeof result, 0, 
+               (struct sockaddr *)&sa, &size) < 0)
     return;
   result = machtime ();
-  sendto (s, (char *) &result, sizeof result, 0, &sa, sizeof sa);
+  sendto (s, (char *) &result, sizeof result, 0, 
+         (struct sockaddr *)&sa, sizeof sa);
 }
 
 /* ARGSUSED */
@@ -1384,17 +1578,21 @@ daytime_dg(int s, struct servtab *sep)
 {
   char buffer[256];
   time_t lclock;
+#ifdef IPV6
+  struct sockaddr_storage sa;
+#else
   struct sockaddr sa;
+#endif
   int size;
 
   (void)sep; /* shutup gcc */
   lclock = time ((time_t *) 0);
 
   size = sizeof sa;
-  if (recvfrom (s, buffer, sizeof buffer, 0, &sa, &size) < 0)
+  if (recvfrom (s, buffer, sizeof buffer, 0, (struct sockaddr *)&sa, &size) < 
0)
     return;
   sprintf (buffer, "%.24s\r\n", ctime (&lclock));
-  sendto (s, buffer, strlen(buffer), 0, &sa, sizeof sa);
+  sendto (s, buffer, strlen(buffer), 0, (struct sockaddr *)&sa, sizeof sa);
 }
 
 /*
Index: ping/Makefile.am
===================================================================
RCS file: /cvsroot/inetutils/inetutils/ping/Makefile.am,v
retrieving revision 1.13
diff -u -p -r1.13 Makefile.am
--- ping/Makefile.am    15 Jan 2003 08:32:40 -0000      1.13
+++ ping/Makefile.am    6 Jul 2004 22:06:43 -0000
@@ -1,29 +1,30 @@
 AUTOMAKE_OPTIONS = ../ansi2knr
 
-bin_PROGRAMS = @ping_BUILD@
+bin_PROGRAMS = @ping_BUILD@ @ping6_BUILD@
 
-EXTRA_PROGRAMS = ping
+EXTRA_PROGRAMS = ping ping6
 
 man_MANS = ping.8
 EXTRA_DIST = $(man_MANS)
 
-LDADD = -L../libinetutils -linetutils -L../libicmp -licmp
-INCLUDES = -I$(top_srcdir)/libicmp -I$(top_builddir)/include
+ping_LDADD = -L../libinetutils -linetutils -L../libicmp -licmp
+ping6_LDADD = -L../libinetutils -linetutils
+INCLUDES = -I$(top_srcdir)/libinetutils -I$(top_srcdir)/libicmp 
-I$(top_builddir)/include
 
-ping_SOURCES = ping.c \
- ping_echo.c \
- ping_address.c \
- ping_router.c \
- ping_timestamp.c \
- ping_impl.h
+ping_SOURCES = ping.c ping_common.c ping_echo.c ping_address.c \
+  ping_router.c ping_timestamp.c ping_common.h  ping_impl.h
+
+ping6_SOURCES = ping6.c ping_common.c ping_common.h ping6.h
 
 SUIDMODE = -o root -m 4775
 
 install-exec-hook:
-       address@hidden(INSTALL_PROGRAM) $(bin_PROGRAMS) $(SUIDMODE) 
$(AM_INSTALL_PROGRAM_FLAGS) $(DESTDIR)$(bindir)/`echo $(bin_PROGRAMS)|sed 
'$(transform)'` ; \
+       address@hidden program in $(bin_PROGRAMS); do \
+       $(INSTALL_PROGRAM) $$program $(SUIDMODE) $(AM_INSTALL_PROGRAM_FLAGS) 
$(DESTDIR)$(bindir)/`echo $$program|sed '$(transform)'` ; \
        if test $$? -ne 0; then \
                echo 'INSTALL-ERROR:'; \
-               echo 'INSTALL-ERROR: THIS PROGRAM($(bin_PROGRAMS)) MUST BE 
INSTALLED SETUID ROOT'; \
-               echo 'INSTALL-ERROR: $(INSTALL_PROGRAM) $(bin_PROGRAMS) 
$(SUIDMODE) $(DESTDIR)$(bindir)/$(bin_PROGRAMS)'; \
+               echo 'INSTALL-ERROR: THIS PROGRAM($$program) MUST BE INSTALLED 
SETUID ROOT'; \
+               echo 'INSTALL-ERROR: $(INSTALL_PROGRAM) $(bin_PROGRAMS) 
$(SUIDMODE) $(DESTDIR)$(bindir)/$$program'; \
                echo 'INSTALL-ERROR:'; \
-       fi
+       fi; \
+       done
Index: ping/ping.c
===================================================================
RCS file: /cvsroot/inetutils/inetutils/ping/ping.c,v
retrieving revision 1.19
diff -u -p -r1.19 ping.c
--- ping/ping.c 3 Mar 2004 10:21:03 -0000       1.19
+++ ping/ping.c 6 Jul 2004 22:06:43 -0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998,2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1998, 2001, 2002, 2004 Free Software Foundation, Inc.
 
    This file is part of GNU Inetutils.
 
@@ -45,10 +45,11 @@
 #include <errno.h>
 #include <limits.h>
 
-#include "getopt.h"
+#include <getopt.h>
 #include <icmp.h>
 #include <ping.h>
-#include <ping_impl.h>
+#include "ping_common.h"
+#include "ping_impl.h"
 
 static char short_options[] = "VLhc:dfi:l:np:qRrs:t:v";
 static struct option long_options[] = 
@@ -80,52 +81,23 @@ static struct option long_options[] = 
   {NULL,      no_argument, NULL, 0}
 };
 
-extern int ping_echo __P ((int argc, char **argv));
-extern int ping_timestamp __P ((int argc, char **argv));
-extern int ping_address __P ((int argc, char **argv));
-extern int ping_router __P ((int argc, char **argv));
+extern int ping_echo (int argc, char **argv);
+extern int ping_timestamp (int argc, char **argv);
+extern int ping_address (int argc, char **argv);
+extern int ping_router (int argc, char **argv);
 
 PING *ping;
 u_char *data_buffer;
 size_t data_length = PING_DATALEN;
 unsigned options;
 unsigned long preload = 0;
-int (*ping_type) __P ((int argc, char **argv)) = ping_echo;
+int (*ping_type) (int argc, char **argv) = ping_echo;
 
 
 static void show_usage (void);
-static void show_license (void);
-static void decode_pattern (const char *text, int *pattern_len, 
-                          u_char *pattern_data);
 static void decode_type (const char *optarg);
-static void init_data_buffer (u_char *pat, int len);
 static int send_echo (PING *ping);
 
-static size_t
-ping_cvt_number (const char *optarg, size_t maxval, int allow_zero)
-{
-  char *p;
-  size_t n;
-
-  n = strtoul (optarg, &p, 0);
-  if (*p)
-    {
-      fprintf (stderr, "Invalid value (`%s' near `%s')\n", optarg, p);
-      exit (1);
-    }
-  if (n == 0 && !allow_zero)
-    {
-      fprintf (stderr, "Option value too small: %s\n", optarg);
-      exit (1);
-    }
-  if (maxval && n > maxval)
-    {
-      fprintf (stderr, "Option value too big: %s\n", optarg);
-      exit (1);
-    }
-  return n;
-}
-
 int
 main (int argc, char **argv)
 {
@@ -155,7 +127,7 @@ main (int argc, char **argv)
        {
        case 'V':
          printf ("ping - %s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
-         printf ("Copyright (C) 1998,2001 Free Software Foundation, Inc.\n");
+         printf ("Copyright (C) 2004 Free Software Foundation, Inc.\n");
          printf ("%s comes with ABSOLUTELY NO WARRANTY.\n", PACKAGE_NAME);
          printf ("You may redistribute copies of %s\n", PACKAGE_NAME);
          printf ("under the terms of the GNU General Public License.\n");
@@ -252,10 +224,20 @@ main (int argc, char **argv)
          break;
          
        case ICMP_ADDRESS:
+         if (!is_root)
+           {
+             fprintf (stderr, "ping: option not allowed: --address\n");
+             exit (1);
+           }
          decode_type ("address");
          break;
          
        case ICMP_ROUTERDISCOVERY:
+         if (!is_root)
+           {
+             fprintf (stderr, "ping: option not allowed: --router\n");
+             exit (1);
+           }
          decode_type ("router");
          break;
          
@@ -279,37 +261,6 @@ main (int argc, char **argv)
 }
 
 void
-init_data_buffer (u_char *pat, int len)
-{
-  int i = 0;
-  u_char *p;
-
-  if (data_length == 0)
-    return;
-  data_buffer = malloc (data_length);
-  if (!data_buffer)
-    {
-      fprintf (stderr, "ping: out of memory\n");
-      exit (1);
-    }
-  if (pat)
-    {
-      for (p = data_buffer; p < data_buffer + data_length; p++)
-       {
-         *p = pat[i];
-         if (i++ >= len)
-           i = 0;
-       }
-    }
-  else
-    {
-      for (i = 0; i < data_length; i++)
-       data_buffer[i] = i;
-    }
-}
-  
-
-void
 decode_type (const char *optarg)
 {
   if (strcasecmp (optarg, "echo") == 0)
@@ -329,23 +280,6 @@ decode_type (const char *optarg)
     }
 }
 
-void
-decode_pattern (const char *text, int *pattern_len, u_char *pattern_data)
-{
-  int i, c, off;
-
-  for (i = 0; *text && i < *pattern_len; i++)
-    {
-      if (sscanf (text, "%2x%n", &c, &off) != 1)
-       {
-         fprintf (stderr, "ping: error in pattern near %s\n", text);
-         exit (1);
-       }
-      text += off;
-    }
-  *pattern_len = i;
-}
-
 int volatile stop = 0;
 
 RETSIGTYPE
@@ -388,7 +322,7 @@ ping_run (PING *ping, int (*finish)())
 
   while (!stop)
     {
-      int n, len;
+      int n;
       
       FD_ZERO (&fdset);
       FD_SET (ping->ping_fd, &fdset);
@@ -508,9 +442,9 @@ Informational options:\n\
   -V, --version      output version information and exit\n\
 Options controlling ICMP request types:\n\
   --echo             Send ICMP_ECHO requests (default)\n\
-  --address          Send ICMP_ADDRESS packets\n\
+* --address          Send ICMP_ADDRESS packets\n\
   --timestamp        Send ICMP_TIMESTAMP packets\n\
-  --router           Send ICMP_ROUTERDISCOVERY packets\n\
+* --router           Send ICMP_ROUTERDISCOVERY packets\n\
 Options valid for all request types:\n\
   -c, --count N      stop after sending N packets\n\
   -d, --debug        set the SO_DEBUG option\n\
@@ -532,24 +466,3 @@ Options marked with an * are available o
 report bugs to " PACKAGE_BUGREPORT ".\n\
 ");
 }
-
-void
-show_license (void)
-{
-  static char license_text[] =
-"   This program is free software; you can redistribute it and/or modify\n"
-"   it under the terms of the GNU General Public License as published by\n"
-"   the Free Software Foundation; either version 2, or (at your option)\n"
-"   any later version.\n"
-"\n"
-"   This program is distributed in the hope that it will be useful,\n"
-"   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
-"   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
-"   GNU General Public License for more details.\n"
-"\n"
-"   You should have received a copy of the GNU General Public License\n"
-"   along with this program; if not, write to the Free Software\n"
-"   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
-  printf ("%s", license_text);
-}
-
Index: ping/ping6.c
===================================================================
RCS file: ping/ping6.c
diff -N ping/ping6.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ping/ping6.c        6 Jul 2004 22:06:43 -0000
@@ -0,0 +1,932 @@
+/* Copyright (C) 1998, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+   This file is part of GNU Inetutils.
+
+   GNU Inetutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU Inetutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Inetutils; see the file COPYING.  If not, write to
+   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <signal.h>
+
+#include <netinet/in.h>
+#include <netinet/ip6.h>
+#include <netinet/icmp6.h>
+
+#include <netdb.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <getopt.h>
+#include <xalloc.h>
+#include "ping_common.h"
+#include "ping6.h"
+
+static char short_options[] = "VLhc:dfi:l:np:qRrs:t:v";
+static struct option long_options[] = 
+{
+  /* Help options */
+  {"version", no_argument, NULL, 'V'},
+  {"license", no_argument, NULL, 'L'},
+  {"help",    no_argument, NULL, 'h'},
+  /* Common options */
+  {"count",   required_argument, NULL, 'c'},
+  {"debug",   no_argument, NULL, 'd'},
+  {"ignore-routing", no_argument, NULL, 'r'},
+  {"size",    required_argument, NULL, 's'},
+  {"interval",required_argument, NULL, 'i'},
+  {"numeric", no_argument, NULL, 'n'},
+  /* echo-specific options */
+  {"flood",   no_argument, NULL, 'f'},
+  {"preload", required_argument, NULL, 'l'},
+  {"pattern", required_argument, NULL, 'p'},
+  {"quiet",   no_argument, NULL, 'q'},
+  {NULL,      no_argument, NULL, 0}
+};
+
+static PING *ping;
+unsigned char *data_buffer;
+size_t data_length = PING_DATALEN;
+static unsigned int options;
+static unsigned long preload = 0;
+
+static int ping_echo (int argc, char **argv);
+
+static void show_usage (void);
+static int send_echo (PING *ping);
+
+int
+main (int argc, char **argv)
+{
+  int c;
+  char *p;
+  int one = 1;
+  u_char pattern[16];
+  int pattern_len = 16;
+  u_char *patptr = NULL;
+  int is_root = getuid () == 0;
+
+  if ((ping = ping_init (0, getpid ())) == NULL)
+    {
+      fprintf (stderr, "can't init ping: %s\n", strerror (errno));
+      exit (1);
+    }
+  setsockopt (ping->ping_fd, SOL_SOCKET, SO_BROADCAST, (char *)&one, sizeof 
(one));
+
+  /* Reset root privileges */
+  setuid (getuid ());
+
+  /* Parse command line */
+  while ((c = getopt_long (argc, argv, short_options, long_options, NULL))
+        != EOF)
+    {
+      switch (c)
+       {
+       case 'V':
+         printf ("ping - %s %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+         printf ("Copyright (C) 2004 Free Software Foundation, Inc.\n");
+         printf ("%s comes with ABSOLUTELY NO WARRANTY.\n", PACKAGE_NAME);
+         printf ("You may redistribute copies of %s\n", PACKAGE_NAME);
+         printf ("under the terms of the GNU General Public License.\n");
+         printf ("For more information about these matters, ");
+         printf ("see the files named COPYING.\n");
+         exit (0);
+         break;
+         
+       case 'L':
+         show_license ();
+         exit (0);
+         
+       case 'h':
+         show_usage ();
+         exit (0);
+         break;
+         
+       case 'c':
+         ping->ping_count = ping_cvt_number (optarg, 0, 0);
+         break;
+         
+       case 'd':
+         setsockopt (ping->ping_fd, SOL_SOCKET, SO_DEBUG, &one, sizeof (one));
+         break;
+         
+       case 'r':
+         setsockopt (ping->ping_fd, SOL_SOCKET, SO_DONTROUTE, &one, sizeof 
(one));
+         break;
+         
+       case 'i':
+         options |= OPT_INTERVAL;
+         ping->ping_interval = ping_cvt_number (optarg, 0, 0);
+         break;
+         
+       case 'p':
+         decode_pattern (optarg, &pattern_len, pattern);
+         patptr = pattern;
+         break;
+         
+       case 's':
+         data_length = ping_cvt_number (optarg, PING_MAX_DATALEN, 1);
+         break;
+         
+       case 'n':
+         options |= OPT_NUMERIC;
+         break;
+         
+       case 'q':
+         options |= OPT_QUIET;
+         break;
+         
+       case 'l':
+         if (!is_root)
+           {
+             fprintf (stderr, "ping: option not allowed: --preload\n");
+             exit (1);
+           }
+         preload = strtoul (optarg, &p, 0);
+         if (*p || preload > INT_MAX)
+           {
+             fprintf (stderr, "ping: invalid preload value (%s)\n", optarg);
+             exit (1);
+           }
+         break;
+
+       case 'f':
+         if (!is_root)
+           {
+             fprintf (stderr, "ping: option not allowed: --flood\n");
+             exit (1);
+           }
+         options |= OPT_FLOOD;
+         setbuf (stdout, (char *)NULL);
+         break;
+
+       default:
+         fprintf (stderr, "%c: not implemented\n", c);
+         exit (1);
+       }
+    }
+
+  argc -= optind;
+  argv += optind;
+  if (argc == 0) 
+    {
+      show_usage ();
+      exit (0);
+    }
+
+  init_data_buffer (patptr, pattern_len);
+
+  return ping_echo (argc, argv);
+}
+
+static char *
+ipaddr2str (struct sockaddr_in6 *from)
+{
+  int err;
+  size_t len;
+  char *buf, ipstr[256], hoststr[256];
+
+  err = getnameinfo ((struct sockaddr *) from, sizeof (*from), ipstr,
+                    sizeof (ipstr), NULL, 0, NI_NUMERICHOST);
+  if (err)
+    {
+      const char *errmsg;
+      
+      if (err == EAI_SYSTEM)
+       errmsg = strerror (errno);
+      else
+       errmsg = gai_strerror (err);
+      
+      fprintf (stderr, "ping: getnameinfo: %s\n", errmsg);
+      return xstrdup ("unknown");
+    }
+  
+  if (options & OPT_NUMERIC)
+    return xstrdup (ipstr);
+
+  err = getnameinfo ((struct sockaddr *) from, sizeof (*from), hoststr,
+                    sizeof (hoststr), NULL, 0, NI_NAMEREQD);
+  if (err)
+    return xstrdup (ipstr);
+
+  len = strlen (ipstr) + strlen (hoststr) + 4; /* Pair of parentheses, a space
+                                                 and a NUL. */
+  buf = xmalloc (len);
+  sprintf (buf, "%s (%s)", hoststr, ipstr);
+
+  return buf;
+}
+
+static volatile int stop = 0;
+
+static RETSIGTYPE
+sig_int (int signal)
+{
+  stop = 1;
+}
+
+static int
+ping_run (PING *ping, int (*finish)())
+{
+  fd_set fdset;
+  int fdmax;
+  struct timeval timeout;
+  struct timeval last, intvl, now;
+  struct timeval *t = NULL;
+  int finishing = 0;
+  int nresp = 0;
+
+  signal (SIGINT, sig_int);
+  
+  fdmax = ping->ping_fd+1;
+
+  while (preload--)      
+    send_echo (ping);
+
+  if (options & OPT_FLOOD)
+    {
+      intvl.tv_sec = 0;
+      intvl.tv_usec = 10000;
+    }
+  else
+    {
+      intvl.tv_sec = ping->ping_interval;
+      intvl.tv_usec = 0;
+    }
+  
+  gettimeofday (&last, NULL);
+  send_echo (ping);
+
+  while (!stop)
+    {
+      int n;
+      
+      FD_ZERO (&fdset);
+      FD_SET (ping->ping_fd, &fdset);
+      gettimeofday (&now, NULL);
+      timeout.tv_sec = last.tv_sec + intvl.tv_sec - now.tv_sec;
+      timeout.tv_usec = last.tv_usec + intvl.tv_usec - now.tv_usec;
+
+      while (timeout.tv_usec < 0)
+       {
+         timeout.tv_usec += 1000000;
+         timeout.tv_sec--;
+       }
+      while (timeout.tv_usec >= 1000000)
+       {
+         timeout.tv_usec -= 1000000;
+         timeout.tv_sec++;
+       }
+
+      if (timeout.tv_sec < 0)
+       timeout.tv_sec = timeout.tv_usec = 0;
+
+      n = select (fdmax, &fdset, NULL, NULL, &timeout);
+      if (n < 0)
+       {
+         if (errno != EINTR)
+           perror ("select");
+         continue;
+       }
+      else if (n == 1)
+       {
+         if (ping_recv (ping) == 0)
+           nresp++;
+         if (t == 0)
+           {
+             gettimeofday (&now, NULL);
+             t = &now;
+           }
+         if (ping->ping_count && nresp >= ping->ping_count)
+           break;
+       }
+      else
+       {
+         if (!ping->ping_count || ping->ping_num_xmit < ping->ping_count)
+           {
+             send_echo (ping);
+             if (!(options & OPT_QUIET) && options & OPT_FLOOD)
+               {
+                 putchar ('.');
+               }
+           }
+         else if (finishing)
+           break;
+         else
+           {
+             finishing = 1;
+
+             intvl.tv_sec = MAXWAIT;
+           }
+         gettimeofday (&last, NULL);
+       }
+    }
+  if (finish)
+    return (*finish)();
+  return 0;
+}
+
+static int
+send_echo (PING *ping)
+{
+  int off = 0;
+  
+  if (PING_TIMING (data_length))
+    {
+      struct timeval tv;
+      gettimeofday (&tv, NULL);
+      ping_set_data (ping, &tv, 0, sizeof (tv));
+      off += sizeof (tv);
+    }
+  if (data_buffer)
+    ping_set_data (ping, data_buffer, off,
+                  data_length > PING_HEADER_LEN ?
+                  data_length - PING_HEADER_LEN : data_length);
+  return ping_xmit (ping);
+}
+
+static int
+ping_finish ()
+{
+  fflush (stdout);
+  printf ("--- %s ping statistics ---\n", ping->ping_hostname);
+  printf ("%ld packets transmitted, ", ping->ping_num_xmit);
+  printf ("%ld packets received, ", ping->ping_num_recv);
+  if (ping->ping_num_rept)
+    printf ("+%ld duplicates, ", ping->ping_num_rept);  
+  if (ping->ping_num_xmit)
+    {
+      if (ping->ping_num_recv > ping->ping_num_xmit)
+       printf ("-- somebody's printing up packets!");
+      else
+       printf ("%d%% packet loss",
+              (int) (((ping->ping_num_xmit - ping->ping_num_recv) * 100) /
+                     ping->ping_num_xmit));
+
+    }
+  printf ("\n");
+  return 0;
+}
+
+static int print_echo (int dup, int hops, struct ping_stat *stat,
+                      struct sockaddr_in6 *dest, struct sockaddr_in6 *from,
+                      struct icmp6_hdr *icmp6, int datalen);
+static void print_icmp_error (struct sockaddr_in6 *from,
+                             struct icmp6_hdr *icmp6, int len);
+
+static int echo_finish (void);
+
+static int
+ping_echo (int argc, char **argv)
+{
+  int err;
+  char buffer[256];
+  struct ping_stat ping_stat;
+
+  if (options & OPT_FLOOD && options & OPT_INTERVAL)
+    {
+      fprintf (stderr,
+              "ping: -f and -i incompatible options.\n");
+      return 2;
+    }
+
+  memset (&ping_stat, 0, sizeof (ping_stat));
+  ping_stat.tmin = 999999999.0;
+
+  ping->ping_datalen = data_length;
+  ping->ping_closure = &ping_stat;
+  
+  if (ping_set_dest (ping, *argv))
+    {
+      fprintf (stderr, "ping: unknown host\n");
+      exit (1);
+    }
+
+  err = getnameinfo ((struct sockaddr *) &ping->ping_dest,
+                    sizeof (ping->ping_dest), buffer,
+                    sizeof (buffer), NULL, 0, NI_NUMERICHOST);
+  if (err)
+    {
+      const char *errmsg;
+      
+      if (err == EAI_SYSTEM)
+       errmsg = strerror (errno);
+      else
+       errmsg = gai_strerror (err);
+
+      fprintf (stderr, "ping: getnameinfo: %s\n", errmsg);
+
+      exit (1);
+    }
+  
+  printf ("PING %s (%s): %d data bytes\n",
+         ping->ping_hostname, buffer, data_length);
+
+  return ping_run (ping, echo_finish);
+}
+
+static int
+print_echo (int dupflag, int hops, struct ping_stat *ping_stat,
+           struct sockaddr_in6 *dest, struct sockaddr_in6 *from,
+           struct icmp6_hdr *icmp6, int datalen)
+{
+  int err;
+  char buf[256];
+  struct timeval tv;
+  int timing = 0;
+  double triptime = 0.0;
+
+  gettimeofday (&tv, NULL);
+
+  /* Do timing */
+  if (PING_TIMING (datalen - sizeof (struct icmp6_hdr)))
+    {
+      struct timeval tv1, *tp;
+
+      timing++;
+      tp = (struct timeval *) icmp6 + 1;
+
+      /* Avoid unaligned data: */
+      memcpy (&tv1, tp, sizeof (tv1));
+      tvsub (&tv, &tv1);
+
+      triptime = ((double)tv.tv_sec) * 1000.0 +
+                 ((double)tv.tv_usec) / 1000.0;
+      ping_stat->tsum += triptime;
+      ping_stat->tsumsq += triptime*triptime;
+      if (triptime < ping_stat->tmin)
+       ping_stat->tmin = triptime;
+      if (triptime > ping_stat->tmax)
+       ping_stat->tmax = triptime;
+    }
+
+  if (options & OPT_QUIET)
+    return 0;
+  if (options & OPT_FLOOD)
+    {
+      putchar ('\b');
+      return 0;
+    }
+
+  err = getnameinfo ((struct sockaddr *) from, sizeof (*from), buf,
+                    sizeof (buf), NULL, 0, 0);
+  if (err)
+    {
+      const char *errmsg;
+      
+      if (err == EAI_SYSTEM)
+       errmsg = strerror (errno);
+      else
+       errmsg = gai_strerror (err);
+
+      fprintf (stderr, "ping: getnameinfo: %s\n", errmsg);
+
+      strcpy (buf, "unknown");
+    }
+
+  printf ("%d bytes from %s: icmp_seq=%u", datalen, buf, htons 
(icmp6->icmp6_seq));
+  if (hops >= 0)
+    printf (" ttl=%d", hops);
+  if (timing)
+    printf (" time=%.3f ms", triptime);
+  if (dupflag)
+    printf (" (DUP!)");
+
+  putchar ('\n');
+
+  return 0;
+}
+
+#define NITEMS(a) sizeof(a)/sizeof((a)[0])
+
+struct icmp_code_descr {
+  int code;
+  char *diag;
+};
+
+static struct icmp_code_descr icmp_dest_unreach_desc[] = {
+  { ICMP6_DST_UNREACH_NOROUTE, "No route to destination" },
+  { ICMP6_DST_UNREACH_ADMIN, "Destination administratively prohibited" },
+  { ICMP6_DST_UNREACH_BEYONDSCOPE, "Beyond scope of source address"  },
+  { ICMP6_DST_UNREACH_ADDR, "Address unreachable" },
+  { ICMP6_DST_UNREACH_NOPORT, "Port unreachable" },
+};
+
+static void
+print_dst_unreach (struct icmp6_hdr *icmp6)
+{
+  struct icmp_code_descr *p;
+
+  printf ("Destination unreachable: ");
+  for (p = icmp_dest_unreach_desc;
+       p < icmp_dest_unreach_desc + NITEMS(icmp_dest_unreach_desc);
+       p++)
+    {
+      if (p->code == icmp6->icmp6_code)
+       {
+         puts (p->diag);
+         return;
+       }
+    }
+
+  printf ("Unknown code %d\n", icmp6->icmp6_code);
+}
+
+static void
+print_packet_too_big (struct icmp6_hdr *icmp6)
+{
+  printf ("Packet too big, mtu=%d\n", icmp6->icmp6_mtu);
+}
+
+static struct icmp_code_descr icmp_time_exceeded_desc[] = {
+  { ICMP6_TIME_EXCEED_TRANSIT, "Hop limit exceeded"},
+  { ICMP6_TIME_EXCEED_REASSEMBLY, "Fragment reassembly timeout"},
+};
+
+static void
+print_time_exceeded (struct icmp6_hdr *icmp6)
+{
+  struct icmp_code_descr *p;
+
+  printf ("Time exceeded: ");
+  for (p = icmp_time_exceeded_desc;
+       p < icmp_time_exceeded_desc + NITEMS(icmp_time_exceeded_desc);
+       p++)
+    {
+      if (p->code == icmp6->icmp6_code)
+       {
+         puts (p->diag);
+         return;
+       }
+    }
+
+  printf ("Unknown code %d\n", icmp6->icmp6_code);
+}
+
+static struct icmp_code_descr icmp_param_prob_desc[] = {
+  { ICMP6_PARAMPROB_HEADER, "Erroneous header field"},
+  { ICMP6_PARAMPROB_NEXTHEADER, "Unrecognized Next Header type"},
+  { ICMP6_PARAMPROB_OPTION, "Unrecognized IPv6 option"},
+};
+
+static void
+print_param_prob (struct icmp6_hdr *icmp6)
+{
+  struct icmp_code_descr *p;
+
+  printf ("Parameter problem: ");
+  for (p = icmp_param_prob_desc;
+       p < icmp_param_prob_desc + NITEMS(icmp_param_prob_desc);
+       p++)
+    {
+      if (p->code == icmp6->icmp6_code)
+       {
+         puts (p->diag);
+         return;
+       }
+    }
+
+  printf ("Unknown code %d\n", icmp6->icmp6_code);
+}
+
+static struct icmp_diag {
+  int type;
+  void (*func) (struct icmp6_hdr *);
+} icmp_diag[] = {
+  { ICMP6_DST_UNREACH, print_dst_unreach },
+  { ICMP6_PACKET_TOO_BIG, print_packet_too_big },
+  { ICMP6_TIME_EXCEEDED, print_time_exceeded },
+  { ICMP6_PARAM_PROB, print_param_prob },
+};
+
+static void
+print_icmp_error (struct sockaddr_in6 *from,
+                 struct icmp6_hdr *icmp6, int len)
+{
+  char *s;
+  struct icmp_diag *p;
+  
+  s = ipaddr2str (from);
+  printf ("%d bytes from %s: ", len, s);
+  free (s);
+
+  for (p = icmp_diag; p < icmp_diag + NITEMS(icmp_diag); p++)
+    {
+      if (p->type == icmp6->icmp6_type)
+       {
+         p->func (icmp6);
+         return;
+       }
+    }
+
+  /* This should never happen because of the ICMP6_FILTER set in
+     ping_init(). */
+  printf ("Unknown ICMP type: %d\n", icmp6->icmp6_type);
+}
+
+static int
+echo_finish ()
+{
+  ping_finish ();
+  if (ping->ping_num_recv && PING_TIMING (data_length))
+    {
+      struct ping_stat *ping_stat = (struct ping_stat*)ping->ping_closure;
+      double total = ping->ping_num_recv + ping->ping_num_rept;
+      double avg = ping_stat->tsum/total;
+      double vari = ping_stat->tsumsq / total - avg * avg;
+
+      printf ("round-trip min/avg/max/stddev = %.3f/%.3f/%.3f/%.3f ms\n",
+             ping_stat->tmin, avg, ping_stat->tmax, nsqrt (vari, 0.0005));
+    }
+  exit (ping->ping_num_recv == 0);
+}
+
+static void
+show_usage (void)
+{
+  printf ("\
+Usage: ping6 [OPTION]... [ADDRESS]...\n\
+\n\
+Informational options:\n\
+  -h, --help         display this help and exit\n\
+  -L, --license      display license and exit\n\
+  -V, --version      output version information and exit\n\
+Options valid for all request types:\n\
+  -c, --count N      stop after sending N packets\n\
+  -d, --debug        set the SO_DEBUG option\n\
+  -i, --interval N   wait N seconds between sending each packet\n\
+  -n, --numeric      do not resolve host addresses\n\
+  -r, --ignore-routing  send directly to a host on an attached network\n\
+Options valid for --echo requests:\n\
+* -f, --flood        flood ping \n\
+* -l, --preload N    send N packets as fast as possible before falling into\n\
+                     normal mode of behavior\n\
+  -p, --pattern PAT  fill ICMP packet with given pattern (hex)\n\
+  -q, --quiet        quiet output\n\
+  -s, --size N       set number of data octets to send\n\
+\n\
+Options marked with an * are available only to super-user\n\
+\n\
+report bugs to " PACKAGE_BUGREPORT ".\n\
+");
+}
+
+static PING *
+ping_init (int type, int ident)
+{
+  int fd, err;
+  const int on = 1;
+  PING *p;
+  struct icmp6_filter filter;
+
+  /* Initialize raw ICMPv6 socket */
+  fd = socket (PF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
+  if (fd < 0) 
+    {
+      if (errno == EPERM) 
+       {
+         fprintf (stderr, "ping: ping must run as root\n");
+       }
+      return NULL;
+    }
+
+  /* Tell which ICMPs we are interested in.  */
+  ICMP6_FILTER_SETBLOCKALL (&filter);
+  ICMP6_FILTER_SETPASS (ICMP6_ECHO_REPLY, &filter);
+  ICMP6_FILTER_SETPASS (ICMP6_DST_UNREACH, &filter);
+  ICMP6_FILTER_SETPASS (ICMP6_PACKET_TOO_BIG, &filter);
+  ICMP6_FILTER_SETPASS (ICMP6_TIME_EXCEEDED, &filter);
+  ICMP6_FILTER_SETPASS (ICMP6_PARAM_PROB, &filter);
+
+  err = setsockopt (fd, IPPROTO_ICMPV6, ICMP6_FILTER, &filter, sizeof 
(filter));
+  if (err)
+    {
+      close (fd);
+      return NULL;
+    }
+
+  err = setsockopt (fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof (on));
+  if (err)
+    {
+      close (fd);
+      return NULL;
+    }
+  
+  /* Allocate PING structure and initialize it to default values */
+  p = malloc (sizeof (*p));
+  if (!p)
+    {
+      close (fd);
+      return NULL;
+    }
+
+  memset (p, 0, sizeof (*p));
+
+  p->ping_fd = fd;
+  p->ping_count = 0;
+  p->ping_interval = PING_INTERVAL;
+  p->ping_datalen = sizeof (struct icmp6_hdr);
+  /* Make sure we use only 16 bits in this field, id for icmp is a u_short.  */
+  p->ping_ident = ident & 0xFFFF;
+  p->ping_cktab_size = PING_CKTABSIZE;
+  return p;
+}
+
+static int
+_ping_setbuf (PING *p)
+{
+  if (!p->ping_buffer)
+    {
+      p->ping_buffer = malloc (_PING_BUFLEN (p));
+      if (!p->ping_buffer)
+       return -1;
+    }
+  if (!p->ping_cktab)
+    {
+      p->ping_cktab = malloc (p->ping_cktab_size);
+      if (!p->ping_cktab)
+        return -1;
+      memset (p->ping_cktab, 0, p->ping_cktab_size);
+    }
+  return 0;
+}
+
+static int
+ping_set_data (PING *p, void *data, size_t off, size_t len)
+{
+  if (_ping_setbuf (p))
+    return -1;
+  if (p->ping_datalen < off + len)
+    return -1;
+  memcpy (p->ping_buffer + sizeof (struct icmp6_hdr) + off, data, len);
+
+  return 0;
+}
+
+static int
+ping_xmit (PING *p)
+{
+  int i, buflen;
+  struct icmp6_hdr *icmp6;
+
+  if (_ping_setbuf (p))
+    return -1;
+
+  buflen = p->ping_datalen + sizeof (struct icmp6_hdr);
+
+  /* Mark sequence number as sent */
+  _PING_CLR (p, p->ping_num_xmit % p->ping_cktab_size);
+
+  icmp6 = (struct icmp6_hdr *) p->ping_buffer;
+  icmp6->icmp6_type = ICMP6_ECHO_REQUEST;
+  icmp6->icmp6_code = 0;
+  /* The checksum will be calculated by the TCP/IP stack.  */
+  icmp6->icmp6_cksum = 0; 
+  icmp6->icmp6_id = htons (p->ping_ident);
+  icmp6->icmp6_seq = htons (p->ping_num_xmit);
+
+  i = sendto (p->ping_fd, (char *)p->ping_buffer, buflen, 0,
+             (struct sockaddr*) &p->ping_dest,
+             sizeof (p->ping_dest));
+  if (i < 0)
+    perror ("ping: sendto");
+  else
+    {
+      p->ping_num_xmit++;
+      if (i != buflen)
+       printf ("ping: wrote %s %d chars, ret=%d\n",
+               p->ping_hostname, buflen, i);
+    }
+
+  return 0;
+}
+
+static int
+my_echo_reply (PING *p, struct icmp6_hdr *icmp6)
+{
+  struct ip6_hdr *orig_ip = 
+    (struct ip6_hdr *) (icmp6 + 1);
+  struct icmp6_hdr *orig_icmp = 
+    (struct icmp6_hdr *)(orig_ip + 1);
+
+  return IN6_ARE_ADDR_EQUAL (&orig_ip->ip6_dst, &ping->ping_dest.sin6_addr)
+    && orig_ip->ip6_nxt == IPPROTO_ICMPV6
+    && orig_icmp->icmp6_type == ICMP6_ECHO_REQUEST
+    && orig_icmp->icmp6_id == htons (p->ping_ident);
+}
+
+static int
+ping_recv (PING *p)
+{
+  int dupflag, n;
+  int hops = -1;
+  struct msghdr msg;
+  struct iovec iov;
+  struct icmp6_hdr *icmp6;
+  struct cmsghdr *cmsg;
+  char cmsg_data[1024];
+
+  iov.iov_base = p->ping_buffer;
+  iov.iov_len = _PING_BUFLEN (p);
+  msg.msg_name = &p->ping_from;
+  msg.msg_namelen = sizeof (p->ping_from);
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = cmsg_data;
+  msg.msg_controllen = sizeof (cmsg_data);
+  msg.msg_flags = 0;
+  
+  n = recvmsg (p->ping_fd, &msg, 0);
+  if (n < 0)
+    return -1;
+
+  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR (&msg, cmsg))
+    {
+      if (cmsg->cmsg_level == IPPROTO_IPV6 && cmsg->cmsg_type == IPV6_HOPLIMIT)
+       {
+         hops = *(int *)CMSG_DATA(cmsg);
+         break;
+       }
+    }
+  
+  icmp6 = (struct icmp6_hdr *) p->ping_buffer;
+  if (icmp6->icmp6_type == ICMP6_ECHO_REPLY)
+    {
+      /* We got an echo reply.  */
+      if (ntohs (icmp6->icmp6_id) != p->ping_ident)
+       return -1; /* It's not a response to us.  */
+
+      if (_PING_TST (p, ntohs (icmp6->icmp6_seq) % p->ping_cktab_size))
+       {
+         /* We already got the reply for this echo request.  */
+         p->ping_num_rept++;
+         dupflag = 1;
+       }
+      else
+       {
+         _PING_SET (p, ntohs (icmp6->icmp6_seq) % p->ping_cktab_size);
+         p->ping_num_recv++;
+         dupflag = 0;
+       }
+
+      print_echo (dupflag, hops, p->ping_closure, &p->ping_dest,
+                 &p->ping_from, icmp6, n);
+
+    }
+  else
+    {
+      /* We got an error reply.  */
+      if (!my_echo_reply (p, icmp6))
+       return -1; /* It's not for us.  */
+
+      print_icmp_error (&p->ping_from, icmp6, n);
+    }
+  
+  return 0;
+}
+
+static int
+ping_set_dest (PING *ping, char *host)
+{
+  int err;
+  struct addrinfo *result, hints;
+  
+  memset (&hints, 0, sizeof (hints));
+
+  hints.ai_family = AF_INET6;
+
+  err = getaddrinfo (host, NULL, &hints, &result);
+  if (err)
+    return 1;
+
+  memcpy (&ping->ping_dest, result->ai_addr, result->ai_addrlen);
+
+  freeaddrinfo (result);
+
+  ping->ping_hostname = strdup (host);
+  if (!ping->ping_hostname)
+    return 1;
+
+  return 0;
+}
Index: ping/ping6.h
===================================================================
RCS file: ping/ping6.h
diff -N ping/ping6.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ping/ping6.h        6 Jul 2004 22:06:43 -0000
@@ -0,0 +1,99 @@
+/* Copyright (C) 1998, 2004 Free Software Foundation, Inc.
+
+   This file is part of GNU Inetutils.
+
+   GNU Inetutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU Inetutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Inetutils; see the file COPYING.  If not, write to
+   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#include <netinet/in.h>
+#include <netinet/icmp6.h>
+
+typedef struct ping_data PING;
+typedef int (*ping_efp) (int code, void *closure, struct sockaddr_in6 *dest,
+                        struct sockaddr_in6 *from, struct icmp6_hdr *icmp,
+                        int datalen);
+
+
+struct ping_data
+{
+  int    ping_fd;        /* Raw socket descriptor */
+  int    ping_type;      /* Type of packets to send */
+  int    ping_count;     /* Number of packets to send */
+  int    ping_interval;  /* Number of seconds to wait between sending pkts */
+  struct sockaddr_in6 ping_dest; /* whom to ping */
+  char   *ping_hostname;     /* Printable hostname */
+  size_t ping_datalen;   /* Length of data */
+  int    ping_ident;     /* Our identifier */
+                          
+  ping_efp ping_event;   /* User-defined handler */
+  void *ping_closure;    /* User-defined data */
+
+  /* Runtime info */
+  int ping_cktab_size;
+  char   *ping_cktab;
+  
+  u_char *ping_buffer;   /* I/O buffer */
+  struct sockaddr_in6 ping_from;
+  long   ping_num_xmit;  /* Number of packets transmitted */
+  long   ping_num_recv;  /* Number of packets received */
+  long   ping_num_rept;  /* Number of duplicates received */
+};
+
+struct ping_stat
+{
+  double tmin;     /* minimum round trip time */
+  double tmax;      /* maximum round trip time */
+  double tsum;     /* sum of all times, for doing average */
+  double tsumsq;    /* sum of all times squared, for std. dev. */
+};
+
+#define PEV_RESPONSE 0
+#define PEV_DUPLICATE 1
+#define PEV_NOECHO  2
+
+#define PING_INTERVAL 1
+#define        PING_CKTABSIZE 128
+
+#define        MAXWAIT         10              /* max seconds to wait for 
response */
+
+#define        OPT_FLOOD       0x001
+#define        OPT_INTERVAL    0x002
+#define        OPT_NUMERIC     0x004
+#define        OPT_QUIET       0x008
+#define        OPT_RROUTE      0x010
+#define        OPT_VERBOSE     0x020
+
+#define PING_TIMING(s) (s >= PING_HEADER_LEN)
+#define        PING_HEADER_LEN sizeof (struct timeval)
+#define        PING_DATALEN    (64 - PING_HEADER_LEN)  /* default data length 
*/
+#define PING_MAX_DATALEN (65535 - sizeof (struct icmp6_hdr))
+
+#define _PING_BUFLEN(p) ((p)->ping_datalen + sizeof (struct icmp6_hdr))
+
+#define _C_BIT(p,bit)    (p)->ping_cktab[(bit)>>3]  /* byte in ck array */
+#define _C_MASK(bit)     (1 << ((bit) & 0x07))
+
+#define _PING_SET(p,bit) (_C_BIT (p,bit) |= _C_MASK (bit))
+#define _PING_CLR(p,bit) (_C_BIT (p,bit) &= (~_C_MASK (bit)))
+#define _PING_TST(p,bit) (_C_BIT (p,bit) & _C_MASK (bit))
+
+static PING *ping_init (int type, int ident);
+static int ping_set_dest (PING *ping, char *host);
+static int ping_set_data (PING *p, void *data, size_t off, size_t len);
+static int ping_recv (PING *p);
+static int ping_xmit (PING *p);
+
+static int ping_run (PING *ping, int (*finish)());
+static int ping_finish (void);
Index: ping/ping_common.c
===================================================================
RCS file: ping/ping_common.c
diff -N ping/ping_common.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ping/ping_common.c  6 Jul 2004 22:06:43 -0000
@@ -0,0 +1,164 @@
+/* Copyright (C) 1998, 2001, 2002, 2004 Free Software Foundation, Inc.
+
+   This file is part of GNU Inetutils.
+
+   GNU Inetutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU Inetutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Inetutils; see the file COPYING.  If not, write to
+   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+
+extern unsigned char *data_buffer;
+extern size_t data_length;
+
+unsigned long int
+ping_cvt_number (const char *optarg, unsigned long int maxval, int allow_zero)
+{
+  char *p;
+  unsigned long int n;
+
+  n = strtoul (optarg, &p, 0);
+  if (*p)
+    {
+      fprintf (stderr, "Invalid value (`%s' near `%s')\n", optarg, p);
+      exit (1);
+    }
+  if (n == 0 && !allow_zero)
+    {
+      fprintf (stderr, "Option value too small: %s\n", optarg);
+      exit (1);
+    }
+  if (maxval && n > maxval)
+    {
+      fprintf (stderr, "Option value too big: %s\n", optarg);
+      exit (1);
+    }
+  return n;
+}
+
+void
+init_data_buffer (unsigned char *pat, int len)
+{
+  int i = 0;
+  u_char *p;
+
+  if (data_length == 0)
+    return;
+  data_buffer = malloc (data_length);
+  if (!data_buffer)
+    {
+      fprintf (stderr, "ping: out of memory\n");
+      exit (1);
+    }
+  if (pat)
+    {
+      for (p = data_buffer; p < data_buffer + data_length; p++)
+       {
+         *p = pat[i];
+         if (i++ >= len)
+           i = 0;
+       }
+    }
+  else
+    {
+      for (i = 0; i < data_length; i++)
+       data_buffer[i] = i;
+    }
+}
+
+
+void
+decode_pattern (const char *text, int *pattern_len, unsigned char 
*pattern_data)
+{
+  int i, c, off;
+
+  for (i = 0; *text && i < *pattern_len; i++)
+    {
+      if (sscanf (text, "%2x%n", &c, &off) != 1)
+       {
+         fprintf (stderr, "ping: error in pattern near %s\n", text);
+         exit (1);
+       }
+      text += off;
+    }
+  *pattern_len = i;
+}
+
+
+/*
+ * tvsub --
+ *     Subtract 2 timeval structs:  out = out - in.  Out is assumed to
+ * be >= in.
+ */
+void
+tvsub (struct timeval *out, struct timeval *in)
+{
+  if ((out->tv_usec -= in->tv_usec) < 0)
+    {
+      --out->tv_sec;
+      out->tv_usec += 1000000;
+    }
+  out->tv_sec -= in->tv_sec;
+}
+
+double
+nabs (double a)
+{
+  return (a < 0) ? -a : a;
+}
+
+double
+nsqrt (double a, double prec)
+{
+  double x0, x1;
+  
+  if (a < 0)
+    return 0; 
+  if (a < prec)
+    return 0;
+  x1 = a/2;
+  do
+    {
+      x0 = x1;
+      x1 = (x0 + a/x0) / 2;
+    }
+  while (nabs (x1 - x0) > prec);
+
+  return x1;
+}
+
+void
+show_license (void)
+{
+  static char license_text[] =
+"   This program is free software; you can redistribute it and/or modify\n"
+"   it under the terms of the GNU General Public License as published by\n"
+"   the Free Software Foundation; either version 2, or (at your option)\n"
+"   any later version.\n"
+"\n"
+"   This program is distributed in the hope that it will be useful,\n"
+"   but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
+"   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
+"   GNU General Public License for more details.\n"
+"\n"
+"   You should have received a copy of the GNU General Public License\n"
+"   along with this program; if not, write to the Free Software\n"
+"   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.\n";
+  printf ("%s", license_text);
+}
Index: ping/ping_common.h
===================================================================
RCS file: ping/ping_common.h
diff -N ping/ping_common.h
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ ping/ping_common.h  6 Jul 2004 22:06:43 -0000
@@ -0,0 +1,34 @@
+/* Copyright (C) 2004 Free Software Foundation, Inc.
+
+   This file is part of GNU Inetutils.
+
+   GNU Inetutils is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 2, or (at your option)
+   any later version.
+
+   GNU Inetutils is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GNU Inetutils; see the file COPYING.  If not, write to
+   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+   Boston, MA 02111-1307, USA. */
+
+
+void tvsub (struct timeval *out, struct timeval *in);
+double nabs (double a);
+double nsqrt (double a, double prec);
+  
+void show_license (void);
+
+unsigned long int ping_cvt_number (const char *optarg,
+                                  unsigned long int maxval, int allow_zero);
+
+void init_data_buffer (unsigned char *pat, int len);
+
+void decode_pattern (const char *text, int *pattern_len,
+                    unsigned char *pattern_data);
+
Index: ping/ping_echo.c
===================================================================
RCS file: /cvsroot/inetutils/inetutils/ping/ping_echo.c,v
retrieving revision 1.10
diff -u -p -r1.10 ping_echo.c
--- ping/ping_echo.c    10 Nov 2003 14:29:40 -0000      1.10
+++ ping/ping_echo.c    6 Jul 2004 22:06:43 -0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 2001, 2002, 2004 Free Software Foundation, Inc.
 
    This file is part of GNU Inetutils.
 
@@ -45,18 +45,17 @@
 #include <errno.h>
 #include <limits.h>
 
-#include "getopt.h"
 #include <icmp.h>
 #include <ping.h>
-#include <ping_impl.h>
+#include "ping_common.h"
+#include "ping_impl.h"
 
 #define        NROUTES         9               /* number of record route slots 
*/
 #ifndef MAX_IPOPTLEN
 # define MAX_IPOPTLEN 40
 #endif
 
-extern char *xstrdup (const char *);
-extern char *xmalloc (size_t);
+#include <xalloc.h>
 
 static int handler (int code, void *closure,
                   struct sockaddr_in *dest, struct sockaddr_in *from,
@@ -70,8 +69,6 @@ void print_icmp_header (struct sockaddr_
                              struct ip *ip, icmphdr_t *icmp, int len);
 static void print_ip_opt (struct ip *ip, int hlen);
 
-static void tvsub (struct timeval *out, struct timeval *in);
-
 int
 ping_echo (int argc, char **argv)
 {
@@ -526,48 +523,6 @@ print_ip_opt (struct ip *ip, int hlen)
       }
 }
 
-/*
- * tvsub --
- *     Subtract 2 timeval structs:  out = out - in.  Out is assumed to
- * be >= in.
- */
-static void
-tvsub (struct timeval *out, struct timeval *in)
-{
-  if ((out->tv_usec -= in->tv_usec) < 0)
-    {
-      --out->tv_sec;
-      out->tv_usec += 1000000;
-    }
-  out->tv_sec -= in->tv_sec;
-}
-
-double
-nabs (double a)
-{
-  return (a < 0) ? -a : a;
-}
-
-double
-nsqrt (double a, double prec)
-{
-  double x0, x1;
-  
-  if (a < 0)
-    return 0; 
-  if (a < prec)
-    return 0;
-  x1 = a/2;
-  do
-    {
-      x0 = x1;
-      x1 = (x0 + a/x0) / 2;
-    }
-  while (nabs (x1 - x0) > prec);
-
-  return x1;
-}
-
 int
 echo_finish ()
 {
Index: telnet/commands.c
===================================================================
RCS file: /cvsroot/inetutils/inetutils/telnet/commands.c,v
retrieving revision 1.17
diff -u -p -r1.17 commands.c
--- telnet/commands.c   31 Aug 2003 22:31:59 -0000      1.17
+++ telnet/commands.c   6 Jul 2004 22:06:43 -0000
@@ -27,9 +27,9 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
+#if 0
 static char sccsid[] = "@(#)commands.c 8.4 (Berkeley) 5/30/95";
-#endif /* not lint */
+#endif
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -72,6 +72,7 @@ static char sccsid[] = "@(#)commands.c        8
 #include <malloc.h>
 #endif
 
+#include <arpa/inet.h>
 #include <arpa/telnet.h>
 
 #include "general.h"
@@ -95,12 +96,7 @@ static char sccsid[] = "@(#)commands.c       8
 #include <netinet/ip.h>
 #endif
 
-#if    defined(IPPROTO_IP) && defined(IP_TOS)
-int tos = -1;
-#endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
-
-char   *hostname;
-static char *_hostname = 0;
+char   *hostname = 0;
 
 extern char *getenv __P((const char *));
 
@@ -2199,246 +2195,324 @@ ayt_status()
 }
 #endif
 
-unsigned long inet_addr();
-
 int
 tn(int argc, char *argv[])
 {
-    register struct hostent *host = 0;
-    struct sockaddr_in sin;
-    struct servent *sp = 0;
-    unsigned long temp;
-    extern char *inet_ntoa();
-#if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
-    char *srp = 0;
-#ifndef strrchr
-    char *strrchr();
-#endif
-    unsigned long sourceroute(), srlen;
-#endif
-    char *cmd, *hostp = 0, *portp = 0, *user = 0;
-
-    /* clear the socket address prior to use */
-    memset((char *)&sin, 0, sizeof(sin));
+#ifdef IPV6
+  struct addrinfo *result, *aip, hints;
+#else
+  struct hostent *host = 0;
+  struct sockaddr_in sin;
+  struct servent *sp = 0;
+  in_addr_t temp;
+#endif
+  const int on = 1;
+  int err;
+  char *cmd, *hostp = 0, *portp = 0, *user = 0;
 
-    if (connected) {
-       printf("?Already connected to %s\n", hostname);
-       setuid(getuid());
-       return 0;
-    }
-    if (argc < 2) {
-       (void) strcpy(line, "open ");
-       printf("(to) ");
-       (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
-       makeargv();
-       argc = margc;
-       argv = margv;
+#ifdef IPV6
+  memset (&hints, 0, sizeof (hints));
+#else
+  /* clear the socket address prior to use */
+  memset ((char *)&sin, 0, sizeof(sin));
+#endif
+  
+  if (connected)
+    {
+      printf("?Already connected to %s\n", hostname);
+      return 0;
     }
-    cmd = *argv;
-    --argc; ++argv;
-    while (argc) {
-       if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
+  if (argc < 2)
+    {
+      (void) strcpy(line, "open ");
+      printf("(to) ");
+      (void) fgets(&line[strlen(line)], sizeof(line) - strlen(line), stdin);
+      makeargv();
+      argc = margc;
+      argv = margv;
+    }
+  cmd = *argv;
+  --argc; ++argv;
+  while (argc)
+    {
+      if (strcmp(*argv, "help") == 0 || isprefix(*argv, "?"))
+       goto usage;
+      if (strcmp(*argv, "-l") == 0)
+       {
+         --argc; ++argv;
+         if (argc == 0)
            goto usage;
-       if (strcmp(*argv, "-l") == 0) {
-           --argc; ++argv;
-           if (argc == 0)
-               goto usage;
-           user = *argv++;
-           --argc;
-           continue;
+         user = *argv++;
+         --argc;
+         continue;
        }
-       if (strcmp(*argv, "-a") == 0) {
-           --argc; ++argv;
-           autologin = 1;
-           continue;
+      if (strcmp(*argv, "-a") == 0)
+       {
+         --argc; ++argv;
+         autologin = 1;
+         continue;
        }
-       if (hostp == 0) {
-           hostp = *argv++;
-           --argc;
-           continue;
+      if (strcmp(*argv, "-6") == 0)
+       {
+         --argc; ++argv;
+#ifdef IPV6
+         hints.ai_family = AF_INET6;
+#else
+         puts ("IPv6 isn't supported");
+#endif
+         continue;
        }
-       if (portp == 0) {
-           portp = *argv++;
-           --argc;
-           continue;
+      if (strcmp(*argv, "-4") == 0)
+       {
+         --argc; ++argv;
+#ifdef IPV6
+         hints.ai_family = AF_INET;
+#endif
+         continue;
+       }
+      if (hostp == 0)
+       {
+         hostp = *argv++;
+         --argc;
+         continue;
+       }
+      if (portp == 0)
+       {
+         portp = *argv++;
+         --argc;
+         continue;
        }
     usage:
-       printf("usage: %s [-l user] [-a] host-name [port]\n", cmd);
-       setuid(getuid());
-       return 0;
+      printf("usage: %s [-4] [-6] [-l user] [-a] host-name [port]\n", cmd);
+      return 0;
     }
-    if (hostp == 0)
-       goto usage;
+  if (hostp == 0)
+    goto usage;
 
-#if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
-    if (hostp[0] == '@' || hostp[0] == '!') {
-       if ((hostname = strrchr(hostp, ':')) == NULL)
-           hostname = strrchr(hostp, '@');
-       hostname++;
-       srp = 0;
-       temp = sourceroute(hostp, &srp, &srlen);
-       if (temp == 0) {
-           herror(srp);
-           setuid(getuid());
-           return 0;
-       } else if (temp == -1) {
-           printf("Bad source route option: %s\n", hostp);
-           setuid(getuid());
-           return 0;
-       } else {
-           sin.sin_addr.s_addr = temp;
-           sin.sin_family = AF_INET;
+  if (!portp)
+    {
+      portp = "telnet";
+      telnetport = 1;
+    }
+  else
+    {
+      if (*portp == '-')
+       {
+         portp++;
+         telnetport = 1;
        }
-    } else {
+      else
+       telnetport = 0;
+    }
+
+  if (hostname)
+    free (hostname);
+  hostname = malloc (strlen (hostp) + 1);
+  if (hostname)
+    strcpy (hostname, hostp);
+  else
+    {
+      printf ("Can't allocate memory to copy hostname\n");
+      return 0;
+    }
+ 
+#ifdef IPV6
+#ifdef AI_ADDRCONFIG
+  hints.ai_flags = AI_ADDRCONFIG;
 #endif
-       temp = inet_addr(hostp);
-       if (temp != (unsigned long) -1) {
-           sin.sin_addr.s_addr = temp;
-           sin.sin_family = AF_INET;
+  hints.ai_socktype = SOCK_STREAM;
 
-       } else {
-           host = gethostbyname(hostp);
-           if (host) {
-               sin.sin_family = host->h_addrtype;
-#if    defined(h_addr)         /* In 4.3, this is a #define */
-               memmove((caddr_t)&sin.sin_addr,
-                               host->h_addr_list[0], host->h_length);
-#else  /* defined(h_addr) */
-               memmove((caddr_t)&sin.sin_addr, host->h_addr, host->h_length);
-#endif /* defined(h_addr) */
+  err = getaddrinfo (hostp, portp, &hints, &result);
+  if (err)
+    {
+      const char *errmsg;
+
+      if (err == EAI_SYSTEM)
+       errmsg = strerror (errno);
+      else
+       errmsg = gai_strerror (err);
+      
+      printf ("%s/%s: lookup failure: %s\n", hostp, portp, errmsg);
+      return 0;
+    }
+
+  aip = result;
+
+  do
+    {
+      char buf[256];
+
+      err = getnameinfo (aip->ai_addr, aip->ai_addrlen, buf, sizeof (buf),
+                        NULL, 0, NI_NUMERICHOST);
+      if (err)
+       {
+         /* I don't know how thing can happen, but we just handle it.  */
+         const char *errmsg;
+         
+         if (err == EAI_SYSTEM)
+           errmsg = strerror (errno);
+         else
+           errmsg = gai_strerror (err);
+         
+         printf ("getnameinfo error: %s\n", errmsg);
+         return 0;
+       }
+      
+      printf ("Trying %s...\n", buf);
 
+      net = socket (aip->ai_family, SOCK_STREAM, 0);
+      if (net < 0)
+       {
+         perror("telnet: socket");
+         return 0;
+       }
+
+      if (debug)
+       {
+         err = setsockopt (net, SOL_SOCKET, SO_DEBUG, &on, sizeof(on));
+         if (err < 0)
+           perror("setsockopt (SO_DEBUG)");
+       }
+
+      err = connect (net, (struct sockaddr *)aip->ai_addr, aip->ai_addrlen);
+      if (err < 0)
+       {
+         if (aip->ai_next)
+           {
+             perror ("Connection failed");
+             aip = aip->ai_next;
+             close (net);
+             continue;
            }
+           
+         perror("telnet: Unable to connect to remote host");
+         return 0;
        }
-        if (_hostname)
-               free (_hostname);
-        _hostname = malloc (strlen (hostp) + 1);
-        if (_hostname) {
-               strcpy (_hostname, hostp);
-               hostname = _hostname;
-       } else {
-               printf ("Can't allocate memory to copy hostname\n");
-               setuid(getuid());
-               return 0;
-       }
-#if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
+      
+      connected++;
+#if    defined(AUTHENTICATION) || defined(ENCRYPTION)
+      auth_encrypt_connect(connected);
+#endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
+    } while (!connected);
+
+  freeaddrinfo (result);
+#else /* !IPV6 */
+  temp = inet_addr (hostp);
+  if (temp != (in_addr_t) -1)
+    {
+      sin.sin_addr.s_addr = temp;
+      sin.sin_family = AF_INET;
     }
-#endif
-    if (portp) {
-       if (*portp == '-') {
-           portp++;
-           telnetport = 1;
-       } else
-           telnetport = 0;
-       sin.sin_port = atoi(portp);
-       if (sin.sin_port == 0) {
-           sp = getservbyname(portp, "tcp");
-           if (sp)
-               sin.sin_port = sp->s_port;
-           else {
-               printf("%s: bad port number\n", portp);
-               setuid(getuid());
-               return 0;
-           }
-       } else {
-#if !HAVE_DECL_HTONS
-#ifndef htons
-           u_short htons __P((unsigned short));
-#endif
-#endif
-           sin.sin_port = htons (sin.sin_port);
+  else
+    {
+      host = gethostbyname (hostp);
+      if (host)
+       {
+         sin.sin_family = host->h_addrtype;
+         memmove (&sin.sin_addr, host->h_addr_list[0], host->h_length);
        }
-    } else {
-       if (sp == 0) {
-           sp = getservbyname("telnet", "tcp");
-           if (sp == 0) {
-               fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
-               setuid(getuid());
-               return 0;
-           }
-           sin.sin_port = sp->s_port;
+      else
+       {
+         printf ("Can't lookup hostname %s\n", hostp);
+         return 0;
        }
-       telnetport = 1;
     }
-    printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
-    do {
-       net = socket(AF_INET, SOCK_STREAM, 0);
-       setuid(getuid());
-       if (net < 0) {
-           perror("telnet: socket");
-           return 0;
+  
+  sin.sin_port = atoi (portp);
+  if (sin.sin_port == 0)
+    {
+      sp = getservbyname (portp, "tcp");
+      if (sp == 0)
+       {
+         printf ("tcp/%s: unknown service\n", portp);
+         return 0;
        }
-#if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
-       if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) 
< 0)
-               perror("setsockopt (IP_OPTIONS)");
-#endif
-#if    defined(IPPROTO_IP) && defined(IP_TOS)
+      sin.sin_port = sp->s_port;
+    }
+  else
+    sin.sin_port = htons (sin.sin_port);
+  
+  printf("Trying %s...\n", inet_ntoa(sin.sin_addr));
+  do
+    {
+      net = socket(AF_INET, SOCK_STREAM, 0);
+      if (net < 0)
        {
-# if   defined(HAS_GETTOS)
-           struct tosent *tp;
-           if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
-               tos = tp->t_tos;
-# endif
-           if (tos < 0)
-               tos = 020;      /* Low Delay bit */
-           if (tos
-               && (setsockopt(net, IPPROTO_IP, IP_TOS,
-                   (char *)&tos, sizeof(int)) < 0)
-               && (errno != ENOPROTOOPT))
-                   perror("telnet: setsockopt (IP_TOS) (ignored)");
+         perror("telnet: socket");
+         return 0;
        }
+#if defined(IPPROTO_IP) && defined(IP_TOS)
+      {
+#ifdef IPTOS_LOWDELAY
+       const int tos = IPTOS_LOWDELAY;
+#else
+       const int tos = 0x10;
+#endif
+
+       err = setsockopt (net, IPPROTO_IP, IP_TOS,
+                         (char *)&tos, sizeof(tos));
+       if (err < 0 && errno != ENOPROTOOPT)
+         perror("telnet: setsockopt (IP_TOS) (ignored)");
+      }
 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
 
-       if (debug && SetSockOpt(net, SOL_SOCKET, SO_DEBUG, 1) < 0) {
-               perror("setsockopt (SO_DEBUG)");
-       }
+      if (debug && setsockopt(net, SOL_SOCKET, SO_DEBUG, &on, sizeof(on)) < 0)
+       perror("setsockopt (SO_DEBUG)");
 
-       if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0) {
-#if    defined(h_addr)         /* In 4.3, this is a #define */
-           if (host && host->h_addr_list[1]) {
-               int oerrno = errno;
-
-               fprintf(stderr, "telnet: connect to address %s: ",
-                                               inet_ntoa(sin.sin_addr));
-               errno = oerrno;
-               perror((char *)0);
-               host->h_addr_list++;
-               memmove((caddr_t)&sin.sin_addr,
-                       host->h_addr_list[0], host->h_length);
-               (void) NetClose(net);
-               continue;
+      if (connect(net, (struct sockaddr *)&sin, sizeof (sin)) < 0)
+       {
+         if (host && host->h_addr_list[1])
+           {
+             int oerrno = errno;
+
+             fprintf(stderr, "telnet: connect to address %s: ",
+                     inet_ntoa(sin.sin_addr));
+             errno = oerrno;
+             perror((char *)0);
+             host->h_addr_list++;
+             memmove((caddr_t)&sin.sin_addr,
+                     host->h_addr_list[0], host->h_length);
+             close (net);
+             continue;
            }
-#endif /* defined(h_addr) */
-           perror("telnet: Unable to connect to remote host");
-           return 0;
+         perror("telnet: Unable to connect to remote host");
+         return 0;
        }
-       connected++;
+      connected++;
 #if    defined(AUTHENTICATION) || defined(ENCRYPTION)
-       auth_encrypt_connect(connected);
+      auth_encrypt_connect(connected);
 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
     } while (connected == 0);
-    cmdrc(hostp, hostname);
-    if (autologin && user == NULL) {
-       struct passwd *pw;
-
-       user = getenv("USER");
-       if (user == NULL ||
-           (pw = getpwnam(user)) && pw->pw_uid != getuid()) {
-               if (pw = getpwuid(getuid()))
-                       user = pw->pw_name;
-               else
-                       user = NULL;
+#endif /* !IPV6 */
+  cmdrc(hostp, hostname);
+  if (autologin && user == NULL)
+    {
+      struct passwd *pw;
+
+      user = getenv("USER");
+      if (user == NULL ||
+         (pw = getpwnam(user)) && pw->pw_uid != getuid())
+       {
+         if (pw = getpwuid(getuid()))
+           user = pw->pw_name;
+         else
+           user = NULL;
        }
     }
-    if (user) {
-       env_define((unsigned char *)"USER", (unsigned char *)user);
-       env_export((unsigned char *)"USER");
+  if (user)
+    {
+      env_define((unsigned char *)"USER", (unsigned char *)user);
+      env_export((unsigned char *)"USER");
     }
-    (void) call(status, "status", "notmuch", 0);
-    if (setjmp(peerdied) == 0)
-       telnet(user);
-    (void) NetClose(net);
-    ExitString("Connection closed by foreign host.\n",1);
-    /*NOTREACHED*/
+  (void) call(status, "status", "notmuch", 0);
+  if (setjmp(peerdied) == 0)
+    telnet(user);
+
+  close (net);
+  ExitString("Connection closed by foreign host.\n",1);
+  /*NOTREACHED*/
+
+  return 0;
 }
 
 #define HELPINDENT (sizeof ("connect"))
@@ -2755,176 +2829,3 @@ cmdrc(char *m1, char *m2)
     }
     fclose(rcfile);
 }
-
-#if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
-
-/*
- * Source route is handed in as
- *     address@hidden@hop2...[@|:]dst
- * If the leading ! is present, it is a
- * strict source route, otherwise it is
- * assmed to be a loose source route.
- *
- * We fill in the source route option as
- *     hop1,hop2,hop3...dest
- * and return a pointer to hop1, which will
- * be the address to connect() to.
- *
- * Arguments:
- *     arg:    pointer to route list to decipher
- *
- *     cpp:    If *cpp is not equal to NULL, this is a
- *             pointer to a pointer to a character array
- *             that should be filled in with the option.
- *
- *     lenp:   pointer to an integer that contains the
- *             length of *cpp if *cpp != NULL.
- *
- * Return values:
- *
- *     Returns the address of the host to connect to.  If the
- *     return value is -1, there was a syntax error in the
- *     option, either unknown characters, or too many hosts.
- *     If the return value is 0, one of the hostnames in the
- *     path is unknown, and *cpp is set to point to the bad
- *     hostname.
- *
- *     *cpp:   If *cpp was equal to NULL, it will be filled
- *             in with a pointer to our static area that has
- *             the option filled in.  This will be 32bit aligned.
- *
- *     *lenp:  This will be filled in with how long the option
- *             pointed to by *cpp is.
- *
- */
-unsigned long
-sourceroute(char *arg, char **cpp, int *lenp)
-{
-       static char lsr[44];
-#ifdef sysV88
-       static IOPTN ipopt;
-#endif
-       char *cp, *cp2, *lsrp, *lsrep;
-       register int tmp;
-       struct in_addr sin_addr;
-       register struct hostent *host = 0;
-       register char c;
-
-       /*
-        * Verify the arguments, and make sure we have
-        * at least 7 bytes for the option.
-        */
-       if (cpp == NULL || lenp == NULL)
-               return((unsigned long)-1);
-       if (*cpp != NULL && *lenp < 7)
-               return((unsigned long)-1);
-       /*
-        * Decide whether we have a buffer passed to us,
-        * or if we need to use our own static buffer.
-        */
-       if (*cpp) {
-               lsrp = *cpp;
-               lsrep = lsrp + *lenp;
-       } else {
-               *cpp = lsrp = lsr;
-               lsrep = lsrp + 44;
-       }
-
-       cp = arg;
-
-       /*
-        * Next, decide whether we have a loose source
-        * route or a strict source route, and fill in
-        * the begining of the option.
-        */
-#ifndef        sysV88
-       if (*cp == '!') {
-               cp++;
-               *lsrp++ = IPOPT_SSRR;
-       } else
-               *lsrp++ = IPOPT_LSRR;
-#else
-       if (*cp == '!') {
-               cp++;
-               ipopt.io_type = IPOPT_SSRR;
-       } else
-               ipopt.io_type = IPOPT_LSRR;
-#endif
-
-       if (*cp != '@')
-               return((unsigned long)-1);
-
-#ifndef        sysV88
-       lsrp++;         /* skip over length, we'll fill it in later */
-       *lsrp++ = 4;
-#endif
-
-       cp++;
-
-       sin_addr.s_addr = 0;
-
-       for (c = 0;;) {
-               if (c == ':')
-                       cp2 = 0;
-               else for (cp2 = cp; c = *cp2; cp2++) {
-                       if (c == ',') {
-                               *cp2++ = '\0';
-                               if (*cp2 == '@')
-                                       cp2++;
-                       } else if (c == '@') {
-                               *cp2++ = '\0';
-                       } else if (c == ':') {
-                               *cp2++ = '\0';
-                       } else
-                               continue;
-                       break;
-               }
-               if (!c)
-                       cp2 = 0;
-
-               if ((tmp = inet_addr(cp)) != -1) {
-                       sin_addr.s_addr = tmp;
-               } else if (host = gethostbyname(cp)) {
-#if    defined(h_addr)
-                       memmove((caddr_t)&sin_addr,
-                               host->h_addr_list[0], host->h_length);
-#else
-                       memmove((caddr_t)&sin_addr, host->h_addr, 
host->h_length);
-#endif
-               } else {
-                       *cpp = cp;
-                       return(0);
-               }
-               memmove(lsrp, (char *)&sin_addr, 4);
-               lsrp += 4;
-               if (cp2)
-                       cp = cp2;
-               else
-                       break;
-               /*
-                * Check to make sure there is space for next address
-                */
-               if (lsrp + 4 > lsrep)
-                       return((unsigned long)-1);
-       }
-#ifndef        sysV88
-       if ((*(*cpp+IPOPT_OLEN) = lsrp - *cpp) <= 7) {
-               *cpp = 0;
-               *lenp = 0;
-               return((unsigned long)-1);
-       }
-       *lsrp++ = IPOPT_NOP; /* 32 bit word align it */
-       *lenp = lsrp - *cpp;
-#else
-       ipopt.io_len = lsrp - *cpp;
-       if (ipopt.io_len <= 5) {                /* Is 3 better ? */
-               *cpp = 0;
-               *lenp = 0;
-               return((unsigned long)-1);
-       }
-       *lenp = sizeof(ipopt);
-       *cpp = (char *) &ipopt;
-#endif
-       return(sin_addr.s_addr);
-}
-#endif
Index: telnet/main.c
===================================================================
RCS file: /cvsroot/inetutils/inetutils/telnet/main.c,v
retrieving revision 1.13
diff -u -p -r1.13 main.c
--- telnet/main.c       29 Apr 2002 21:22:31 -0000      1.13
+++ telnet/main.c       6 Jul 2004 22:06:43 -0000
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1988, 1990, 1993, 2002
+ * Copyright (c) 1988, 1990, 1993
  *     The Regents of the University of California.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -27,15 +27,9 @@
  * SUCH DAMAGE.
  */
 
-#ifndef lint
-static char copyright[] =
-"@(#) Copyright (c) 1988, 1990, 1993\n\
-       The Regents of the University of California.  All rights reserved.\n";
-#endif /* not lint */
-
-#ifndef lint
+#if 0
 static char sccsid[] = "@(#)main.c     8.3 (Berkeley) 5/30/95";
-#endif /* not lint */
+#endif
 
 #ifdef HAVE_CONFIG_H
 #include <config.h>
@@ -44,6 +38,7 @@ static char sccsid[] = "@(#)main.c    8.3 (
 #include <sys/types.h>
 
 #include <getopt.h>
+#include <stdlib.h>
 
 #include "ring.h"
 #include "externs.h"
@@ -87,6 +82,8 @@ help ()
   fprintf (stdout, USAGE, prompt);
 
   puts ("Login to remote system HOST (optionally, on service port PORT)\n\n\
+  -4, --ipv4                 Use only IPv4\n\
+  -6, --ipv6                 Use only IPv6\n\
   -8, --binary               Use an 8-bit data path\n\
   -a, --login                Attempt automatic login\n\
   -c, --no-rc                Don't read the user's .telnetrc file\n\
@@ -98,7 +95,6 @@ help ()
   -L, --binary-output        Use an 8-bit data path for output only\n\
   -n FILE, --trace=FILE      Record trace information into FILE\n\
   -r, --rlogin               Use a user-interface similar to rlogin\n\
-  -S TOS, --tos=TOS          Use the IP type-of-service TOS\n\
   -X ATYPE, --disable-auth=ATYPE   Disable type ATYPE authentication");
 
 #ifdef ENCRYPTION
@@ -155,6 +151,8 @@ usage ()
 
 static struct option long_options[] =
 {
+  { "ipv4", no_argument, 0, '4'},
+  { "ipv6", no_argument, 0, '6'},
   { "binary", no_argument, 0, '8' },
   { "login", no_argument, 0, 'a' },
   { "no-rc", no_argument, 0, 'c' },
@@ -166,7 +164,6 @@ static struct option long_options[] =
   { "binary-output", no_argument, 0, 'L' },
   { "trace", required_argument, 0, 'n' },
   { "rlogin", no_argument, 0, 'r' },
-  { "tos", required_argument, 0, 'S' },
   { "disable-auth", required_argument, 0, 'X' },
   { "encrypt", no_argument, 0, 'x' },
   { "fwd-credentials", no_argument, 0, 'f' },
@@ -186,6 +183,7 @@ main(int argc, char *argv[])
        extern char *optarg;
        extern int optind;
        int ch;
+       int family = 0;
        char *user;
 #ifndef strrchr
        char *strrchr();
@@ -211,11 +209,19 @@ main(int argc, char *argv[])
        rlogin = (strncmp(prompt, "rlog", 4) == 0) ? '~' : _POSIX_VDISABLE;
        autologin = -1;
 
-       while ((ch = getopt_long (argc, argv, "8EKLS:X:acde:fFk:l:n:rt:x",
+       while ((ch = getopt_long (argc, argv, "468EKLS:X:acde:fFk:l:n:rt:x",
                                  long_options, 0))
               != EOF)
        {
                switch(ch) {
+               case '4':
+                       family = 4;
+                       break;
+
+               case '6':
+                       family = 6;
+                       break;
+                       
                case '8':
                        eight = 3;      /* binary output and input */
                        break;
@@ -230,23 +236,6 @@ main(int argc, char *argv[])
                case 'L':
                        eight |= 2;     /* binary output only */
                        break;
-               case 'S':
-                   {
-#ifdef HAS_GETTOS
-                       extern int tos;
-
-                       if ((tos = parsetos(optarg, "tcp")) < 0)
-                               fprintf(stderr, "%s%s%s%s\n",
-                                       prompt, ": Bad TOS argument '",
-                                       optarg,
-                                       "; will try to use default TOS");
-#else
-                       fprintf(stderr,
-                          "%s: Warning: -S ignored, no parsetos() support.\n",
-                                                               prompt);
-#endif
-                   }
-                       break;
                case 'X':
 #ifdef AUTHENTICATION
                        auth_disable_name(optarg);
@@ -374,7 +363,7 @@ main(int argc, char *argv[])
        argv += optind;
 
        if (argc) {
-               char *args[7], **argp = args;
+               char *args[8], **argp = args;
 
                if (argc > 2)
                        usage ();
@@ -383,6 +372,11 @@ main(int argc, char *argv[])
                        *argp++ = "-l";
                        *argp++ = user;
                }
+               if (family == 4)
+                 *argp++ = "-4";
+               else if (family == 6)
+                 *argp++ = "-6";
+
                *argp++ = argv[0];              /* host */
                if (argc > 1)
                        *argp++ = argv[1];      /* port */
Index: telnetd/telnetd.c
===================================================================
RCS file: /cvsroot/inetutils/inetutils/telnetd/telnetd.c,v
retrieving revision 1.31
diff -u -p -r1.31 telnetd.c
--- telnetd/telnetd.c   5 Apr 2003 16:45:08 -0000       1.31
+++ telnetd/telnetd.c   6 Jul 2004 22:06:43 -0000
@@ -1,4 +1,4 @@
-/* Copyright (C) 1998,2001, 2002 Free Software Foundation, Inc.
+/* Copyright (C) 1998, 2001, 2002, 2004x Free Software Foundation, Inc.
 
    This file is part of GNU Inetutils.
 
@@ -275,10 +275,16 @@ extern char *localhost __P ((void));
 void
 telnetd_setup (int fd)
 {
+#ifdef IPV6
+  struct sockaddr_storage saddr;
+  char buf[256], buf2[256]; /* FIXME: We should use dynamic allocation. */
+  int err;
+#else
   struct sockaddr_in saddr;
+  struct hostent *hp;
+#endif
   int true = 1;
   socklen_t len;
-  struct hostent *hp;
   char uname[256]; /*FIXME*/
   int level;
  
@@ -289,8 +295,84 @@ telnetd_setup (int fd)
       exit (1);
     }
 
-  syslog (LOG_INFO, "Connect from %s", inet_ntoa (saddr.sin_addr));
-  
+#ifdef IPV6
+  err = getnameinfo ((struct sockaddr *) &saddr, sizeof (saddr), buf,
+                    sizeof (buf), NULL, 0, NI_NUMERICHOST);
+  if (err)
+    {
+      const char *errmsg;
+      
+      if (err == EAI_SYSTEM)
+       errmsg = strerror (errno);
+      else
+       errmsg = gai_strerror (err);
+      
+      syslog (LOG_AUTH|LOG_NOTICE, "Cannot get address: %s", errmsg);
+      fatal (fd, "Cannot get address.");
+    }
+
+  /* We use a second buffer so we don't have to call getnameinfo again
+     if we need the numeric host below.  */
+  err = getnameinfo ((struct sockaddr *) &saddr, sizeof (saddr), buf2,
+                    sizeof (buf2), NULL, 0, NI_NAMEREQD);
+
+  if (reverse_lookup)
+    {
+      struct addrinfo *result, *aip;
+
+      if (err)
+       {
+         const char *errmsg;
+         
+         if (err == EAI_SYSTEM)
+           errmsg = strerror (errno);
+         else
+           errmsg = gai_strerror (err);
+         
+         syslog (LOG_AUTH|LOG_NOTICE, "Can't resolve %s: %s", buf, errmsg);
+         fatal (fd, "Cannot resolve address.");
+       }
+
+      remote_hostname = xstrdup (buf2);
+
+      err = getaddrinfo (remote_hostname, NULL, NULL, &result);
+      if (err)
+       {
+         const char *errmsg;
+         
+         if (err == EAI_SYSTEM)
+           errmsg = strerror (errno);
+         else
+           errmsg = gai_strerror (err);
+         
+         syslog (LOG_AUTH|LOG_NOTICE, "Forward resolve of %s failed: %s",
+                 remote_hostname, errmsg);
+         fatal (fd, "Cannot resolve address.");
+       }
+
+      for (aip = result; aip; aip = aip->ai_next)
+       if (!memcmp (aip->ai_addr, &saddr, aip->ai_addrlen))
+         break;
+
+      if (aip == NULL)
+       {
+         syslog (LOG_AUTH|LOG_NOTICE,
+                 "None of addresses of %s matched %s",
+                 remote_hostname,
+                 buf);
+         exit (0);
+       }
+
+      freeaddrinfo (result);
+    }
+  else
+    {
+      if (!err)
+       remote_hostname = xstrdup (buf2);
+      else
+       remote_hostname = xstrdup (buf);
+    }
+#else
   hp = gethostbyaddr ((char*)&saddr.sin_addr.s_addr,
                      sizeof (saddr.sin_addr.s_addr), AF_INET);
   if (reverse_lookup)
@@ -337,6 +419,7 @@ telnetd_setup (int fd)
       else
        remote_hostname = xstrdup (inet_ntoa (saddr.sin_addr));
     }
+#endif
   
   /* Set socket options */
 




reply via email to

[Prev in Thread] Current Thread [Next in Thread]