Home | History | Annotate | Line # | Download | only in inet
inet_net_ntop.c revision 1.2.8.1
      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.2.8.1      yamt __RCSID("$NetBSD: inet_net_ntop.c,v 1.2.8.1 2012/04/17 00:05:20 yamt 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.2.8.1      yamt static char *	inet_net_ntop_ipv4(const u_char *src, int bits,
     53  1.2.8.1      yamt 					char *dst, size_t size);
     54  1.2.8.1      yamt static char *	inet_net_ntop_ipv6(const u_char *src, int bits,
     55  1.2.8.1      yamt 					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.2.8.1      yamt 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.2.8.1      yamt 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.2.8.1      yamt inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
    171  1.2.8.1      yamt {
    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.1  christos 			m = ~0 << (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