Home | History | Annotate | Line # | Download | only in inet
inet_net_ntop.c revision 1.3.22.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.3.22.1  pgoyette __RCSID("$NetBSD: inet_net_ntop.c,v 1.3.22.1 2017/05/11 02:58:33 pgoyette 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.3.22.1  pgoyette 			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