/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")4* Copyright (c) 1998,1999 by Internet Software Consortium.5*6* Permission to use, copy, modify, and distribute this software for any7* purpose with or without fee is hereby granted, provided that the above8* copyright notice and this permission notice appear in all copies.9*10* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES11* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF12* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR13* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES14* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN15* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT16* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.17*/1819#include "port_before.h"2021#include <sys/types.h>22#include <sys/socket.h>23#include <netinet/in.h>24#include <arpa/nameser.h>25#include <arpa/inet.h>2627#include <errno.h>28#include <stdio.h>29#include <string.h>30#include <stdlib.h>3132#include "port_after.h"3334#ifdef SPRINTF_CHAR35# define SPRINTF(x) strlen(sprintf/**/x)36#else37# define SPRINTF(x) ((size_t)sprintf x)38#endif3940static char *41inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size);42static char *43inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size);4445/*%46* char *47* inet_cidr_ntop(af, src, bits, dst, size)48* convert network address from network to presentation format.49* "src"'s size is determined from its "af".50* return:51* pointer to dst, or NULL if an error occurred (check errno).52* note:53* 192.5.5.1/28 has a nonzero host part, which means it isn't a network54* as called for by inet_net_ntop() but it can be a host address with55* an included netmask.56* author:57* Paul Vixie (ISC), October 199858*/59char *60inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {61switch (af) {62case AF_INET:63return (inet_cidr_ntop_ipv4(src, bits, dst, size));64case AF_INET6:65return (inet_cidr_ntop_ipv6(src, bits, dst, size));66default:67errno = EAFNOSUPPORT;68return (NULL);69}70}7172static int73decoct(const u_char *src, int bytes, char *dst, size_t size) {74char *odst = dst;75char *t;76int b;7778for (b = 1; b <= bytes; b++) {79if (size < sizeof "255.")80return (0);81t = dst;82dst += SPRINTF((dst, "%u", *src++));83if (b != bytes) {84*dst++ = '.';85*dst = '\0';86}87size -= (size_t)(dst - t);88}89return (dst - odst);90}9192/*%93* static char *94* inet_cidr_ntop_ipv4(src, bits, dst, size)95* convert IPv4 network address from network to presentation format.96* "src"'s size is determined from its "af".97* return:98* pointer to dst, or NULL if an error occurred (check errno).99* note:100* network byte order assumed. this means 192.5.5.240/28 has101* 0b11110000 in its fourth octet.102* author:103* Paul Vixie (ISC), October 1998104*/105static char *106inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {107char *odst = dst;108size_t len = 4;109size_t b;110size_t bytes;111112if ((bits < -1) || (bits > 32)) {113errno = EINVAL;114return (NULL);115}116117/* Find number of significant bytes in address. */118if (bits == -1)119len = 4;120else121for (len = 1, b = 1 ; b < 4U; b++)122if (*(src + b))123len = b + 1;124125/* Format whole octets plus nonzero trailing octets. */126bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;127if (len > bytes)128bytes = len;129b = decoct(src, bytes, dst, size);130if (b == 0U)131goto emsgsize;132dst += b;133size -= b;134135if (bits != -1) {136/* Format CIDR /width. */137if (size < sizeof "/32")138goto emsgsize;139dst += SPRINTF((dst, "/%u", bits));140}141142return (odst);143144emsgsize:145errno = EMSGSIZE;146return (NULL);147}148149static char *150inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {151/*152* Note that int32_t and int16_t need only be "at least" large enough153* to contain a value of the specified size. On some systems, like154* Crays, there is no such thing as an integer variable with 16 bits.155* Keep this in mind if you think this function should have been coded156* to use pointer overlays. All the world's not a VAX.157*/158char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];159char *tp;160struct { int base, len; } best, cur;161u_int words[NS_IN6ADDRSZ / NS_INT16SZ];162int i;163164if ((bits < -1) || (bits > 128)) {165errno = EINVAL;166return (NULL);167}168169/*170* Preprocess:171* Copy the input (bytewise) array into a wordwise array.172* Find the longest run of 0x00's in src[] for :: shorthanding.173*/174memset(words, '\0', sizeof words);175for (i = 0; i < NS_IN6ADDRSZ; i++)176words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));177best.base = -1;178best.len = 0;179cur.base = -1;180cur.len = 0;181for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {182if (words[i] == 0) {183if (cur.base == -1)184cur.base = i, cur.len = 1;185else186cur.len++;187} else {188if (cur.base != -1) {189if (best.base == -1 || cur.len > best.len)190best = cur;191cur.base = -1;192}193}194}195if (cur.base != -1) {196if (best.base == -1 || cur.len > best.len)197best = cur;198}199if (best.base != -1 && best.len < 2)200best.base = -1;201202/*203* Format the result.204*/205tp = tmp;206for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {207/* Are we inside the best run of 0x00's? */208if (best.base != -1 && i >= best.base &&209i < (best.base + best.len)) {210if (i == best.base)211*tp++ = ':';212continue;213}214/* Are we following an initial run of 0x00s or any real hex? */215if (i != 0)216*tp++ = ':';217/* Is this address an encapsulated IPv4? */218if (i == 6 && best.base == 0 && (best.len == 6 ||219(best.len == 7 && words[7] != 0x0001) ||220(best.len == 5 && words[5] == 0xffff))) {221int n;222223if (src[15] || bits == -1 || bits > 120)224n = 4;225else if (src[14] || bits > 112)226n = 3;227else228n = 2;229n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));230if (n == 0) {231errno = EMSGSIZE;232return (NULL);233}234tp += strlen(tp);235break;236}237tp += SPRINTF((tp, "%x", words[i]));238}239240/* Was it a trailing run of 0x00's? */241if (best.base != -1 && (best.base + best.len) ==242(NS_IN6ADDRSZ / NS_INT16SZ))243*tp++ = ':';244*tp = '\0';245246if (bits != -1)247tp += SPRINTF((tp, "/%u", bits));248249/*250* Check for overflow, copy, and we're done.251*/252if ((size_t)(tp - tmp) > size) {253errno = EMSGSIZE;254return (NULL);255}256strcpy(dst, tmp);257return (dst);258}259260/*! \file */261262263