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