10Sstevel@tonic-gate /*
2*11038SRao.Shoaib@Sun.COM * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
30Sstevel@tonic-gate * Copyright (c) 1998,1999 by Internet Software Consortium.
40Sstevel@tonic-gate *
50Sstevel@tonic-gate * Permission to use, copy, modify, and distribute this software for any
60Sstevel@tonic-gate * purpose with or without fee is hereby granted, provided that the above
70Sstevel@tonic-gate * copyright notice and this permission notice appear in all copies.
80Sstevel@tonic-gate *
9*11038SRao.Shoaib@Sun.COM * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10*11038SRao.Shoaib@Sun.COM * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11*11038SRao.Shoaib@Sun.COM * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12*11038SRao.Shoaib@Sun.COM * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13*11038SRao.Shoaib@Sun.COM * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14*11038SRao.Shoaib@Sun.COM * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15*11038SRao.Shoaib@Sun.COM * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
160Sstevel@tonic-gate */
170Sstevel@tonic-gate
180Sstevel@tonic-gate #if defined(LIBC_SCCS) && !defined(lint)
19*11038SRao.Shoaib@Sun.COM static const char rcsid[] = "$Id: inet_cidr_ntop.c,v 1.7 2006/10/11 02:18:18 marka Exp $";
200Sstevel@tonic-gate #endif
210Sstevel@tonic-gate
220Sstevel@tonic-gate #include "port_before.h"
230Sstevel@tonic-gate
240Sstevel@tonic-gate #include <sys/types.h>
250Sstevel@tonic-gate #include <sys/socket.h>
260Sstevel@tonic-gate #include <netinet/in.h>
270Sstevel@tonic-gate #include <arpa/nameser.h>
280Sstevel@tonic-gate #include <arpa/inet.h>
290Sstevel@tonic-gate
300Sstevel@tonic-gate #include <errno.h>
310Sstevel@tonic-gate #include <stdio.h>
320Sstevel@tonic-gate #include <string.h>
330Sstevel@tonic-gate #include <stdlib.h>
340Sstevel@tonic-gate
350Sstevel@tonic-gate #include "port_after.h"
360Sstevel@tonic-gate
370Sstevel@tonic-gate #ifdef SPRINTF_CHAR
380Sstevel@tonic-gate # define SPRINTF(x) strlen(sprintf/**/x)
390Sstevel@tonic-gate #else
400Sstevel@tonic-gate # define SPRINTF(x) ((size_t)sprintf x)
410Sstevel@tonic-gate #endif
420Sstevel@tonic-gate
43*11038SRao.Shoaib@Sun.COM static char *
44*11038SRao.Shoaib@Sun.COM inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size);
45*11038SRao.Shoaib@Sun.COM static char *
46*11038SRao.Shoaib@Sun.COM inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size);
470Sstevel@tonic-gate
48*11038SRao.Shoaib@Sun.COM /*%
490Sstevel@tonic-gate * char *
500Sstevel@tonic-gate * inet_cidr_ntop(af, src, bits, dst, size)
510Sstevel@tonic-gate * convert network address from network to presentation format.
520Sstevel@tonic-gate * "src"'s size is determined from its "af".
530Sstevel@tonic-gate * return:
540Sstevel@tonic-gate * pointer to dst, or NULL if an error occurred (check errno).
550Sstevel@tonic-gate * note:
560Sstevel@tonic-gate * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
570Sstevel@tonic-gate * as called for by inet_net_ntop() but it can be a host address with
580Sstevel@tonic-gate * an included netmask.
590Sstevel@tonic-gate * author:
600Sstevel@tonic-gate * Paul Vixie (ISC), October 1998
610Sstevel@tonic-gate */
620Sstevel@tonic-gate char *
inet_cidr_ntop(int af,const void * src,int bits,char * dst,size_t size)630Sstevel@tonic-gate inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
640Sstevel@tonic-gate switch (af) {
650Sstevel@tonic-gate case AF_INET:
660Sstevel@tonic-gate return (inet_cidr_ntop_ipv4(src, bits, dst, size));
670Sstevel@tonic-gate case AF_INET6:
680Sstevel@tonic-gate return (inet_cidr_ntop_ipv6(src, bits, dst, size));
690Sstevel@tonic-gate default:
700Sstevel@tonic-gate errno = EAFNOSUPPORT;
710Sstevel@tonic-gate return (NULL);
720Sstevel@tonic-gate }
730Sstevel@tonic-gate }
740Sstevel@tonic-gate
750Sstevel@tonic-gate static int
decoct(const u_char * src,int bytes,char * dst,size_t size)760Sstevel@tonic-gate decoct(const u_char *src, int bytes, char *dst, size_t size) {
770Sstevel@tonic-gate char *odst = dst;
780Sstevel@tonic-gate char *t;
790Sstevel@tonic-gate int b;
800Sstevel@tonic-gate
810Sstevel@tonic-gate for (b = 1; b <= bytes; b++) {
820Sstevel@tonic-gate if (size < sizeof "255.")
830Sstevel@tonic-gate return (0);
840Sstevel@tonic-gate t = dst;
850Sstevel@tonic-gate dst += SPRINTF((dst, "%u", *src++));
860Sstevel@tonic-gate if (b != bytes) {
870Sstevel@tonic-gate *dst++ = '.';
880Sstevel@tonic-gate *dst = '\0';
890Sstevel@tonic-gate }
900Sstevel@tonic-gate size -= (size_t)(dst - t);
910Sstevel@tonic-gate }
920Sstevel@tonic-gate return (dst - odst);
930Sstevel@tonic-gate }
940Sstevel@tonic-gate
95*11038SRao.Shoaib@Sun.COM /*%
960Sstevel@tonic-gate * static char *
970Sstevel@tonic-gate * inet_cidr_ntop_ipv4(src, bits, dst, size)
980Sstevel@tonic-gate * convert IPv4 network address from network to presentation format.
990Sstevel@tonic-gate * "src"'s size is determined from its "af".
1000Sstevel@tonic-gate * return:
1010Sstevel@tonic-gate * pointer to dst, or NULL if an error occurred (check errno).
1020Sstevel@tonic-gate * note:
1030Sstevel@tonic-gate * network byte order assumed. this means 192.5.5.240/28 has
1040Sstevel@tonic-gate * 0b11110000 in its fourth octet.
1050Sstevel@tonic-gate * author:
1060Sstevel@tonic-gate * Paul Vixie (ISC), October 1998
1070Sstevel@tonic-gate */
1080Sstevel@tonic-gate static char *
inet_cidr_ntop_ipv4(const u_char * src,int bits,char * dst,size_t size)1090Sstevel@tonic-gate inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
1100Sstevel@tonic-gate char *odst = dst;
1110Sstevel@tonic-gate size_t len = 4;
1120Sstevel@tonic-gate size_t b;
1130Sstevel@tonic-gate size_t bytes;
1140Sstevel@tonic-gate
1150Sstevel@tonic-gate if ((bits < -1) || (bits > 32)) {
1160Sstevel@tonic-gate errno = EINVAL;
1170Sstevel@tonic-gate return (NULL);
1180Sstevel@tonic-gate }
1190Sstevel@tonic-gate
1200Sstevel@tonic-gate /* Find number of significant bytes in address. */
1210Sstevel@tonic-gate if (bits == -1)
1220Sstevel@tonic-gate len = 4;
1230Sstevel@tonic-gate else
124*11038SRao.Shoaib@Sun.COM for (len = 1, b = 1 ; b < 4U; b++)
1250Sstevel@tonic-gate if (*(src + b))
1260Sstevel@tonic-gate len = b + 1;
1270Sstevel@tonic-gate
1280Sstevel@tonic-gate /* Format whole octets plus nonzero trailing octets. */
1290Sstevel@tonic-gate bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
1300Sstevel@tonic-gate if (len > bytes)
1310Sstevel@tonic-gate bytes = len;
1320Sstevel@tonic-gate b = decoct(src, bytes, dst, size);
133*11038SRao.Shoaib@Sun.COM if (b == 0U)
1340Sstevel@tonic-gate goto emsgsize;
1350Sstevel@tonic-gate dst += b;
1360Sstevel@tonic-gate size -= b;
1370Sstevel@tonic-gate
1380Sstevel@tonic-gate if (bits != -1) {
1390Sstevel@tonic-gate /* Format CIDR /width. */
1400Sstevel@tonic-gate if (size < sizeof "/32")
1410Sstevel@tonic-gate goto emsgsize;
1420Sstevel@tonic-gate dst += SPRINTF((dst, "/%u", bits));
1430Sstevel@tonic-gate }
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate return (odst);
1460Sstevel@tonic-gate
1470Sstevel@tonic-gate emsgsize:
1480Sstevel@tonic-gate errno = EMSGSIZE;
1490Sstevel@tonic-gate return (NULL);
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate static char *
inet_cidr_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)1530Sstevel@tonic-gate inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
1540Sstevel@tonic-gate /*
1550Sstevel@tonic-gate * Note that int32_t and int16_t need only be "at least" large enough
1560Sstevel@tonic-gate * to contain a value of the specified size. On some systems, like
1570Sstevel@tonic-gate * Crays, there is no such thing as an integer variable with 16 bits.
1580Sstevel@tonic-gate * Keep this in mind if you think this function should have been coded
1590Sstevel@tonic-gate * to use pointer overlays. All the world's not a VAX.
1600Sstevel@tonic-gate */
1610Sstevel@tonic-gate char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
1620Sstevel@tonic-gate char *tp;
1630Sstevel@tonic-gate struct { int base, len; } best, cur;
1640Sstevel@tonic-gate u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
1650Sstevel@tonic-gate int i;
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate if ((bits < -1) || (bits > 128)) {
1680Sstevel@tonic-gate errno = EINVAL;
1690Sstevel@tonic-gate return (NULL);
1700Sstevel@tonic-gate }
1710Sstevel@tonic-gate
1720Sstevel@tonic-gate /*
1730Sstevel@tonic-gate * Preprocess:
1740Sstevel@tonic-gate * Copy the input (bytewise) array into a wordwise array.
1750Sstevel@tonic-gate * Find the longest run of 0x00's in src[] for :: shorthanding.
1760Sstevel@tonic-gate */
1770Sstevel@tonic-gate memset(words, '\0', sizeof words);
1780Sstevel@tonic-gate for (i = 0; i < NS_IN6ADDRSZ; i++)
1790Sstevel@tonic-gate words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
1800Sstevel@tonic-gate best.base = -1;
181*11038SRao.Shoaib@Sun.COM best.len = 0;
1820Sstevel@tonic-gate cur.base = -1;
183*11038SRao.Shoaib@Sun.COM cur.len = 0;
1840Sstevel@tonic-gate for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
1850Sstevel@tonic-gate if (words[i] == 0) {
1860Sstevel@tonic-gate if (cur.base == -1)
1870Sstevel@tonic-gate cur.base = i, cur.len = 1;
1880Sstevel@tonic-gate else
1890Sstevel@tonic-gate cur.len++;
1900Sstevel@tonic-gate } else {
1910Sstevel@tonic-gate if (cur.base != -1) {
1920Sstevel@tonic-gate if (best.base == -1 || cur.len > best.len)
1930Sstevel@tonic-gate best = cur;
1940Sstevel@tonic-gate cur.base = -1;
1950Sstevel@tonic-gate }
1960Sstevel@tonic-gate }
1970Sstevel@tonic-gate }
1980Sstevel@tonic-gate if (cur.base != -1) {
1990Sstevel@tonic-gate if (best.base == -1 || cur.len > best.len)
2000Sstevel@tonic-gate best = cur;
2010Sstevel@tonic-gate }
2020Sstevel@tonic-gate if (best.base != -1 && best.len < 2)
2030Sstevel@tonic-gate best.base = -1;
2040Sstevel@tonic-gate
2050Sstevel@tonic-gate /*
2060Sstevel@tonic-gate * Format the result.
2070Sstevel@tonic-gate */
2080Sstevel@tonic-gate tp = tmp;
2090Sstevel@tonic-gate for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
2100Sstevel@tonic-gate /* Are we inside the best run of 0x00's? */
2110Sstevel@tonic-gate if (best.base != -1 && i >= best.base &&
2120Sstevel@tonic-gate i < (best.base + best.len)) {
2130Sstevel@tonic-gate if (i == best.base)
2140Sstevel@tonic-gate *tp++ = ':';
2150Sstevel@tonic-gate continue;
2160Sstevel@tonic-gate }
2170Sstevel@tonic-gate /* Are we following an initial run of 0x00s or any real hex? */
2180Sstevel@tonic-gate if (i != 0)
2190Sstevel@tonic-gate *tp++ = ':';
2200Sstevel@tonic-gate /* Is this address an encapsulated IPv4? */
2210Sstevel@tonic-gate if (i == 6 && best.base == 0 && (best.len == 6 ||
2220Sstevel@tonic-gate (best.len == 7 && words[7] != 0x0001) ||
2230Sstevel@tonic-gate (best.len == 5 && words[5] == 0xffff))) {
2240Sstevel@tonic-gate int n;
2250Sstevel@tonic-gate
2260Sstevel@tonic-gate if (src[15] || bits == -1 || bits > 120)
2270Sstevel@tonic-gate n = 4;
2280Sstevel@tonic-gate else if (src[14] || bits > 112)
2290Sstevel@tonic-gate n = 3;
2300Sstevel@tonic-gate else
2310Sstevel@tonic-gate n = 2;
2320Sstevel@tonic-gate n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
2330Sstevel@tonic-gate if (n == 0) {
2340Sstevel@tonic-gate errno = EMSGSIZE;
2350Sstevel@tonic-gate return (NULL);
2360Sstevel@tonic-gate }
2370Sstevel@tonic-gate tp += strlen(tp);
2380Sstevel@tonic-gate break;
2390Sstevel@tonic-gate }
2400Sstevel@tonic-gate tp += SPRINTF((tp, "%x", words[i]));
2410Sstevel@tonic-gate }
2420Sstevel@tonic-gate
2430Sstevel@tonic-gate /* Was it a trailing run of 0x00's? */
2440Sstevel@tonic-gate if (best.base != -1 && (best.base + best.len) ==
2450Sstevel@tonic-gate (NS_IN6ADDRSZ / NS_INT16SZ))
2460Sstevel@tonic-gate *tp++ = ':';
2470Sstevel@tonic-gate *tp = '\0';
2480Sstevel@tonic-gate
2490Sstevel@tonic-gate if (bits != -1)
2500Sstevel@tonic-gate tp += SPRINTF((tp, "/%u", bits));
2510Sstevel@tonic-gate
2520Sstevel@tonic-gate /*
2530Sstevel@tonic-gate * Check for overflow, copy, and we're done.
2540Sstevel@tonic-gate */
2550Sstevel@tonic-gate if ((size_t)(tp - tmp) > size) {
2560Sstevel@tonic-gate errno = EMSGSIZE;
2570Sstevel@tonic-gate return (NULL);
2580Sstevel@tonic-gate }
2590Sstevel@tonic-gate strcpy(dst, tmp);
2600Sstevel@tonic-gate return (dst);
2610Sstevel@tonic-gate }
262*11038SRao.Shoaib@Sun.COM
263*11038SRao.Shoaib@Sun.COM /*! \file */
264