From Elliott: Add contrast to the border.
[obnox/wireshark/wip.git] / inet_ntop.c
1 /*
2  * $Id$
3  *
4  * Copyright (c) 1996-1999 by Internet Software Consortium.
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
11  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
12  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
13  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
16  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
17  * SOFTWARE.
18  */
19
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #ifdef HAVE_SYS_PARAM_H
26 #include <sys/param.h>
27 #endif
28
29 #ifdef HAVE_SYS_TYPES_H
30 #include <sys/types.h>
31 #endif
32
33 #ifdef HAVE_SYS_SOCKET_H
34 #include <sys/socket.h>         /* needed to define AF_ values on UNIX */
35 #endif
36
37 #ifdef HAVE_WINSOCK2_H
38 #include <winsock2.h>           /* needed to define AF_ values on Windows */
39 #define EAFNOSUPPORT    WSAEAFNOSUPPORT
40 #endif
41
42 #ifdef HAVE_NETINET_IN_H
43 #include <netinet/in.h>
44 #endif
45
46 #ifdef HAVE_ARPA_INET_H
47 #include <arpa/inet.h>
48 #endif
49
50 #ifdef HAVE_ARPA_NAMESER_H
51 #include <arpa/nameser.h>
52 #endif
53
54 #include <errno.h>
55 #include <stdio.h>
56 #include <string.h>
57
58 #include "inet_v6defs.h"
59
60 #include <glib.h>
61
62 #ifndef NS_INADDRSZ
63 #define NS_INADDRSZ     4
64 #endif
65 #ifndef NS_IN6ADDRSZ
66 #define NS_IN6ADDRSZ    16
67 #endif
68 #ifndef NS_INT16SZ
69 #define NS_INT16SZ      2
70 #endif
71
72 /*
73  * WARNING: Don't even consider trying to compile this on a system where
74  * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
75  */
76
77 static const char *inet_ntop4 __P((const u_char *src, char *dst, size_t size));
78 static const char *inet_ntop6 __P((const u_char *src, char *dst, size_t size));
79
80 /* char *
81  * inet_ntop(af, src, dst, size)
82  *      convert a network format address to presentation format.
83  * return:
84  *      pointer to presentation format address (`dst'), or NULL (see errno).
85  * author:
86  *      Paul Vixie, 1996.
87  */
88 const char *
89 inet_ntop(af, src, dst, size)
90         int af;
91         const void *src;
92         char *dst;
93         size_t size;
94 {
95         switch (af) {
96         case AF_INET:
97                 return (inet_ntop4(src, dst, size));
98         case AF_INET6:
99                 return (inet_ntop6(src, dst, size));
100         default:
101                 errno = EAFNOSUPPORT;
102                 return (NULL);
103         }
104         /* NOTREACHED */
105 }
106
107 /* const char *
108  * inet_ntop4(src, dst, size)
109  *      format an IPv4 address
110  * return:
111  *      `dst' (as a const)
112  * notes:
113  *      (1) uses no statics
114  *      (2) takes a u_char* not an in_addr as input
115  * author:
116  *      Paul Vixie, 1996.
117  */
118 static const char *
119 inet_ntop4(src, dst, size)
120         const u_char *src;
121         char *dst;
122         size_t size;
123 {
124         static const char fmt[] = "%u.%u.%u.%u";
125         char tmp[sizeof "255.255.255.255"];
126         int nprinted;
127
128         nprinted = g_snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]);
129         /* Note: nprinted *excludes* the trailing '\0' character */
130         if ((size_t)nprinted >= size) {
131                 errno = ENOSPC;
132                 return (NULL);
133         }
134         g_strlcpy(dst, tmp, size);
135         return (dst);
136 }
137
138 /* const char *
139  * inet_ntop6(src, dst, size)
140  *      convert IPv6 binary address into presentation (printable) format
141  * author:
142  *      Paul Vixie, 1996.
143  */
144 static const char *
145 inet_ntop6(src, dst, size)
146         const u_char *src;
147         char *dst;
148         size_t size;
149 {
150         /*
151          * Note that int32_t and int16_t need only be "at least" large enough
152          * to contain a value of the specified size.  On some systems, like
153          * Crays, there is no such thing as an integer variable with 16 bits.
154          * Keep this in mind if you think this function should have been coded
155          * to use pointer overlays.  All the world's not a VAX.
156          */
157         char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
158         struct { int base, len; } best, cur;
159         u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
160         int i;
161
162         /*
163          * Preprocess:
164          *      Copy the input (bytewise) array into a wordwise array.
165          *      Find the longest run of 0x00's in src[] for :: shorthanding.
166          */
167         memset(words, '\0', sizeof words);
168         for (i = 0; i < NS_IN6ADDRSZ; i++)
169                 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
170         best.base = -1;
171         cur.base = -1;
172         for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
173                 if (words[i] == 0) {
174                         if (cur.base == -1)
175                                 cur.base = i, cur.len = 1;
176                         else
177                                 cur.len++;
178                 } else {
179                         if (cur.base != -1) {
180                                 if (best.base == -1 || cur.len > best.len)
181                                         best = cur;
182                                 cur.base = -1;
183                         }
184                 }
185         }
186         if (cur.base != -1) {
187                 if (best.base == -1 || cur.len > best.len)
188                         best = cur;
189         }
190         if (best.base != -1 && best.len < 2)
191                 best.base = -1;
192
193         /*
194          * Format the result.
195          */
196         tp = tmp;
197         for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
198                 /* Are we inside the best run of 0x00's? */
199                 if (best.base != -1 && i >= best.base &&
200                     i < (best.base + best.len)) {
201                         if (i == best.base)
202                                 *tp++ = ':';
203                         continue;
204                 }
205                 /* Are we following an initial run of 0x00s or any real hex? */
206                 if (i != 0)
207                         *tp++ = ':';
208                 /* Is this address an encapsulated IPv4? */
209                 if (i == 6 && best.base == 0 &&
210                     (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
211                         if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
212                                 return (NULL);
213                         tp += strlen(tp);
214                         break;
215                 }
216                 tp += g_snprintf(tp, (gulong) (sizeof tmp - (tp - tmp)), "%x", words[i]);
217         }
218         /* Was it a trailing run of 0x00's? */
219         if (best.base != -1 && (best.base + best.len) ==
220             (NS_IN6ADDRSZ / NS_INT16SZ))
221                 *tp++ = ':';
222         *tp++ = '\0';
223
224         /*
225          * Check for overflow, copy, and we're done.
226          */
227         if ((size_t)(tp - tmp) > size) {
228                 errno = ENOSPC;
229                 return (NULL);
230         }
231         g_strlcpy(dst, tmp, size);
232         return (dst);
233 }