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