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