enable -fno-strict-aliasing until the code base gets a hefty clean up to fix all...
[platform/upstream/net-tools.git] / lib / inet6.c
index c5e058f..9a484a0 100644 (file)
@@ -3,7 +3,7 @@
  *              support functions for the net-tools.
  *              (most of it copied from lib/inet.c 1.26).
  *
- * Version:     $Id: inet6.c,v 1.5 1998/11/17 15:16:49 freitag Exp $
+ * Version:     $Id: inet6.c,v 1.12 2002/12/10 01:03:09 ecki Exp $
  *
  * Author:      Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
  *              Copyright 1993 MicroWalt Corporation
@@ -11,6 +11,7 @@
  * Modified:
  *960808 {0.01} Frank Strauss :         adapted for IPv6 support
  *980701 {0.02} Arnaldo C. Melo:        GNU gettext instead of catgets
+ *990824        Bernd Eckenfels:       clear members for selecting v6 address
  *
  *              This program is free software; you can redistribute it
  *              and/or  modify it under  the terms of  the GNU General
 #include "net-support.h"
 #include "pathnames.h"
 #include "intl.h"
+#include "util.h"
 
 extern int h_errno;            /* some netdb.h versions don't export this */
 
+char * fix_v4_address(char *buf, struct in6_addr *in6) 
+{ 
+       if (IN6_IS_ADDR_V4MAPPED(in6->s6_addr)) { 
+                       char *s =strchr(buf, '.'); 
+                       if (s) { 
+                               while (s > buf && *s != ':')
+                                       --s;
+                               if (*s == ':') ++s;     
+                               else s = NULL; 
+                       }       
+                       if (s) return s;
+       } 
+       return buf; 
+} 
+
 static int INET6_resolve(char *name, struct sockaddr_in6 *sin6)
 {
     struct addrinfo req, *ai;
     int s;
 
+    memset (&req, '\0', sizeof req);
     req.ai_family = AF_INET6;
     if ((s = getaddrinfo(name, NULL, &req, &ai))) {
-       fprintf(stderr, "getaddrinfo: %s: %s\n", name, gai_strerror(s));
+       fprintf(stderr, "getaddrinfo: %s: %d\n", name, s);
        return -1;
     }
     memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6));
@@ -59,6 +77,12 @@ static int INET6_resolve(char *name, struct sockaddr_in6 *sin6)
     return (0);
 }
 
+#ifndef IN6_IS_ADDR_UNSPECIFIED
+#define IN6_IS_ADDR_UNSPECIFIED(a) \
+        (((__u32 *) (a))[0] == 0 && ((__u32 *) (a))[1] == 0 && \
+         ((__u32 *) (a))[2] == 0 && ((__u32 *) (a))[3] == 0)
+#endif
+
 
 static int INET6_rresolve(char *name, struct sockaddr_in6 *sin6, int numeric)
 {
@@ -74,12 +98,20 @@ static int INET6_rresolve(char *name, struct sockaddr_in6 *sin6, int numeric)
        return (-1);
     }
     if (numeric & 0x7FFF) {
-       inet_ntop(AF_INET6, &sin6->sin6_addr, name, 80);
+       inet_ntop( AF_INET6, &sin6->sin6_addr, name, 80);
+       return (0);
+    }
+    if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
+        if (numeric & 0x8000)
+           strcpy(name, "default");
+       else
+           strcpy(name, "[::]");
        return (0);
     }
+
     if ((s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6),
                         name, 255 /* !! */ , NULL, 0, 0))) {
-       fprintf(stderr, "getnameinfo: %s\n", gai_strerror(s));
+       fputs("getnameinfo failed\n", stderr);
        return -1;
     }
     return (0);
@@ -92,13 +124,14 @@ static void INET6_reserror(char *text)
 }
 
 
+
 /* Display an Internet socket address. */
 static char *INET6_print(unsigned char *ptr)
 {
     static char name[80];
 
     inet_ntop(AF_INET6, (struct in6_addr *) ptr, name, 80);
-    return name;
+       return fix_v4_address(name, (struct in6_addr *)ptr);
 }
 
 
@@ -111,14 +144,15 @@ static char *INET6_sprint(struct sockaddr *sap, int numeric)
     if (sap->sa_family == 0xFFFF || sap->sa_family == 0)
        return safe_strncpy(buff, _("[NONE SET]"), sizeof(buff));
     if (INET6_rresolve(buff, (struct sockaddr_in6 *) sap, numeric) != 0)
-       return (NULL);
-    return (buff);
+       return safe_strncpy(buff, _("[UNKNOWN]"), sizeof(buff));
+    return (fix_v4_address(buff, &((struct sockaddr_in6 *)sap)->sin6_addr));
 }
 
 
 static int INET6_getsock(char *bufp, struct sockaddr *sap)
 {
     struct sockaddr_in6 *sin6;
+       char *p;
 
     sin6 = (struct sockaddr_in6 *) sap;
     sin6->sin6_family = AF_INET6;
@@ -126,7 +160,9 @@ static int INET6_getsock(char *bufp, struct sockaddr *sap)
 
     if (inet_pton(AF_INET6, bufp, sin6->sin6_addr.s6_addr) <= 0)
        return (-1);
-
+       p = fix_v4_address(bufp, &sin6->sin6_addr);
+       if (p != bufp) 
+               memcpy(bufp, p, strlen(p)+1); 
     return 16;                 /* ?;) */
 }