xref: /minix3/lib/libc/inet/inet_net_ntop.c (revision f14fb602092e015ff630df58e17c2a9cd57d29b3)
12fe8fb19SBen Gras /*
22fe8fb19SBen Gras  * Copyright (c) 1996,1999 by Internet Software Consortium.
32fe8fb19SBen Gras  *
42fe8fb19SBen Gras  * Permission to use, copy, modify, and distribute this software for any
52fe8fb19SBen Gras  * purpose with or without fee is hereby granted, provided that the above
62fe8fb19SBen Gras  * copyright notice and this permission notice appear in all copies.
72fe8fb19SBen Gras  *
82fe8fb19SBen Gras  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
92fe8fb19SBen Gras  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
102fe8fb19SBen Gras  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
112fe8fb19SBen Gras  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
122fe8fb19SBen Gras  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
132fe8fb19SBen Gras  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
142fe8fb19SBen Gras  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
152fe8fb19SBen Gras  * SOFTWARE.
162fe8fb19SBen Gras  */
172fe8fb19SBen Gras 
182fe8fb19SBen Gras #include <sys/cdefs.h>
192fe8fb19SBen Gras #if defined(LIBC_SCCS) && !defined(lint)
202fe8fb19SBen Gras #ifdef notdef
212fe8fb19SBen Gras static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.1 2002/08/02 02:17:21 marka Exp ";
222fe8fb19SBen Gras #else
23*f14fb602SLionel Sambuc __RCSID("$NetBSD: inet_net_ntop.c,v 1.3 2012/03/20 17:08:13 matt Exp $");
242fe8fb19SBen Gras #endif
252fe8fb19SBen Gras #endif
262fe8fb19SBen Gras 
272fe8fb19SBen Gras #include "port_before.h"
282fe8fb19SBen Gras 
292fe8fb19SBen Gras #include "namespace.h"
302fe8fb19SBen Gras #include <sys/types.h>
312fe8fb19SBen Gras #include <sys/socket.h>
322fe8fb19SBen Gras #include <netinet/in.h>
332fe8fb19SBen Gras #include <arpa/inet.h>
342fe8fb19SBen Gras 
352fe8fb19SBen Gras #include <errno.h>
362fe8fb19SBen Gras #include <stdio.h>
372fe8fb19SBen Gras #include <string.h>
382fe8fb19SBen Gras #include <stdlib.h>
392fe8fb19SBen Gras 
402fe8fb19SBen Gras #include "port_after.h"
412fe8fb19SBen Gras 
422fe8fb19SBen Gras #ifdef __weak_alias
432fe8fb19SBen Gras __weak_alias(inet_net_ntop,_inet_net_ntop)
442fe8fb19SBen Gras #endif
452fe8fb19SBen Gras 
462fe8fb19SBen Gras #ifdef SPRINTF_CHAR
472fe8fb19SBen Gras # define SPRINTF(x) strlen(sprintf/**/x)
482fe8fb19SBen Gras #else
492fe8fb19SBen Gras # define SPRINTF(x) sprintf x
502fe8fb19SBen Gras #endif
512fe8fb19SBen Gras 
52*f14fb602SLionel Sambuc static char *	inet_net_ntop_ipv4(const u_char *src, int bits,
53*f14fb602SLionel Sambuc 					char *dst, size_t size);
54*f14fb602SLionel Sambuc static char *	inet_net_ntop_ipv6(const u_char *src, int bits,
55*f14fb602SLionel Sambuc 					char *dst, size_t size);
562fe8fb19SBen Gras 
572fe8fb19SBen Gras /*
582fe8fb19SBen Gras  * char *
592fe8fb19SBen Gras  * inet_net_ntop(af, src, bits, dst, size)
602fe8fb19SBen Gras  *	convert network number from network to presentation format.
612fe8fb19SBen Gras  *	generates CIDR style result always.
622fe8fb19SBen Gras  * return:
632fe8fb19SBen Gras  *	pointer to dst, or NULL if an error occurred (check errno).
642fe8fb19SBen Gras  * author:
652fe8fb19SBen Gras  *	Paul Vixie (ISC), July 1996
662fe8fb19SBen Gras  */
672fe8fb19SBen Gras char *
inet_net_ntop(int af,const void * src,int bits,char * dst,size_t size)68*f14fb602SLionel Sambuc inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
692fe8fb19SBen Gras {
702fe8fb19SBen Gras 	switch (af) {
712fe8fb19SBen Gras 	case AF_INET:
722fe8fb19SBen Gras 		return (inet_net_ntop_ipv4(src, bits, dst, size));
732fe8fb19SBen Gras 	case AF_INET6:
742fe8fb19SBen Gras 		return (inet_net_ntop_ipv6(src, bits, dst, size));
752fe8fb19SBen Gras 	default:
762fe8fb19SBen Gras 		errno = EAFNOSUPPORT;
772fe8fb19SBen Gras 		return (NULL);
782fe8fb19SBen Gras 	}
792fe8fb19SBen Gras }
802fe8fb19SBen Gras 
812fe8fb19SBen Gras /*
822fe8fb19SBen Gras  * static char *
832fe8fb19SBen Gras  * inet_net_ntop_ipv4(src, bits, dst, size)
842fe8fb19SBen Gras  *	convert IPv4 network number from network to presentation format.
852fe8fb19SBen Gras  *	generates CIDR style result always.
862fe8fb19SBen Gras  * return:
872fe8fb19SBen Gras  *	pointer to dst, or NULL if an error occurred (check errno).
882fe8fb19SBen Gras  * note:
892fe8fb19SBen Gras  *	network byte order assumed.  this means 192.5.5.240/28 has
902fe8fb19SBen Gras  *	0b11110000 in its fourth octet.
912fe8fb19SBen Gras  * author:
922fe8fb19SBen Gras  *	Paul Vixie (ISC), July 1996
932fe8fb19SBen Gras  */
942fe8fb19SBen Gras static char *
inet_net_ntop_ipv4(const u_char * src,int bits,char * dst,size_t size)95*f14fb602SLionel Sambuc inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
962fe8fb19SBen Gras {
972fe8fb19SBen Gras 	char *odst = dst;
982fe8fb19SBen Gras 	char *t;
992fe8fb19SBen Gras 	u_int m;
1002fe8fb19SBen Gras 	int b;
1012fe8fb19SBen Gras 
1022fe8fb19SBen Gras 	if (bits < 0 || bits > 32) {
1032fe8fb19SBen Gras 		errno = EINVAL;
1042fe8fb19SBen Gras 		return (NULL);
1052fe8fb19SBen Gras 	}
1062fe8fb19SBen Gras 
1072fe8fb19SBen Gras 	if (bits == 0) {
1082fe8fb19SBen Gras 		if (size < sizeof "0")
1092fe8fb19SBen Gras 			goto emsgsize;
1102fe8fb19SBen Gras 		*dst++ = '0';
1112fe8fb19SBen Gras 		size--;
1122fe8fb19SBen Gras 		*dst = '\0';
1132fe8fb19SBen Gras 	}
1142fe8fb19SBen Gras 
1152fe8fb19SBen Gras 	/* Format whole octets. */
1162fe8fb19SBen Gras 	for (b = bits / 8; b > 0; b--) {
1172fe8fb19SBen Gras 		if (size <= sizeof "255.")
1182fe8fb19SBen Gras 			goto emsgsize;
1192fe8fb19SBen Gras 		t = dst;
1202fe8fb19SBen Gras 		dst += SPRINTF((dst, "%u", *src++));
1212fe8fb19SBen Gras 		if (b > 1) {
1222fe8fb19SBen Gras 			*dst++ = '.';
1232fe8fb19SBen Gras 			*dst = '\0';
1242fe8fb19SBen Gras 		}
1252fe8fb19SBen Gras 		size -= (size_t)(dst - t);
1262fe8fb19SBen Gras 	}
1272fe8fb19SBen Gras 
1282fe8fb19SBen Gras 	/* Format partial octet. */
1292fe8fb19SBen Gras 	b = bits % 8;
1302fe8fb19SBen Gras 	if (b > 0) {
1312fe8fb19SBen Gras 		if (size <= sizeof ".255")
1322fe8fb19SBen Gras 			goto emsgsize;
1332fe8fb19SBen Gras 		t = dst;
1342fe8fb19SBen Gras 		if (dst != odst)
1352fe8fb19SBen Gras 			*dst++ = '.';
1362fe8fb19SBen Gras 		m = ((1 << b) - 1) << (8 - b);
1372fe8fb19SBen Gras 		dst += SPRINTF((dst, "%u", *src & m));
1382fe8fb19SBen Gras 		size -= (size_t)(dst - t);
1392fe8fb19SBen Gras 	}
1402fe8fb19SBen Gras 
1412fe8fb19SBen Gras 	/* Format CIDR /width. */
1422fe8fb19SBen Gras 	if (size <= sizeof "/32")
1432fe8fb19SBen Gras 		goto emsgsize;
1442fe8fb19SBen Gras 	dst += SPRINTF((dst, "/%u", bits));
1452fe8fb19SBen Gras 	return (odst);
1462fe8fb19SBen Gras 
1472fe8fb19SBen Gras  emsgsize:
1482fe8fb19SBen Gras 	errno = EMSGSIZE;
1492fe8fb19SBen Gras 	return (NULL);
1502fe8fb19SBen Gras }
1512fe8fb19SBen Gras 
1522fe8fb19SBen Gras /*
1532fe8fb19SBen Gras  * static char *
1542fe8fb19SBen Gras  * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
1552fe8fb19SBen Gras  *	convert IPv6 network number from network to presentation format.
1562fe8fb19SBen Gras  *	generates CIDR style result always. Picks the shortest representation
1572fe8fb19SBen Gras  *	unless the IP is really IPv4.
1582fe8fb19SBen Gras  *	always prints specified number of bits (bits).
1592fe8fb19SBen Gras  * return:
1602fe8fb19SBen Gras  *	pointer to dst, or NULL if an error occurred (check errno).
1612fe8fb19SBen Gras  * note:
1622fe8fb19SBen Gras  *	network byte order assumed.  this means 192.5.5.240/28 has
1632fe8fb19SBen Gras  *	0x11110000 in its fourth octet.
1642fe8fb19SBen Gras  * author:
1652fe8fb19SBen Gras  *	Vadim Kogan (UCB), June 2001
1662fe8fb19SBen Gras  *  Original version (IPv4) by Paul Vixie (ISC), July 1996
1672fe8fb19SBen Gras  */
1682fe8fb19SBen Gras 
1692fe8fb19SBen Gras static char *
inet_net_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)170*f14fb602SLionel Sambuc inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
171*f14fb602SLionel Sambuc {
1722fe8fb19SBen Gras 	u_int	m;
1732fe8fb19SBen Gras 	int	b;
1742fe8fb19SBen Gras 	size_t	p;
1752fe8fb19SBen Gras 	size_t	zero_s, zero_l, tmp_zero_s, tmp_zero_l;
1762fe8fb19SBen Gras 	size_t	i;
1772fe8fb19SBen Gras 	int	is_ipv4 = 0;
1782fe8fb19SBen Gras 	unsigned char inbuf[16];
1792fe8fb19SBen Gras 	char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
1802fe8fb19SBen Gras 	char	*cp;
1812fe8fb19SBen Gras 	size_t	words;
1822fe8fb19SBen Gras 	u_char	*s;
1832fe8fb19SBen Gras 
1842fe8fb19SBen Gras 	if (bits < 0 || bits > 128) {
1852fe8fb19SBen Gras 		errno = EINVAL;
1862fe8fb19SBen Gras 		return (NULL);
1872fe8fb19SBen Gras 	}
1882fe8fb19SBen Gras 
1892fe8fb19SBen Gras 	cp = outbuf;
1902fe8fb19SBen Gras 
1912fe8fb19SBen Gras 	if (bits == 0) {
1922fe8fb19SBen Gras 		*cp++ = ':';
1932fe8fb19SBen Gras 		*cp++ = ':';
1942fe8fb19SBen Gras 		*cp = '\0';
1952fe8fb19SBen Gras 	} else {
1962fe8fb19SBen Gras 		/* Copy src to private buffer.  Zero host part. */
1972fe8fb19SBen Gras 		p = (bits + 7) / 8;
1982fe8fb19SBen Gras 		memcpy(inbuf, src, p);
1992fe8fb19SBen Gras 		memset(inbuf + p, 0, 16 - p);
2002fe8fb19SBen Gras 		b = bits % 8;
2012fe8fb19SBen Gras 		if (b != 0) {
2022fe8fb19SBen Gras 			m = ~0 << (8 - b);
2032fe8fb19SBen Gras 			inbuf[p-1] &= m;
2042fe8fb19SBen Gras 		}
2052fe8fb19SBen Gras 
2062fe8fb19SBen Gras 		s = inbuf;
2072fe8fb19SBen Gras 
2082fe8fb19SBen Gras 		/* how many words need to be displayed in output */
2092fe8fb19SBen Gras 		words = (bits + 15) / 16;
2102fe8fb19SBen Gras 		if (words == 1)
2112fe8fb19SBen Gras 			words = 2;
2122fe8fb19SBen Gras 
2132fe8fb19SBen Gras 		/* Find the longest substring of zero's */
2142fe8fb19SBen Gras 		zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
2152fe8fb19SBen Gras 		for (i = 0; i < (words * 2); i += 2) {
2162fe8fb19SBen Gras 			if ((s[i] | s[i+1]) == 0) {
2172fe8fb19SBen Gras 				if (tmp_zero_l == 0)
2182fe8fb19SBen Gras 					tmp_zero_s = i / 2;
2192fe8fb19SBen Gras 				tmp_zero_l++;
2202fe8fb19SBen Gras 			} else {
2212fe8fb19SBen Gras 				if (tmp_zero_l && zero_l < tmp_zero_l) {
2222fe8fb19SBen Gras 					zero_s = tmp_zero_s;
2232fe8fb19SBen Gras 					zero_l = tmp_zero_l;
2242fe8fb19SBen Gras 					tmp_zero_l = 0;
2252fe8fb19SBen Gras 				}
2262fe8fb19SBen Gras 			}
2272fe8fb19SBen Gras 		}
2282fe8fb19SBen Gras 
2292fe8fb19SBen Gras 		if (tmp_zero_l && zero_l < tmp_zero_l) {
2302fe8fb19SBen Gras 			zero_s = tmp_zero_s;
2312fe8fb19SBen Gras 			zero_l = tmp_zero_l;
2322fe8fb19SBen Gras 		}
2332fe8fb19SBen Gras 
2342fe8fb19SBen Gras 		if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
2352fe8fb19SBen Gras 		    ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
2362fe8fb19SBen Gras 		    ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
2372fe8fb19SBen Gras 			is_ipv4 = 1;
2382fe8fb19SBen Gras 
2392fe8fb19SBen Gras 		/* Format whole words. */
2402fe8fb19SBen Gras 		for (p = 0; p < words; p++) {
2412fe8fb19SBen Gras 			if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
2422fe8fb19SBen Gras 				/* Time to skip some zeros */
2432fe8fb19SBen Gras 				if (p == zero_s)
2442fe8fb19SBen Gras 					*cp++ = ':';
2452fe8fb19SBen Gras 				if (p == words - 1)
2462fe8fb19SBen Gras 					*cp++ = ':';
2472fe8fb19SBen Gras 				s++;
2482fe8fb19SBen Gras 				s++;
2492fe8fb19SBen Gras 				continue;
2502fe8fb19SBen Gras 			}
2512fe8fb19SBen Gras 
2522fe8fb19SBen Gras 			if (is_ipv4 && p > 5 ) {
2532fe8fb19SBen Gras 				*cp++ = (p == 6) ? ':' : '.';
2542fe8fb19SBen Gras 				cp += SPRINTF((cp, "%u", *s++));
2552fe8fb19SBen Gras 				/* we can potentially drop the last octet */
2562fe8fb19SBen Gras 				if (p != 7 || bits > 120) {
2572fe8fb19SBen Gras 					*cp++ = '.';
2582fe8fb19SBen Gras 					cp += SPRINTF((cp, "%u", *s++));
2592fe8fb19SBen Gras 				}
2602fe8fb19SBen Gras 			} else {
2612fe8fb19SBen Gras 				if (cp != outbuf)
2622fe8fb19SBen Gras 					*cp++ = ':';
2632fe8fb19SBen Gras 				cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
2642fe8fb19SBen Gras 				s += 2;
2652fe8fb19SBen Gras 			}
2662fe8fb19SBen Gras 		}
2672fe8fb19SBen Gras 	}
2682fe8fb19SBen Gras 	/* Format CIDR /width. */
2692fe8fb19SBen Gras 	(void)SPRINTF((cp, "/%u", bits));
2702fe8fb19SBen Gras 	if (strlen(outbuf) + 1 > size)
2712fe8fb19SBen Gras 		goto emsgsize;
2722fe8fb19SBen Gras 	strcpy(dst, outbuf);
2732fe8fb19SBen Gras 
2742fe8fb19SBen Gras 	return (dst);
2752fe8fb19SBen Gras 
2762fe8fb19SBen Gras emsgsize:
2772fe8fb19SBen Gras 	errno = EMSGSIZE;
2782fe8fb19SBen Gras 	return (NULL);
2792fe8fb19SBen Gras }
280