inet_ntop.c

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

Generated on Tue Apr 28 17:41:04 2015 by Doxygen 1.5.4 for BIND9 Internals 9.11.0pre-alpha