bug-inetutils
[Top][All Lists]
Advanced

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

Re: [bug-inetutils] IPv6 support for inetd, telnet and telnetd


From: Jeroen Dekkers
Subject: Re: [bug-inetutils] IPv6 support for inetd, telnet and telnetd
Date: Wed, 19 May 2004 21:19:00 +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)

At Wed, 19 May 2004 19:59:16 +0200,
Göran Weinholt wrote:
> 
> On Mon, Apr 19, 2004 at 04:36:31PM +0200, Jeroen Dekkers wrote:
> > Hi, 
> > 
> > the patch below implements IPv6 support for inetd, telnet and
> > telnetd.  I also cleaned up telnet some bit, removing source routing
> > (I don't think anyone allows you to do that nowadays) and code for
> > some obsolete TOS interface.  If you've any questions about the
> > patch, just ask. :)
> 
> I had a small problem with the patch against telnet (I haven't tested
> the rest.) It always connects to port 23, no matter what port you give
> it.
> 
> > +  telnetport = 0;
> > +  if (portp && *portp == '-')
> > +    {
> > +      portp++;
> > +      telnetport = 1;
> > +    }
> > +  else
> > +    {
> > +      telnetport = 1;
> > +      portp = "telnet";
> > +    }
> 
> The problem would appear to be here. Changing the else to "else if
> (!portp)" seems to fix it.

You're right, I've recoded the logic which should fix it. Here is a
new version of the patch:

2004-04-19  Jeroen Dekkers  <address@hidden>

        * configure.ac: Add checks for IPv6.

doc/
2004-04-19  Jeroen Dekkers  <address@hidden>

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

inetd/
2004-04-19  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.

telnet/
2004-04-19  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-04-19  Jeroen Dekkers  <address@hidden>

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

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        19 May 2004 18:58:04 -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>
 #
@@ -280,6 +280,65 @@ if test ".$LIBAUTH" != .; then
                    [Define to one if you want authentication.])
   test "$enable_encryption" = yes     && AC_DEFINE(ENCRYPTION, 1,
                    [Define to one if you want encryption.])
+fi
+
+dnl Checks for IPv6
+
+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]
+)
+
+if test ! "X$ipv6" = "Xno"; then
+  working_ipv6=yes
+
+  AC_MSG_CHECKING([for AF_INET6])
+  AC_COMPILE_IFELSE([AC_INCLUDES_DEFAULT
+#include <sys/socket.h>
+
+#ifndef AF_INET6
+#error Missing AF_INET6
+#endif
+  ], [AC_MSG_RESULT(yes)], [
+  AC_MSG_RESULT(no)
+  working_ipv6=no])
+
+  AC_MSG_CHECKING([for IPV6_V6ONLY])
+  AC_COMPILE_IFELSE([AC_INCLUDES_DEFAULT
+#include <netinet/in.h>
+
+#ifndef IPV6_V6ONLY
+#error Missing IPV6_V6ONLY
+#endif
+  ], [AC_MSG_RESULT(yes)], [
+  AC_MSG_RESULT(no)
+  working_ipv6=no])
+
+  AC_CHECK_TYPE(struct sockaddr_storage, , working_ipv6=no, [#include 
<sys/socket.h>])
+  AC_CHECK_TYPE(struct addrinfo, , working_ipv6=no, [#include <netdb.h>])
+
+  AC_CHECK_FUNC(getaddrinfo, ,working_ipv6=no, [#include <netdb.h>])
+  AC_CHECK_FUNC(getnameinfo, ,working_ipv6=no, [#include <netdb.h>])
+  
+  if test "X$working_ipv6" = "Xyes"; then
+    AC_MSG_NOTICE([Enabling IPv6])
+    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
+    AC_MSG_WARN([Disabling IPv6 support])
+    fi
+  fi
 fi
 
 dnl Check if they want support for Wrap.  Certain daemons like
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      19 May 2004 18:58:04 -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       19 May 2004 18:58:05 -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 },
 
@@ -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: 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   19 May 2004 18:58:05 -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       19 May 2004 18:58:05 -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>
@@ -87,6 +81,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 +94,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 +150,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 +163,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 +182,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 +208,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 +235,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 +362,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 +371,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   19 May 2004 18:58:15 -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.
 
@@ -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]