xref: /haiku/src/system/libnetwork/netresolv/inet/inet_net_ntop.c (revision aa6411e23e78610d8eecaa4de48b6c71c994fbf3)
1*aa6411e2SAugustin Cavalier /*
2*aa6411e2SAugustin Cavalier  * Copyright (c) 1996,1999 by Internet Software Consortium.
3*aa6411e2SAugustin Cavalier  *
4*aa6411e2SAugustin Cavalier  * Permission to use, copy, modify, and distribute this software for any
5*aa6411e2SAugustin Cavalier  * purpose with or without fee is hereby granted, provided that the above
6*aa6411e2SAugustin Cavalier  * copyright notice and this permission notice appear in all copies.
7*aa6411e2SAugustin Cavalier  *
8*aa6411e2SAugustin Cavalier  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9*aa6411e2SAugustin Cavalier  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10*aa6411e2SAugustin Cavalier  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11*aa6411e2SAugustin Cavalier  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12*aa6411e2SAugustin Cavalier  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13*aa6411e2SAugustin Cavalier  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14*aa6411e2SAugustin Cavalier  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15*aa6411e2SAugustin Cavalier  * SOFTWARE.
16*aa6411e2SAugustin Cavalier  */
17*aa6411e2SAugustin Cavalier 
18*aa6411e2SAugustin Cavalier #include <sys/cdefs.h>
19*aa6411e2SAugustin Cavalier #if defined(LIBC_SCCS) && !defined(lint)
20*aa6411e2SAugustin Cavalier #ifdef notdef
21*aa6411e2SAugustin Cavalier static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.1 2002/08/02 02:17:21 marka Exp ";
22*aa6411e2SAugustin Cavalier #else
23*aa6411e2SAugustin Cavalier __RCSID("$NetBSD: inet_net_ntop.c,v 1.4 2017/05/09 02:56:44 maya Exp $");
24*aa6411e2SAugustin Cavalier #endif
25*aa6411e2SAugustin Cavalier #endif
26*aa6411e2SAugustin Cavalier 
27*aa6411e2SAugustin Cavalier #include "port_before.h"
28*aa6411e2SAugustin Cavalier 
29*aa6411e2SAugustin Cavalier #include <sys/types.h>
30*aa6411e2SAugustin Cavalier #include <sys/socket.h>
31*aa6411e2SAugustin Cavalier #include <netinet/in.h>
32*aa6411e2SAugustin Cavalier #include <arpa/inet.h>
33*aa6411e2SAugustin Cavalier 
34*aa6411e2SAugustin Cavalier #include <errno.h>
35*aa6411e2SAugustin Cavalier #include <stdio.h>
36*aa6411e2SAugustin Cavalier #include <string.h>
37*aa6411e2SAugustin Cavalier #include <stdlib.h>
38*aa6411e2SAugustin Cavalier 
39*aa6411e2SAugustin Cavalier #include "port_after.h"
40*aa6411e2SAugustin Cavalier 
41*aa6411e2SAugustin Cavalier #ifdef __weak_alias
42*aa6411e2SAugustin Cavalier __weak_alias(inet_net_ntop,_inet_net_ntop)
43*aa6411e2SAugustin Cavalier #endif
44*aa6411e2SAugustin Cavalier 
45*aa6411e2SAugustin Cavalier #ifdef SPRINTF_CHAR
46*aa6411e2SAugustin Cavalier # define SPRINTF(x) strlen(sprintf/**/x)
47*aa6411e2SAugustin Cavalier #else
48*aa6411e2SAugustin Cavalier # define SPRINTF(x) sprintf x
49*aa6411e2SAugustin Cavalier #endif
50*aa6411e2SAugustin Cavalier 
51*aa6411e2SAugustin Cavalier static char *	inet_net_ntop_ipv4(const u_char *src, int bits,
52*aa6411e2SAugustin Cavalier 					char *dst, size_t size);
53*aa6411e2SAugustin Cavalier static char *	inet_net_ntop_ipv6(const u_char *src, int bits,
54*aa6411e2SAugustin Cavalier 					char *dst, size_t size);
55*aa6411e2SAugustin Cavalier 
56*aa6411e2SAugustin Cavalier /*
57*aa6411e2SAugustin Cavalier  * char *
58*aa6411e2SAugustin Cavalier  * inet_net_ntop(af, src, bits, dst, size)
59*aa6411e2SAugustin Cavalier  *	convert network number from network to presentation format.
60*aa6411e2SAugustin Cavalier  *	generates CIDR style result always.
61*aa6411e2SAugustin Cavalier  * return:
62*aa6411e2SAugustin Cavalier  *	pointer to dst, or NULL if an error occurred (check errno).
63*aa6411e2SAugustin Cavalier  * author:
64*aa6411e2SAugustin Cavalier  *	Paul Vixie (ISC), July 1996
65*aa6411e2SAugustin Cavalier  */
66*aa6411e2SAugustin Cavalier char *
inet_net_ntop(int af,const void * src,int bits,char * dst,size_t size)67*aa6411e2SAugustin Cavalier inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
68*aa6411e2SAugustin Cavalier {
69*aa6411e2SAugustin Cavalier 	switch (af) {
70*aa6411e2SAugustin Cavalier 	case AF_INET:
71*aa6411e2SAugustin Cavalier 		return (inet_net_ntop_ipv4(src, bits, dst, size));
72*aa6411e2SAugustin Cavalier 	case AF_INET6:
73*aa6411e2SAugustin Cavalier 		return (inet_net_ntop_ipv6(src, bits, dst, size));
74*aa6411e2SAugustin Cavalier 	default:
75*aa6411e2SAugustin Cavalier 		errno = EAFNOSUPPORT;
76*aa6411e2SAugustin Cavalier 		return (NULL);
77*aa6411e2SAugustin Cavalier 	}
78*aa6411e2SAugustin Cavalier }
79*aa6411e2SAugustin Cavalier 
80*aa6411e2SAugustin Cavalier /*
81*aa6411e2SAugustin Cavalier  * static char *
82*aa6411e2SAugustin Cavalier  * inet_net_ntop_ipv4(src, bits, dst, size)
83*aa6411e2SAugustin Cavalier  *	convert IPv4 network number from network to presentation format.
84*aa6411e2SAugustin Cavalier  *	generates CIDR style result always.
85*aa6411e2SAugustin Cavalier  * return:
86*aa6411e2SAugustin Cavalier  *	pointer to dst, or NULL if an error occurred (check errno).
87*aa6411e2SAugustin Cavalier  * note:
88*aa6411e2SAugustin Cavalier  *	network byte order assumed.  this means 192.5.5.240/28 has
89*aa6411e2SAugustin Cavalier  *	0b11110000 in its fourth octet.
90*aa6411e2SAugustin Cavalier  * author:
91*aa6411e2SAugustin Cavalier  *	Paul Vixie (ISC), July 1996
92*aa6411e2SAugustin Cavalier  */
93*aa6411e2SAugustin Cavalier static char *
inet_net_ntop_ipv4(const u_char * src,int bits,char * dst,size_t size)94*aa6411e2SAugustin Cavalier inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
95*aa6411e2SAugustin Cavalier {
96*aa6411e2SAugustin Cavalier 	char *odst = dst;
97*aa6411e2SAugustin Cavalier 	char *t;
98*aa6411e2SAugustin Cavalier 	u_int m;
99*aa6411e2SAugustin Cavalier 	int b;
100*aa6411e2SAugustin Cavalier 
101*aa6411e2SAugustin Cavalier 	if (bits < 0 || bits > 32) {
102*aa6411e2SAugustin Cavalier 		errno = EINVAL;
103*aa6411e2SAugustin Cavalier 		return (NULL);
104*aa6411e2SAugustin Cavalier 	}
105*aa6411e2SAugustin Cavalier 
106*aa6411e2SAugustin Cavalier 	if (bits == 0) {
107*aa6411e2SAugustin Cavalier 		if (size < sizeof "0")
108*aa6411e2SAugustin Cavalier 			goto emsgsize;
109*aa6411e2SAugustin Cavalier 		*dst++ = '0';
110*aa6411e2SAugustin Cavalier 		size--;
111*aa6411e2SAugustin Cavalier 		*dst = '\0';
112*aa6411e2SAugustin Cavalier 	}
113*aa6411e2SAugustin Cavalier 
114*aa6411e2SAugustin Cavalier 	/* Format whole octets. */
115*aa6411e2SAugustin Cavalier 	for (b = bits / 8; b > 0; b--) {
116*aa6411e2SAugustin Cavalier 		if (size <= sizeof "255.")
117*aa6411e2SAugustin Cavalier 			goto emsgsize;
118*aa6411e2SAugustin Cavalier 		t = dst;
119*aa6411e2SAugustin Cavalier 		dst += SPRINTF((dst, "%u", *src++));
120*aa6411e2SAugustin Cavalier 		if (b > 1) {
121*aa6411e2SAugustin Cavalier 			*dst++ = '.';
122*aa6411e2SAugustin Cavalier 			*dst = '\0';
123*aa6411e2SAugustin Cavalier 		}
124*aa6411e2SAugustin Cavalier 		size -= (size_t)(dst - t);
125*aa6411e2SAugustin Cavalier 	}
126*aa6411e2SAugustin Cavalier 
127*aa6411e2SAugustin Cavalier 	/* Format partial octet. */
128*aa6411e2SAugustin Cavalier 	b = bits % 8;
129*aa6411e2SAugustin Cavalier 	if (b > 0) {
130*aa6411e2SAugustin Cavalier 		if (size <= sizeof ".255")
131*aa6411e2SAugustin Cavalier 			goto emsgsize;
132*aa6411e2SAugustin Cavalier 		t = dst;
133*aa6411e2SAugustin Cavalier 		if (dst != odst)
134*aa6411e2SAugustin Cavalier 			*dst++ = '.';
135*aa6411e2SAugustin Cavalier 		m = ((1 << b) - 1) << (8 - b);
136*aa6411e2SAugustin Cavalier 		dst += SPRINTF((dst, "%u", *src & m));
137*aa6411e2SAugustin Cavalier 		size -= (size_t)(dst - t);
138*aa6411e2SAugustin Cavalier 	}
139*aa6411e2SAugustin Cavalier 
140*aa6411e2SAugustin Cavalier 	/* Format CIDR /width. */
141*aa6411e2SAugustin Cavalier 	if (size <= sizeof "/32")
142*aa6411e2SAugustin Cavalier 		goto emsgsize;
143*aa6411e2SAugustin Cavalier 	dst += SPRINTF((dst, "/%u", bits));
144*aa6411e2SAugustin Cavalier 	return (odst);
145*aa6411e2SAugustin Cavalier 
146*aa6411e2SAugustin Cavalier  emsgsize:
147*aa6411e2SAugustin Cavalier 	errno = EMSGSIZE;
148*aa6411e2SAugustin Cavalier 	return (NULL);
149*aa6411e2SAugustin Cavalier }
150*aa6411e2SAugustin Cavalier 
151*aa6411e2SAugustin Cavalier /*
152*aa6411e2SAugustin Cavalier  * static char *
153*aa6411e2SAugustin Cavalier  * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
154*aa6411e2SAugustin Cavalier  *	convert IPv6 network number from network to presentation format.
155*aa6411e2SAugustin Cavalier  *	generates CIDR style result always. Picks the shortest representation
156*aa6411e2SAugustin Cavalier  *	unless the IP is really IPv4.
157*aa6411e2SAugustin Cavalier  *	always prints specified number of bits (bits).
158*aa6411e2SAugustin Cavalier  * return:
159*aa6411e2SAugustin Cavalier  *	pointer to dst, or NULL if an error occurred (check errno).
160*aa6411e2SAugustin Cavalier  * note:
161*aa6411e2SAugustin Cavalier  *	network byte order assumed.  this means 192.5.5.240/28 has
162*aa6411e2SAugustin Cavalier  *	0x11110000 in its fourth octet.
163*aa6411e2SAugustin Cavalier  * author:
164*aa6411e2SAugustin Cavalier  *	Vadim Kogan (UCB), June 2001
165*aa6411e2SAugustin Cavalier  *  Original version (IPv4) by Paul Vixie (ISC), July 1996
166*aa6411e2SAugustin Cavalier  */
167*aa6411e2SAugustin Cavalier 
168*aa6411e2SAugustin Cavalier static char *
inet_net_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)169*aa6411e2SAugustin Cavalier inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
170*aa6411e2SAugustin Cavalier {
171*aa6411e2SAugustin Cavalier 	u_int	m;
172*aa6411e2SAugustin Cavalier 	int	b;
173*aa6411e2SAugustin Cavalier 	size_t	p;
174*aa6411e2SAugustin Cavalier 	size_t	zero_s, zero_l, tmp_zero_s, tmp_zero_l;
175*aa6411e2SAugustin Cavalier 	size_t	i;
176*aa6411e2SAugustin Cavalier 	int	is_ipv4 = 0;
177*aa6411e2SAugustin Cavalier 	unsigned char inbuf[16];
178*aa6411e2SAugustin Cavalier 	char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
179*aa6411e2SAugustin Cavalier 	char	*cp;
180*aa6411e2SAugustin Cavalier 	size_t	words;
181*aa6411e2SAugustin Cavalier 	u_char	*s;
182*aa6411e2SAugustin Cavalier 
183*aa6411e2SAugustin Cavalier 	if (bits < 0 || bits > 128) {
184*aa6411e2SAugustin Cavalier 		errno = EINVAL;
185*aa6411e2SAugustin Cavalier 		return (NULL);
186*aa6411e2SAugustin Cavalier 	}
187*aa6411e2SAugustin Cavalier 
188*aa6411e2SAugustin Cavalier 	cp = outbuf;
189*aa6411e2SAugustin Cavalier 
190*aa6411e2SAugustin Cavalier 	if (bits == 0) {
191*aa6411e2SAugustin Cavalier 		*cp++ = ':';
192*aa6411e2SAugustin Cavalier 		*cp++ = ':';
193*aa6411e2SAugustin Cavalier 		*cp = '\0';
194*aa6411e2SAugustin Cavalier 	} else {
195*aa6411e2SAugustin Cavalier 		/* Copy src to private buffer.  Zero host part. */
196*aa6411e2SAugustin Cavalier 		p = (bits + 7) / 8;
197*aa6411e2SAugustin Cavalier 		memcpy(inbuf, src, p);
198*aa6411e2SAugustin Cavalier 		memset(inbuf + p, 0, 16 - p);
199*aa6411e2SAugustin Cavalier 		b = bits % 8;
200*aa6411e2SAugustin Cavalier 		if (b != 0) {
201*aa6411e2SAugustin Cavalier 			m = ~0u << (8 - b);
202*aa6411e2SAugustin Cavalier 			inbuf[p-1] &= m;
203*aa6411e2SAugustin Cavalier 		}
204*aa6411e2SAugustin Cavalier 
205*aa6411e2SAugustin Cavalier 		s = inbuf;
206*aa6411e2SAugustin Cavalier 
207*aa6411e2SAugustin Cavalier 		/* how many words need to be displayed in output */
208*aa6411e2SAugustin Cavalier 		words = (bits + 15) / 16;
209*aa6411e2SAugustin Cavalier 		if (words == 1)
210*aa6411e2SAugustin Cavalier 			words = 2;
211*aa6411e2SAugustin Cavalier 
212*aa6411e2SAugustin Cavalier 		/* Find the longest substring of zero's */
213*aa6411e2SAugustin Cavalier 		zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
214*aa6411e2SAugustin Cavalier 		for (i = 0; i < (words * 2); i += 2) {
215*aa6411e2SAugustin Cavalier 			if ((s[i] | s[i+1]) == 0) {
216*aa6411e2SAugustin Cavalier 				if (tmp_zero_l == 0)
217*aa6411e2SAugustin Cavalier 					tmp_zero_s = i / 2;
218*aa6411e2SAugustin Cavalier 				tmp_zero_l++;
219*aa6411e2SAugustin Cavalier 			} else {
220*aa6411e2SAugustin Cavalier 				if (tmp_zero_l && zero_l < tmp_zero_l) {
221*aa6411e2SAugustin Cavalier 					zero_s = tmp_zero_s;
222*aa6411e2SAugustin Cavalier 					zero_l = tmp_zero_l;
223*aa6411e2SAugustin Cavalier 					tmp_zero_l = 0;
224*aa6411e2SAugustin Cavalier 				}
225*aa6411e2SAugustin Cavalier 			}
226*aa6411e2SAugustin Cavalier 		}
227*aa6411e2SAugustin Cavalier 
228*aa6411e2SAugustin Cavalier 		if (tmp_zero_l && zero_l < tmp_zero_l) {
229*aa6411e2SAugustin Cavalier 			zero_s = tmp_zero_s;
230*aa6411e2SAugustin Cavalier 			zero_l = tmp_zero_l;
231*aa6411e2SAugustin Cavalier 		}
232*aa6411e2SAugustin Cavalier 
233*aa6411e2SAugustin Cavalier 		if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
234*aa6411e2SAugustin Cavalier 		    ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
235*aa6411e2SAugustin Cavalier 		    ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
236*aa6411e2SAugustin Cavalier 			is_ipv4 = 1;
237*aa6411e2SAugustin Cavalier 
238*aa6411e2SAugustin Cavalier 		/* Format whole words. */
239*aa6411e2SAugustin Cavalier 		for (p = 0; p < words; p++) {
240*aa6411e2SAugustin Cavalier 			if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
241*aa6411e2SAugustin Cavalier 				/* Time to skip some zeros */
242*aa6411e2SAugustin Cavalier 				if (p == zero_s)
243*aa6411e2SAugustin Cavalier 					*cp++ = ':';
244*aa6411e2SAugustin Cavalier 				if (p == words - 1)
245*aa6411e2SAugustin Cavalier 					*cp++ = ':';
246*aa6411e2SAugustin Cavalier 				s++;
247*aa6411e2SAugustin Cavalier 				s++;
248*aa6411e2SAugustin Cavalier 				continue;
249*aa6411e2SAugustin Cavalier 			}
250*aa6411e2SAugustin Cavalier 
251*aa6411e2SAugustin Cavalier 			if (is_ipv4 && p > 5 ) {
252*aa6411e2SAugustin Cavalier 				*cp++ = (p == 6) ? ':' : '.';
253*aa6411e2SAugustin Cavalier 				cp += SPRINTF((cp, "%u", *s++));
254*aa6411e2SAugustin Cavalier 				/* we can potentially drop the last octet */
255*aa6411e2SAugustin Cavalier 				if (p != 7 || bits > 120) {
256*aa6411e2SAugustin Cavalier 					*cp++ = '.';
257*aa6411e2SAugustin Cavalier 					cp += SPRINTF((cp, "%u", *s++));
258*aa6411e2SAugustin Cavalier 				}
259*aa6411e2SAugustin Cavalier 			} else {
260*aa6411e2SAugustin Cavalier 				if (cp != outbuf)
261*aa6411e2SAugustin Cavalier 					*cp++ = ':';
262*aa6411e2SAugustin Cavalier 				cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
263*aa6411e2SAugustin Cavalier 				s += 2;
264*aa6411e2SAugustin Cavalier 			}
265*aa6411e2SAugustin Cavalier 		}
266*aa6411e2SAugustin Cavalier 	}
267*aa6411e2SAugustin Cavalier 	/* Format CIDR /width. */
268*aa6411e2SAugustin Cavalier 	(void)SPRINTF((cp, "/%u", bits));
269*aa6411e2SAugustin Cavalier 	if (strlen(outbuf) + 1 > size)
270*aa6411e2SAugustin Cavalier 		goto emsgsize;
271*aa6411e2SAugustin Cavalier 	strcpy(dst, outbuf);
272*aa6411e2SAugustin Cavalier 
273*aa6411e2SAugustin Cavalier 	return (dst);
274*aa6411e2SAugustin Cavalier 
275*aa6411e2SAugustin Cavalier emsgsize:
276*aa6411e2SAugustin Cavalier 	errno = EMSGSIZE;
277*aa6411e2SAugustin Cavalier 	return (NULL);
278*aa6411e2SAugustin Cavalier }
279*aa6411e2SAugustin Cavalier 
280*aa6411e2SAugustin Cavalier #undef inet_net_ntop
281*aa6411e2SAugustin Cavalier #pragma weak inet_net_ntop = __inet_net_ntop
282