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