ipv6 support, except if source routing is requested (may be broken)
authorKen Raeburn <raeburn@mit.edu>
Thu, 30 Aug 2001 19:26:13 +0000 (19:26 +0000)
committerKen Raeburn <raeburn@mit.edu>
Thu, 30 Aug 2001 19:26:13 +0000 (19:26 +0000)
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13698 dc483132-0cff-0310-8789-dd5450dbe970

src/appl/telnet/telnet/ChangeLog
src/appl/telnet/telnet/commands.c
src/appl/telnet/telnet/configure.in

index 33e667bb4c29a85d6d30d6429cf7d061bc3f7e5a..d7d87fb0c177a32764102e87c46ea839466351e4 100644 (file)
@@ -1,3 +1,17 @@
+2001-08-30  Ken Raeburn  <raeburn@mit.edu>
+
+       * commands.c: Include netdb.h and fake-addrinfo.c.
+       (FAI_PREFIX): Define.
+       (hostaddr): Deleted.
+       (hostaddrstring): New static variable.
+       (status): Use hostaddrstring instead of hostaddr.
+       (tn): Use get{addr,name}info instead of gethostby{name,addr}, and
+       attempt to connect to both IPv6 and IPv4 sockets.  Add workarounds
+       for GNU libc bugs.  Fill in hostaddrstring with printable form of
+       each net address.  Source routing is still IPv4-only.
+
+       * configure.in: Run KRB5_AC_INET6.
+
 2001-08-29  Ken Raeburn  <raeburn@mit.edu>
 
        * telnet.c (setupterm): Now static.
index 4ac736e4e3caaf6f49a7863d4aa083eea30084aa..ef4d3eeca11387c622e3c3307b22002c469d2758 100644 (file)
 #if HAVE_ARPA_NAMESER_H
 #include <arpa/nameser.h>
 #endif
+#include <netdb.h>
 
 #ifndef MAXDNAME
 #define MAXDNAME 256 /*per the rfc*/
@@ -118,9 +119,12 @@ int tos = -1;
 static unsigned long sourceroute(char *, char **, int *);
 #endif /* defined(IPPROTO_IP) && defined(IP_TOS) */
 
+#define FAI_PREFIX telnet
+#include "fake-addrinfo.c"
+
 char   *hostname;
 static char _hostname[MAXDNAME];
-struct in_addr hostaddr;
+static char hostaddrstring[NI_MAXHOST];
 
 extern char *getenv();
 
@@ -2314,7 +2318,7 @@ status(argc, argv)
     char *argv[];
 {
     if (connected) {
-       printf("Connected to %s (%s).\r\n", hostname, inet_ntoa(hostaddr));
+       printf("Connected to %s (%s).\r\n", hostname, hostaddrstring);
        if ((argc < 2) || strcmp(argv[1], "notmuch")) {
            int mode = getconnmode();
 
@@ -2402,18 +2406,14 @@ tn(argc, argv)
     int argc;
     char *argv[];
 {
-    register struct hostent *host = 0;
-    struct sockaddr_in sin4;
-    struct servent *sp = 0;
-    unsigned long temp;
 #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
     char *srp = 0;
     int srlen;
 #endif
     char *cmd, *hostp = 0, *portp = 0, *volatile user = 0;
-
-    /* clear the socket address prior to use */
-    memset((char *)&sin4, 0, sizeof(sin4));
+    struct addrinfo *addrs = 0, *addrp;
+    struct addrinfo hints;
+    int error;
 
     if (connected) {
        printf("?Already connected to %s\r\n", hostname);
@@ -2462,8 +2462,22 @@ tn(argc, argv)
     if (hostp == 0)
        goto usage;
 
+    if (portp) {
+       if (*portp == '-') {
+           portp++;
+           telnetport = 1;
+       } else
+           telnetport = 0;
+    } else {
+       portp = "telnet";
+       telnetport = 1;
+    }
+
 #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
     if (hostp[0] == '@' || hostp[0] == '!') {
+       static struct sockaddr_in sr_sin4;
+       static struct addrinfo sr_addr;
+       unsigned long temp;
        if ((hostname = strrchr(hostp, ':')) == NULL)
            hostname = strrchr(hostp, '@');
        hostname++;
@@ -2476,83 +2490,110 @@ tn(argc, argv)
            printf("Bad source route option: %s\r\n", hostp);
            return 0;
        } else {
-           sin4.sin_addr.s_addr = temp;
-           sin4.sin_family = AF_INET;
+           sr_sin4.sin_addr.s_addr = temp;
+           sr_sin4.sin_family = AF_INET;
+#ifdef HAVE_SA_LEN
+           sr_sin4.sin_len = sizeof (sr_sin4);
+#endif
+           sr_addr.ai_family = AF_INET;
+           sr_addr.ai_addrlen = sizeof (sr_sin4);
+           sr_addr.ai_addr = (struct sockaddr *) &sr_sin4;
+           sr_addr.ai_next = 0;
+           sr_addr.ai_canonname = hostname;
+           addrs = &sr_addr;
        }
     } else {
 #endif
-       temp = inet_addr(hostp);
-       if ((temp & 0xffffffff) != INADDR_NONE) {
-           sin4.sin_addr.s_addr = temp;
-           sin4.sin_family = AF_INET;
-           (void) strncpy(_hostname, hostp, sizeof(_hostname) - 1);  
-           _hostname[sizeof(_hostname) - 1] = '\0';
-           hostname = _hostname;
-       } else {
-           host = gethostbyname(hostp);
-           if (host) {
-               sin4.sin_family = host->h_addrtype;
-#if    defined(h_addr)         /* In 4.3, this is a #define */
-               memcpy((caddr_t)&sin4.sin_addr,
-                      host->h_addr_list[0], sizeof(sin4.sin_addr));
-#else  /* defined(h_addr) */
-               memcpy((caddr_t)&sin4.sin_addr, host->h_addr, 
-                      sizeof(sin4.sin_addr)); 
-#endif /* defined(h_addr) */
-               strncpy(_hostname, host->h_name, sizeof(_hostname));
-               _hostname[sizeof(_hostname)-1] = '\0';
+       memset (&hints, 0, sizeof (hints));
+       hints.ai_socktype = SOCK_STREAM;
+       hints.ai_family = PF_UNSPEC;
+
+
+       /* The GNU Libc (Red Hat Linux 6.1, on x86, which MIT is using
+          at this time) implementation seems to completely ignore
+          AI_NUMERICHOST, and contacts DNS anyways.  But other
+          versions will not, and we do want to treat the two cases a
+          little differently.  */
+#ifdef AF_INET6
+#define IS_NUMERIC_ADDR(P) \
+       ('\0' == (P)[strspn((P), (strchr((P),':') ? "abcdefABCDEF:0123456789." : "0123456789."))])
+#else
+#define IS_NUMERIC_ADDR(P) \
+       ('\0' == (P)[strspn((P), "0123456789.")])
+#endif
+       if (! IS_NUMERIC_ADDR (hostp))
+           goto not_numeric;
+
+
+       hints.ai_flags = AI_NUMERICHOST;
+       error = getaddrinfo (hostp, portp, &hints, &addrs);
+       if (error == 0) {
+           if (getnameinfo (addrs->ai_addr, addrs->ai_addrlen,
+                            _hostname, sizeof(_hostname), 0, 0, NI_NAMEREQD) == 0)
                hostname = _hostname;
+       } else {
+       not_numeric:
+           hints.ai_flags = AI_CANONNAME;
+           error = getaddrinfo (hostp, portp, &hints, &addrs);
+           if (error == 0) {
+
+               /* Stupid glibc lossage again.  */
+               if (! IS_NUMERIC_ADDR (addrs->ai_canonname)) {
+                   strncpy(_hostname, addrs->ai_canonname, sizeof(_hostname));
+               } else {
+                   fprintf (stderr,
+                            "telnet: system library bug? getaddrinfo returns numeric address\n"
+                            "\tas canonical name of %s\n",
+                            hostp);
+                   strncpy(_hostname, hostp, sizeof (_hostname));
+               }
+
            } else {
-               herror(hostp);
-               return 0;
+               strncpy(_hostname, hostp, sizeof (_hostname));
            }
+           hostname = _hostname;
+       }
+       if (error) {
+           fprintf (stderr, "%s/%s: %s\n", hostp, portp, gai_strerror (error));
+           return 0;
        }
 #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
     }
 #endif
-    hostaddr.s_addr = sin4.sin_addr.s_addr;
-    if (portp) {
-       if (*portp == '-') {
-           portp++;
-           telnetport = 1;
-       } else
-           telnetport = 0;
-       sin4.sin_port = atoi(portp);
-       if (sin4.sin_port == 0) {
-           sp = getservbyname(portp, "tcp");
-           if (sp)
-               sin4.sin_port = sp->s_port;
-           else {
-               printf("%s: bad port number\r\n", portp);
-               return 0;
-           }
-       } else {
-           sin4.sin_port = htons(sin4.sin_port);
-       }
-    } else {
-       if (sp == 0) {
-           sp = getservbyname("telnet", "tcp");
-           if (sp == 0) {
-               fprintf(stderr, "telnet: tcp/telnet: unknown service\n");
-               return 0;
-           }
-           sin4.sin_port = sp->s_port;
+    for (addrp = addrs; addrp && !connected; addrp = addrp->ai_next) {
+       error = getnameinfo (addrp->ai_addr, addrp->ai_addrlen,
+                            hostaddrstring, sizeof (hostaddrstring),
+                            (char *) NULL, 0, NI_NUMERICHOST);
+       if (error) {
+           fprintf (stderr, "getnameinfo() error printing address: %s\n",
+                    gai_strerror (error));
+           strcpy (hostaddrstring, "[address unprintable]");
+       }
+       printf("Trying %s...\r\n", hostaddrstring);
+#if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
+       if (srp && addrp->ai_family != AF_INET) {
+           printf ("source routing not supported (yet) for address family,"
+                   " trying another address\n");
+           continue;
        }
-       telnetport = 1;
-    }
-    printf("Trying %s...\r\n", inet_ntoa(sin4.sin_addr));
-    do {
-       net = socket(AF_INET, SOCK_STREAM, 0);
+#endif
+       net = socket(addrp->ai_family, SOCK_STREAM, 0);
        if (net < 0) {
            perror("telnet: socket");
-           return 0;
+           continue;
        }
 #if    defined(IP_OPTIONS) && defined(IPPROTO_IP)
-       if (srp && setsockopt(net, IPPROTO_IP, IP_OPTIONS, (char *)srp, srlen) < 0)
+       if (srp) {
+           if (addrp->ai_family != AF_INET)
+               printf ("source routing not supported (yet)"
+                       " for address family\n");
+           else if (setsockopt(net, IPPROTO_IP, IP_OPTIONS,
+                               (char *)srp, srlen) < 0)
                perror("setsockopt (IP_OPTIONS)");
+       }
 #endif
 #if    defined(IPPROTO_IP) && defined(IP_TOS)
-       {
+       if (addrp->ai_family == AF_INET) {
 # if   defined(HAVE_GETTOSBYNAME)
            struct tosent *tp;
            if (tos < 0 && (tp = gettosbyname("telnet", "tcp")))
@@ -2572,40 +2613,24 @@ tn(argc, argv)
                perror("setsockopt (SO_DEBUG)");
        }
 
-       if (connect(net, (struct sockaddr *)&sin4, sizeof (sin4)) < 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(sin4.sin_addr));
-               errno = oerrno;
-               perror((char *)0);
-               host->h_addr_list++;
-               memcpy((caddr_t)&sin4.sin_addr, 
-                       host->h_addr_list[0], sizeof(sin4.sin_addr));
-               memcpy((caddr_t)&hostaddr,
-                      host->h_addr_list[0], sizeof(sin4.sin_addr));
+       if (connect(net, addrp->ai_addr, addrp->ai_addrlen) < 0) {
+           if (hostaddrstring[0]) {
+               fprintf(stderr, "telnet: connect to address %s: %s\n",
+                       hostaddrstring, strerror (errno));
                (void) NetClose(net);
                continue;
            }
-#endif /* defined(h_addr) */
-           perror("telnet: Unable to connect to remote host");
-           return 0;
        }
        connected++;
-       host = gethostbyaddr((char *) &sin4.sin_addr, sizeof(struct in_addr),
-                            sin4.sin_family);
-           if (host) {
-             strncpy(_hostname, host->h_name, sizeof(_hostname));
-               _hostname[sizeof(_hostname)-1] = '\0';
-               hostname = _hostname;
-           } 
 
 #if    defined(AUTHENTICATION) || defined(ENCRYPTION)
        auth_encrypt_connect(connected);
 #endif /* defined(AUTHENTICATION) || defined(ENCRYPTION) */
-    } while (connected == 0);
+    }
+    if (!connected) {
+       perror("telnet: Unable to connect to remote host");
+       return 0;
+    }
     if (user)
       user = strdup(user);
     if (hostp)
index 74cc1c706fa8736c1dd32a7ad1b7069fe3967baf..3a77cd64637d76d62e0d0769dbeeb0e5bbfce187 100644 (file)
@@ -9,6 +9,7 @@ LIBS="$LIBS -ltermcap",
   AC_CHECK_LIB(curses,setupterm,LIBS="$LIBS -lcurses",
   AC_CHECK_LIB(ncurses,setupterm,LIBS="$LIBS -lncurses")
 ))
+KRB5_AC_INET6
 AC_CHECK_FUNCS(gettosbyname setupterm)
 AC_CHECK_HEADER(termios.h,AC_DEFINE(USE_TERMIO) ac_termio=1)
 if test -z "$ac_termio"; then