Back to index

glibc  2.9
inet_ntop.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1996-1999 by Internet Software Consortium.
00003  *
00004  * Permission to use, copy, modify, and distribute this software for any
00005  * purpose with or without fee is hereby granted, provided that the above
00006  * copyright notice and this permission notice appear in all copies.
00007  *
00008  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
00009  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
00010  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
00011  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
00012  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
00013  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
00014  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00015  * SOFTWARE.
00016  */
00017 
00018 #if defined(LIBC_SCCS) && !defined(lint)
00019 static const char rcsid[] = "$BINDId: inet_ntop.c,v 1.8 1999/10/13 16:39:28 vixie Exp $";
00020 #endif /* LIBC_SCCS and not lint */
00021 
00022 #include <sys/param.h>
00023 #include <sys/types.h>
00024 #include <sys/socket.h>
00025 
00026 #include <netinet/in.h>
00027 #include <arpa/inet.h>
00028 #include <arpa/nameser.h>
00029 
00030 #include <errno.h>
00031 #include <stdio.h>
00032 #include <string.h>
00033 
00034 #ifdef SPRINTF_CHAR
00035 # define SPRINTF(x) strlen(sprintfx)
00036 #else
00037 # define SPRINTF(x) ((size_t)sprintf x)
00038 #endif
00039 
00040 /*
00041  * WARNING: Don't even consider trying to compile this on a system where
00042  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
00043  */
00044 
00045 static const char *inet_ntop4 (const u_char *src, char *dst, socklen_t size)
00046      internal_function;
00047 static const char *inet_ntop6 (const u_char *src, char *dst, socklen_t size)
00048      internal_function;
00049 
00050 /* char *
00051  * inet_ntop(af, src, dst, size)
00052  *     convert a network format address to presentation format.
00053  * return:
00054  *     pointer to presentation format address (`dst'), or NULL (see errno).
00055  * author:
00056  *     Paul Vixie, 1996.
00057  */
00058 const char *
00059 inet_ntop(af, src, dst, size)
00060        int af;
00061        const void *src;
00062        char *dst;
00063        socklen_t size;
00064 {
00065        switch (af) {
00066        case AF_INET:
00067               return (inet_ntop4(src, dst, size));
00068        case AF_INET6:
00069               return (inet_ntop6(src, dst, size));
00070        default:
00071               __set_errno (EAFNOSUPPORT);
00072               return (NULL);
00073        }
00074        /* NOTREACHED */
00075 }
00076 libc_hidden_def (inet_ntop)
00077 
00078 /* const char *
00079  * inet_ntop4(src, dst, size)
00080  *     format an IPv4 address
00081  * return:
00082  *     `dst' (as a const)
00083  * notes:
00084  *     (1) uses no statics
00085  *     (2) takes a u_char* not an in_addr as input
00086  * author:
00087  *     Paul Vixie, 1996.
00088  */
00089 static const char *
00090 internal_function
00091 inet_ntop4(src, dst, size)
00092        const u_char *src;
00093        char *dst;
00094        socklen_t size;
00095 {
00096        static const char fmt[] = "%u.%u.%u.%u";
00097        char tmp[sizeof "255.255.255.255"];
00098 
00099        if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
00100               __set_errno (ENOSPC);
00101               return (NULL);
00102        }
00103        return strcpy(dst, tmp);
00104 }
00105 
00106 /* const char *
00107  * inet_ntop6(src, dst, size)
00108  *     convert IPv6 binary address into presentation (printable) format
00109  * author:
00110  *     Paul Vixie, 1996.
00111  */
00112 static const char *
00113 internal_function
00114 inet_ntop6(src, dst, size)
00115        const u_char *src;
00116        char *dst;
00117        socklen_t size;
00118 {
00119        /*
00120         * Note that int32_t and int16_t need only be "at least" large enough
00121         * to contain a value of the specified size.  On some systems, like
00122         * Crays, there is no such thing as an integer variable with 16 bits.
00123         * Keep this in mind if you think this function should have been coded
00124         * to use pointer overlays.  All the world's not a VAX.
00125         */
00126        char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
00127        struct { int base, len; } best, cur;
00128        u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
00129        int i;
00130 
00131        /*
00132         * Preprocess:
00133         *     Copy the input (bytewise) array into a wordwise array.
00134         *     Find the longest run of 0x00's in src[] for :: shorthanding.
00135         */
00136        memset(words, '\0', sizeof words);
00137        for (i = 0; i < NS_IN6ADDRSZ; i += 2)
00138               words[i / 2] = (src[i] << 8) | src[i + 1];
00139        best.base = -1;
00140        cur.base = -1;
00141        best.len = 0;
00142        cur.len = 0;
00143        for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
00144               if (words[i] == 0) {
00145                      if (cur.base == -1)
00146                             cur.base = i, cur.len = 1;
00147                      else
00148                             cur.len++;
00149               } else {
00150                      if (cur.base != -1) {
00151                             if (best.base == -1 || cur.len > best.len)
00152                                    best = cur;
00153                             cur.base = -1;
00154                      }
00155               }
00156        }
00157        if (cur.base != -1) {
00158               if (best.base == -1 || cur.len > best.len)
00159                      best = cur;
00160        }
00161        if (best.base != -1 && best.len < 2)
00162               best.base = -1;
00163 
00164        /*
00165         * Format the result.
00166         */
00167        tp = tmp;
00168        for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
00169               /* Are we inside the best run of 0x00's? */
00170               if (best.base != -1 && i >= best.base &&
00171                   i < (best.base + best.len)) {
00172                      if (i == best.base)
00173                             *tp++ = ':';
00174                      continue;
00175               }
00176               /* Are we following an initial run of 0x00s or any real hex? */
00177               if (i != 0)
00178                      *tp++ = ':';
00179               /* Is this address an encapsulated IPv4? */
00180               if (i == 6 && best.base == 0 &&
00181                   (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
00182                      if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
00183                             return (NULL);
00184                      tp += strlen(tp);
00185                      break;
00186               }
00187               tp += SPRINTF((tp, "%x", words[i]));
00188        }
00189        /* Was it a trailing run of 0x00's? */
00190        if (best.base != -1 && (best.base + best.len) ==
00191            (NS_IN6ADDRSZ / NS_INT16SZ))
00192               *tp++ = ':';
00193        *tp++ = '\0';
00194 
00195        /*
00196         * Check for overflow, copy, and we're done.
00197         */
00198        if ((socklen_t)(tp - tmp) > size) {
00199               __set_errno (ENOSPC);
00200               return (NULL);
00201        }
00202        return strcpy(dst, tmp);
00203 }