Merge from vendor branch GROFF:
[dragonfly.git] / contrib / bind-9.2.4rc7 / lib / bind / inet / inet_cidr_ntop.c
1 /*
2  * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (c) 1998,1999 by Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15  * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 #if defined(LIBC_SCCS) && !defined(lint)
19 static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.1.2.3 2004/03/17 00:40:10 marka Exp $";
20 #endif
21
22 #include "port_before.h"
23
24 #include <sys/types.h>
25 #include <sys/socket.h>
26 #include <netinet/in.h>
27 #include <arpa/nameser.h>
28 #include <arpa/inet.h>
29
30 #include <errno.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stdlib.h>
34
35 #include "port_after.h"
36
37 #ifdef SPRINTF_CHAR
38 # define SPRINTF(x) strlen(sprintf/**/x)
39 #else
40 # define SPRINTF(x) ((size_t)sprintf x)
41 #endif
42
43 static char *   inet_cidr_ntop_ipv4 __P((const u_char *src, int bits,
44                                          char *dst, size_t size));
45 static char *   inet_cidr_ntop_ipv6 __P((const u_char *src, int bits,
46                                          char *dst, size_t size));
47
48 /*
49  * char *
50  * inet_cidr_ntop(af, src, bits, dst, size)
51  *      convert network address from network to presentation format.
52  *      "src"'s size is determined from its "af".
53  * return:
54  *      pointer to dst, or NULL if an error occurred (check errno).
55  * note:
56  *      192.5.5.1/28 has a nonzero host part, which means it isn't a network
57  *      as called for by inet_net_ntop() but it can be a host address with
58  *      an included netmask.
59  * author:
60  *      Paul Vixie (ISC), October 1998
61  */
62 char *
63 inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
64         switch (af) {
65         case AF_INET:
66                 return (inet_cidr_ntop_ipv4(src, bits, dst, size));
67         case AF_INET6:
68                 return (inet_cidr_ntop_ipv6(src, bits, dst, size));
69         default:
70                 errno = EAFNOSUPPORT;
71                 return (NULL);
72         }
73 }
74
75 static int
76 decoct(const u_char *src, int bytes, char *dst, size_t size) {
77         char *odst = dst;
78         char *t;
79         int b;
80
81         for (b = 1; b <= bytes; b++) {
82                 if (size < sizeof "255.")
83                         return (0);
84                 t = dst;
85                 dst += SPRINTF((dst, "%u", *src++));
86                 if (b != bytes) {
87                         *dst++ = '.';
88                         *dst = '\0';
89                 }
90                 size -= (size_t)(dst - t);
91         }
92         return (dst - odst);
93 }
94
95 /*
96  * static char *
97  * inet_cidr_ntop_ipv4(src, bits, dst, size)
98  *      convert IPv4 network address from network to presentation format.
99  *      "src"'s size is determined from its "af".
100  * return:
101  *      pointer to dst, or NULL if an error occurred (check errno).
102  * note:
103  *      network byte order assumed.  this means 192.5.5.240/28 has
104  *      0b11110000 in its fourth octet.
105  * author:
106  *      Paul Vixie (ISC), October 1998
107  */
108 static char *
109 inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
110         char *odst = dst;
111         size_t len = 4;
112         size_t b;
113         size_t bytes;
114
115         if ((bits < -1) || (bits > 32)) {
116                 errno = EINVAL;
117                 return (NULL);
118         }
119
120         /* Find number of significant bytes in address. */
121         if (bits == -1)
122                 len = 4;
123         else
124                 for (len = 1, b = 1 ; b < 4U; b++)
125                         if (*(src + b))
126                                 len = b + 1;
127
128         /* Format whole octets plus nonzero trailing octets. */
129         bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
130         if (len > bytes)
131                 bytes = len;
132         b = decoct(src, bytes, dst, size);
133         if (b == 0U)
134                 goto emsgsize;
135         dst += b;
136         size -= b;
137
138         if (bits != -1) {
139                 /* Format CIDR /width. */
140                 if (size < sizeof "/32")
141                         goto emsgsize;
142                 dst += SPRINTF((dst, "/%u", bits));
143         }
144
145         return (odst);
146
147  emsgsize:
148         errno = EMSGSIZE;
149         return (NULL);
150 }
151  
152 static char *
153 inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
154         /*
155          * Note that int32_t and int16_t need only be "at least" large enough
156          * to contain a value of the specified size.  On some systems, like
157          * Crays, there is no such thing as an integer variable with 16 bits.
158          * Keep this in mind if you think this function should have been coded
159          * to use pointer overlays.  All the world's not a VAX.
160          */
161         char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
162         char *tp;
163         struct { int base, len; } best, cur;
164         u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
165         int i;
166
167         if ((bits < -1) || (bits > 128)) {
168                 errno = EINVAL;
169                 return (NULL);
170         }
171
172         /*
173          * Preprocess:
174          *      Copy the input (bytewise) array into a wordwise array.
175          *      Find the longest run of 0x00's in src[] for :: shorthanding.
176          */
177         memset(words, '\0', sizeof words);
178         for (i = 0; i < NS_IN6ADDRSZ; i++)
179                 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
180         best.base = -1;
181         cur.base = -1;
182         for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
183                 if (words[i] == 0) {
184                         if (cur.base == -1)
185                                 cur.base = i, cur.len = 1;
186                         else
187                                 cur.len++;
188                 } else {
189                         if (cur.base != -1) {
190                                 if (best.base == -1 || cur.len > best.len)
191                                         best = cur;
192                                 cur.base = -1;
193                         }
194                 }
195         }
196         if (cur.base != -1) {
197                 if (best.base == -1 || cur.len > best.len)
198                         best = cur;
199         }
200         if (best.base != -1 && best.len < 2)
201                 best.base = -1;
202
203         /*
204          * Format the result.
205          */
206         tp = tmp;
207         for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
208                 /* Are we inside the best run of 0x00's? */
209                 if (best.base != -1 && i >= best.base &&
210                     i < (best.base + best.len)) {
211                         if (i == best.base)
212                                 *tp++ = ':';
213                         continue;
214                 }
215                 /* Are we following an initial run of 0x00s or any real hex? */
216                 if (i != 0)
217                         *tp++ = ':';
218                 /* Is this address an encapsulated IPv4? */
219                 if (i == 6 && best.base == 0 && (best.len == 6 ||
220                     (best.len == 7 && words[7] != 0x0001) ||
221                     (best.len == 5 && words[5] == 0xffff))) {
222                         int n;
223
224                         if (src[15] || bits == -1 || bits > 120)
225                                 n = 4;
226                         else if (src[14] || bits > 112)
227                                 n = 3;
228                         else
229                                 n = 2;
230                         n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
231                         if (n == 0) {
232                                 errno = EMSGSIZE;
233                                 return (NULL);
234                         }
235                         tp += strlen(tp);
236                         break;
237                 }
238                 tp += SPRINTF((tp, "%x", words[i]));
239         }
240
241         /* Was it a trailing run of 0x00's? */
242         if (best.base != -1 && (best.base + best.len) == 
243             (NS_IN6ADDRSZ / NS_INT16SZ))
244                 *tp++ = ':';
245         *tp = '\0';
246
247         if (bits != -1)
248                 tp += SPRINTF((tp, "/%u", bits));
249
250         /*
251          * Check for overflow, copy, and we're done.
252          */
253         if ((size_t)(tp - tmp) > size) {
254                 errno = EMSGSIZE;
255                 return (NULL);
256         }
257         strcpy(dst, tmp);
258         return (dst);
259 }