/*-1* SPDX-License-Identifier: ISC2*3* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")4* Copyright (c) 1996,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/inet.h>2526#include <errno.h>27#include <stdio.h>28#include <string.h>29#include <stdlib.h>3031#include "port_after.h"3233#ifdef SPRINTF_CHAR34# define SPRINTF(x) strlen(sprintf/**/x)35#else36# define SPRINTF(x) ((size_t)sprintf x)37#endif3839static char * inet_net_ntop_ipv4(const u_char *src, int bits, char *dst,40size_t size);41static char * inet_net_ntop_ipv6(const u_char *src, int bits, char *dst,42size_t size);4344/*%45* char *46* inet_net_ntop(af, src, bits, dst, size)47* convert network number from network to presentation format.48* generates CIDR style result always.49* return:50* pointer to dst, or NULL if an error occurred (check errno).51* author:52* Paul Vixie (ISC), July 199653*/54char *55inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)56{57switch (af) {58case AF_INET:59return (inet_net_ntop_ipv4(src, bits, dst, size));60case AF_INET6:61return (inet_net_ntop_ipv6(src, bits, dst, size));62default:63errno = EAFNOSUPPORT;64return (NULL);65}66}6768/*%69* static char *70* inet_net_ntop_ipv4(src, bits, dst, size)71* convert IPv4 network number from network to presentation format.72* generates CIDR style result always.73* return:74* pointer to dst, or NULL if an error occurred (check errno).75* note:76* network byte order assumed. this means 192.5.5.240/28 has77* 0b11110000 in its fourth octet.78* author:79* Paul Vixie (ISC), July 199680*/81static char *82inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)83{84char *odst = dst;85char *t;86u_int m;87int b;8889if (bits < 0 || bits > 32) {90errno = EINVAL;91return (NULL);92}9394if (bits == 0) {95if (size < sizeof "0")96goto emsgsize;97*dst++ = '0';98size--;99*dst = '\0';100}101102/* Format whole octets. */103for (b = bits / 8; b > 0; b--) {104if (size <= sizeof "255.")105goto emsgsize;106t = dst;107dst += SPRINTF((dst, "%u", *src++));108if (b > 1) {109*dst++ = '.';110*dst = '\0';111}112size -= (size_t)(dst - t);113}114115/* Format partial octet. */116b = bits % 8;117if (b > 0) {118if (size <= sizeof ".255")119goto emsgsize;120t = dst;121if (dst != odst)122*dst++ = '.';123m = ((1 << b) - 1) << (8 - b);124dst += SPRINTF((dst, "%u", *src & m));125size -= (size_t)(dst - t);126}127128/* Format CIDR /width. */129if (size <= sizeof "/32")130goto emsgsize;131dst += SPRINTF((dst, "/%u", bits));132return (odst);133134emsgsize:135errno = EMSGSIZE;136return (NULL);137}138139/*%140* static char *141* inet_net_ntop_ipv6(src, bits, fakebits, dst, size)142* convert IPv6 network number from network to presentation format.143* generates CIDR style result always. Picks the shortest representation144* unless the IP is really IPv4.145* always prints specified number of bits (bits).146* return:147* pointer to dst, or NULL if an error occurred (check errno).148* note:149* network byte order assumed. this means 192.5.5.240/28 has150* 0b11110000 in its fourth octet.151* author:152* Vadim Kogan (UCB), June 2001153* Original version (IPv4) by Paul Vixie (ISC), July 1996154*/155156static char *157inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {158u_int m;159int b;160int p;161int zero_s, zero_l, tmp_zero_s, tmp_zero_l;162int i;163int is_ipv4 = 0;164unsigned char inbuf[16];165char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];166char *cp;167int words;168u_char *s;169170if (bits < 0 || bits > 128) {171errno = EINVAL;172return (NULL);173}174175cp = outbuf;176177if (bits == 0) {178*cp++ = ':';179*cp++ = ':';180*cp = '\0';181} else {182/* Copy src to private buffer. Zero host part. */183p = (bits + 7) / 8;184memcpy(inbuf, src, p);185memset(inbuf + p, 0, 16 - p);186b = bits % 8;187if (b != 0) {188m = ~0 << (8 - b);189inbuf[p-1] &= m;190}191192s = inbuf;193194/* how many words need to be displayed in output */195words = (bits + 15) / 16;196if (words == 1)197words = 2;198199/* Find the longest substring of zero's */200zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;201for (i = 0; i < (words * 2); i += 2) {202if ((s[i] | s[i+1]) == 0) {203if (tmp_zero_l == 0)204tmp_zero_s = i / 2;205tmp_zero_l++;206} else {207if (tmp_zero_l && zero_l < tmp_zero_l) {208zero_s = tmp_zero_s;209zero_l = tmp_zero_l;210tmp_zero_l = 0;211}212}213}214215if (tmp_zero_l && zero_l < tmp_zero_l) {216zero_s = tmp_zero_s;217zero_l = tmp_zero_l;218}219220if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||221((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||222((zero_l == 7 && s[14] != 0 && s[15] != 1)))))223is_ipv4 = 1;224225/* Format whole words. */226for (p = 0; p < words; p++) {227if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {228/* Time to skip some zeros */229if (p == zero_s)230*cp++ = ':';231if (p == words - 1)232*cp++ = ':';233s++;234s++;235continue;236}237238if (is_ipv4 && p > 5 ) {239*cp++ = (p == 6) ? ':' : '.';240cp += SPRINTF((cp, "%u", *s++));241/* we can potentially drop the last octet */242if (p != 7 || bits > 120) {243*cp++ = '.';244cp += SPRINTF((cp, "%u", *s++));245}246} else {247if (cp != outbuf)248*cp++ = ':';249cp += SPRINTF((cp, "%x", *s * 256 + s[1]));250s += 2;251}252}253}254/* Format CIDR /width. */255sprintf(cp, "/%u", bits);256if (strlen(outbuf) + 1 > size)257goto emsgsize;258strcpy(dst, outbuf);259260return (dst);261262emsgsize:263errno = EMSGSIZE;264return (NULL);265}266267/*268* Weak aliases for applications that use certain private entry points,269* and fail to include <arpa/inet.h>.270*/271#undef inet_net_ntop272__weak_reference(__inet_net_ntop, inet_net_ntop);273274/*! \file */275276277