1*aa6411e2SAugustin Cavalier /*
2*aa6411e2SAugustin Cavalier * Copyright (c) 1996,1999 by Internet Software Consortium.
3*aa6411e2SAugustin Cavalier *
4*aa6411e2SAugustin Cavalier * Permission to use, copy, modify, and distribute this software for any
5*aa6411e2SAugustin Cavalier * purpose with or without fee is hereby granted, provided that the above
6*aa6411e2SAugustin Cavalier * copyright notice and this permission notice appear in all copies.
7*aa6411e2SAugustin Cavalier *
8*aa6411e2SAugustin Cavalier * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9*aa6411e2SAugustin Cavalier * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10*aa6411e2SAugustin Cavalier * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11*aa6411e2SAugustin Cavalier * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12*aa6411e2SAugustin Cavalier * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13*aa6411e2SAugustin Cavalier * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14*aa6411e2SAugustin Cavalier * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15*aa6411e2SAugustin Cavalier * SOFTWARE.
16*aa6411e2SAugustin Cavalier */
17*aa6411e2SAugustin Cavalier
18*aa6411e2SAugustin Cavalier #include <sys/cdefs.h>
19*aa6411e2SAugustin Cavalier #if defined(LIBC_SCCS) && !defined(lint)
20*aa6411e2SAugustin Cavalier #ifdef notdef
21*aa6411e2SAugustin Cavalier static const char rcsid[] = "Id: inet_net_ntop.c,v 1.1.2.1 2002/08/02 02:17:21 marka Exp ";
22*aa6411e2SAugustin Cavalier #else
23*aa6411e2SAugustin Cavalier __RCSID("$NetBSD: inet_net_ntop.c,v 1.4 2017/05/09 02:56:44 maya Exp $");
24*aa6411e2SAugustin Cavalier #endif
25*aa6411e2SAugustin Cavalier #endif
26*aa6411e2SAugustin Cavalier
27*aa6411e2SAugustin Cavalier #include "port_before.h"
28*aa6411e2SAugustin Cavalier
29*aa6411e2SAugustin Cavalier #include <sys/types.h>
30*aa6411e2SAugustin Cavalier #include <sys/socket.h>
31*aa6411e2SAugustin Cavalier #include <netinet/in.h>
32*aa6411e2SAugustin Cavalier #include <arpa/inet.h>
33*aa6411e2SAugustin Cavalier
34*aa6411e2SAugustin Cavalier #include <errno.h>
35*aa6411e2SAugustin Cavalier #include <stdio.h>
36*aa6411e2SAugustin Cavalier #include <string.h>
37*aa6411e2SAugustin Cavalier #include <stdlib.h>
38*aa6411e2SAugustin Cavalier
39*aa6411e2SAugustin Cavalier #include "port_after.h"
40*aa6411e2SAugustin Cavalier
41*aa6411e2SAugustin Cavalier #ifdef __weak_alias
42*aa6411e2SAugustin Cavalier __weak_alias(inet_net_ntop,_inet_net_ntop)
43*aa6411e2SAugustin Cavalier #endif
44*aa6411e2SAugustin Cavalier
45*aa6411e2SAugustin Cavalier #ifdef SPRINTF_CHAR
46*aa6411e2SAugustin Cavalier # define SPRINTF(x) strlen(sprintf/**/x)
47*aa6411e2SAugustin Cavalier #else
48*aa6411e2SAugustin Cavalier # define SPRINTF(x) sprintf x
49*aa6411e2SAugustin Cavalier #endif
50*aa6411e2SAugustin Cavalier
51*aa6411e2SAugustin Cavalier static char * inet_net_ntop_ipv4(const u_char *src, int bits,
52*aa6411e2SAugustin Cavalier char *dst, size_t size);
53*aa6411e2SAugustin Cavalier static char * inet_net_ntop_ipv6(const u_char *src, int bits,
54*aa6411e2SAugustin Cavalier char *dst, size_t size);
55*aa6411e2SAugustin Cavalier
56*aa6411e2SAugustin Cavalier /*
57*aa6411e2SAugustin Cavalier * char *
58*aa6411e2SAugustin Cavalier * inet_net_ntop(af, src, bits, dst, size)
59*aa6411e2SAugustin Cavalier * convert network number from network to presentation format.
60*aa6411e2SAugustin Cavalier * generates CIDR style result always.
61*aa6411e2SAugustin Cavalier * return:
62*aa6411e2SAugustin Cavalier * pointer to dst, or NULL if an error occurred (check errno).
63*aa6411e2SAugustin Cavalier * author:
64*aa6411e2SAugustin Cavalier * Paul Vixie (ISC), July 1996
65*aa6411e2SAugustin Cavalier */
66*aa6411e2SAugustin Cavalier char *
inet_net_ntop(int af,const void * src,int bits,char * dst,size_t size)67*aa6411e2SAugustin Cavalier inet_net_ntop(int af, const void *src, int bits, char *dst, size_t size)
68*aa6411e2SAugustin Cavalier {
69*aa6411e2SAugustin Cavalier switch (af) {
70*aa6411e2SAugustin Cavalier case AF_INET:
71*aa6411e2SAugustin Cavalier return (inet_net_ntop_ipv4(src, bits, dst, size));
72*aa6411e2SAugustin Cavalier case AF_INET6:
73*aa6411e2SAugustin Cavalier return (inet_net_ntop_ipv6(src, bits, dst, size));
74*aa6411e2SAugustin Cavalier default:
75*aa6411e2SAugustin Cavalier errno = EAFNOSUPPORT;
76*aa6411e2SAugustin Cavalier return (NULL);
77*aa6411e2SAugustin Cavalier }
78*aa6411e2SAugustin Cavalier }
79*aa6411e2SAugustin Cavalier
80*aa6411e2SAugustin Cavalier /*
81*aa6411e2SAugustin Cavalier * static char *
82*aa6411e2SAugustin Cavalier * inet_net_ntop_ipv4(src, bits, dst, size)
83*aa6411e2SAugustin Cavalier * convert IPv4 network number from network to presentation format.
84*aa6411e2SAugustin Cavalier * generates CIDR style result always.
85*aa6411e2SAugustin Cavalier * return:
86*aa6411e2SAugustin Cavalier * pointer to dst, or NULL if an error occurred (check errno).
87*aa6411e2SAugustin Cavalier * note:
88*aa6411e2SAugustin Cavalier * network byte order assumed. this means 192.5.5.240/28 has
89*aa6411e2SAugustin Cavalier * 0b11110000 in its fourth octet.
90*aa6411e2SAugustin Cavalier * author:
91*aa6411e2SAugustin Cavalier * Paul Vixie (ISC), July 1996
92*aa6411e2SAugustin Cavalier */
93*aa6411e2SAugustin Cavalier static char *
inet_net_ntop_ipv4(const u_char * src,int bits,char * dst,size_t size)94*aa6411e2SAugustin Cavalier inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size)
95*aa6411e2SAugustin Cavalier {
96*aa6411e2SAugustin Cavalier char *odst = dst;
97*aa6411e2SAugustin Cavalier char *t;
98*aa6411e2SAugustin Cavalier u_int m;
99*aa6411e2SAugustin Cavalier int b;
100*aa6411e2SAugustin Cavalier
101*aa6411e2SAugustin Cavalier if (bits < 0 || bits > 32) {
102*aa6411e2SAugustin Cavalier errno = EINVAL;
103*aa6411e2SAugustin Cavalier return (NULL);
104*aa6411e2SAugustin Cavalier }
105*aa6411e2SAugustin Cavalier
106*aa6411e2SAugustin Cavalier if (bits == 0) {
107*aa6411e2SAugustin Cavalier if (size < sizeof "0")
108*aa6411e2SAugustin Cavalier goto emsgsize;
109*aa6411e2SAugustin Cavalier *dst++ = '0';
110*aa6411e2SAugustin Cavalier size--;
111*aa6411e2SAugustin Cavalier *dst = '\0';
112*aa6411e2SAugustin Cavalier }
113*aa6411e2SAugustin Cavalier
114*aa6411e2SAugustin Cavalier /* Format whole octets. */
115*aa6411e2SAugustin Cavalier for (b = bits / 8; b > 0; b--) {
116*aa6411e2SAugustin Cavalier if (size <= sizeof "255.")
117*aa6411e2SAugustin Cavalier goto emsgsize;
118*aa6411e2SAugustin Cavalier t = dst;
119*aa6411e2SAugustin Cavalier dst += SPRINTF((dst, "%u", *src++));
120*aa6411e2SAugustin Cavalier if (b > 1) {
121*aa6411e2SAugustin Cavalier *dst++ = '.';
122*aa6411e2SAugustin Cavalier *dst = '\0';
123*aa6411e2SAugustin Cavalier }
124*aa6411e2SAugustin Cavalier size -= (size_t)(dst - t);
125*aa6411e2SAugustin Cavalier }
126*aa6411e2SAugustin Cavalier
127*aa6411e2SAugustin Cavalier /* Format partial octet. */
128*aa6411e2SAugustin Cavalier b = bits % 8;
129*aa6411e2SAugustin Cavalier if (b > 0) {
130*aa6411e2SAugustin Cavalier if (size <= sizeof ".255")
131*aa6411e2SAugustin Cavalier goto emsgsize;
132*aa6411e2SAugustin Cavalier t = dst;
133*aa6411e2SAugustin Cavalier if (dst != odst)
134*aa6411e2SAugustin Cavalier *dst++ = '.';
135*aa6411e2SAugustin Cavalier m = ((1 << b) - 1) << (8 - b);
136*aa6411e2SAugustin Cavalier dst += SPRINTF((dst, "%u", *src & m));
137*aa6411e2SAugustin Cavalier size -= (size_t)(dst - t);
138*aa6411e2SAugustin Cavalier }
139*aa6411e2SAugustin Cavalier
140*aa6411e2SAugustin Cavalier /* Format CIDR /width. */
141*aa6411e2SAugustin Cavalier if (size <= sizeof "/32")
142*aa6411e2SAugustin Cavalier goto emsgsize;
143*aa6411e2SAugustin Cavalier dst += SPRINTF((dst, "/%u", bits));
144*aa6411e2SAugustin Cavalier return (odst);
145*aa6411e2SAugustin Cavalier
146*aa6411e2SAugustin Cavalier emsgsize:
147*aa6411e2SAugustin Cavalier errno = EMSGSIZE;
148*aa6411e2SAugustin Cavalier return (NULL);
149*aa6411e2SAugustin Cavalier }
150*aa6411e2SAugustin Cavalier
151*aa6411e2SAugustin Cavalier /*
152*aa6411e2SAugustin Cavalier * static char *
153*aa6411e2SAugustin Cavalier * inet_net_ntop_ipv6(src, bits, fakebits, dst, size)
154*aa6411e2SAugustin Cavalier * convert IPv6 network number from network to presentation format.
155*aa6411e2SAugustin Cavalier * generates CIDR style result always. Picks the shortest representation
156*aa6411e2SAugustin Cavalier * unless the IP is really IPv4.
157*aa6411e2SAugustin Cavalier * always prints specified number of bits (bits).
158*aa6411e2SAugustin Cavalier * return:
159*aa6411e2SAugustin Cavalier * pointer to dst, or NULL if an error occurred (check errno).
160*aa6411e2SAugustin Cavalier * note:
161*aa6411e2SAugustin Cavalier * network byte order assumed. this means 192.5.5.240/28 has
162*aa6411e2SAugustin Cavalier * 0x11110000 in its fourth octet.
163*aa6411e2SAugustin Cavalier * author:
164*aa6411e2SAugustin Cavalier * Vadim Kogan (UCB), June 2001
165*aa6411e2SAugustin Cavalier * Original version (IPv4) by Paul Vixie (ISC), July 1996
166*aa6411e2SAugustin Cavalier */
167*aa6411e2SAugustin Cavalier
168*aa6411e2SAugustin Cavalier static char *
inet_net_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)169*aa6411e2SAugustin Cavalier inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size)
170*aa6411e2SAugustin Cavalier {
171*aa6411e2SAugustin Cavalier u_int m;
172*aa6411e2SAugustin Cavalier int b;
173*aa6411e2SAugustin Cavalier size_t p;
174*aa6411e2SAugustin Cavalier size_t zero_s, zero_l, tmp_zero_s, tmp_zero_l;
175*aa6411e2SAugustin Cavalier size_t i;
176*aa6411e2SAugustin Cavalier int is_ipv4 = 0;
177*aa6411e2SAugustin Cavalier unsigned char inbuf[16];
178*aa6411e2SAugustin Cavalier char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")];
179*aa6411e2SAugustin Cavalier char *cp;
180*aa6411e2SAugustin Cavalier size_t words;
181*aa6411e2SAugustin Cavalier u_char *s;
182*aa6411e2SAugustin Cavalier
183*aa6411e2SAugustin Cavalier if (bits < 0 || bits > 128) {
184*aa6411e2SAugustin Cavalier errno = EINVAL;
185*aa6411e2SAugustin Cavalier return (NULL);
186*aa6411e2SAugustin Cavalier }
187*aa6411e2SAugustin Cavalier
188*aa6411e2SAugustin Cavalier cp = outbuf;
189*aa6411e2SAugustin Cavalier
190*aa6411e2SAugustin Cavalier if (bits == 0) {
191*aa6411e2SAugustin Cavalier *cp++ = ':';
192*aa6411e2SAugustin Cavalier *cp++ = ':';
193*aa6411e2SAugustin Cavalier *cp = '\0';
194*aa6411e2SAugustin Cavalier } else {
195*aa6411e2SAugustin Cavalier /* Copy src to private buffer. Zero host part. */
196*aa6411e2SAugustin Cavalier p = (bits + 7) / 8;
197*aa6411e2SAugustin Cavalier memcpy(inbuf, src, p);
198*aa6411e2SAugustin Cavalier memset(inbuf + p, 0, 16 - p);
199*aa6411e2SAugustin Cavalier b = bits % 8;
200*aa6411e2SAugustin Cavalier if (b != 0) {
201*aa6411e2SAugustin Cavalier m = ~0u << (8 - b);
202*aa6411e2SAugustin Cavalier inbuf[p-1] &= m;
203*aa6411e2SAugustin Cavalier }
204*aa6411e2SAugustin Cavalier
205*aa6411e2SAugustin Cavalier s = inbuf;
206*aa6411e2SAugustin Cavalier
207*aa6411e2SAugustin Cavalier /* how many words need to be displayed in output */
208*aa6411e2SAugustin Cavalier words = (bits + 15) / 16;
209*aa6411e2SAugustin Cavalier if (words == 1)
210*aa6411e2SAugustin Cavalier words = 2;
211*aa6411e2SAugustin Cavalier
212*aa6411e2SAugustin Cavalier /* Find the longest substring of zero's */
213*aa6411e2SAugustin Cavalier zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0;
214*aa6411e2SAugustin Cavalier for (i = 0; i < (words * 2); i += 2) {
215*aa6411e2SAugustin Cavalier if ((s[i] | s[i+1]) == 0) {
216*aa6411e2SAugustin Cavalier if (tmp_zero_l == 0)
217*aa6411e2SAugustin Cavalier tmp_zero_s = i / 2;
218*aa6411e2SAugustin Cavalier tmp_zero_l++;
219*aa6411e2SAugustin Cavalier } else {
220*aa6411e2SAugustin Cavalier if (tmp_zero_l && zero_l < tmp_zero_l) {
221*aa6411e2SAugustin Cavalier zero_s = tmp_zero_s;
222*aa6411e2SAugustin Cavalier zero_l = tmp_zero_l;
223*aa6411e2SAugustin Cavalier tmp_zero_l = 0;
224*aa6411e2SAugustin Cavalier }
225*aa6411e2SAugustin Cavalier }
226*aa6411e2SAugustin Cavalier }
227*aa6411e2SAugustin Cavalier
228*aa6411e2SAugustin Cavalier if (tmp_zero_l && zero_l < tmp_zero_l) {
229*aa6411e2SAugustin Cavalier zero_s = tmp_zero_s;
230*aa6411e2SAugustin Cavalier zero_l = tmp_zero_l;
231*aa6411e2SAugustin Cavalier }
232*aa6411e2SAugustin Cavalier
233*aa6411e2SAugustin Cavalier if (zero_l != words && zero_s == 0 && ((zero_l == 6) ||
234*aa6411e2SAugustin Cavalier ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) ||
235*aa6411e2SAugustin Cavalier ((zero_l == 7 && s[14] != 0 && s[15] != 1)))))
236*aa6411e2SAugustin Cavalier is_ipv4 = 1;
237*aa6411e2SAugustin Cavalier
238*aa6411e2SAugustin Cavalier /* Format whole words. */
239*aa6411e2SAugustin Cavalier for (p = 0; p < words; p++) {
240*aa6411e2SAugustin Cavalier if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) {
241*aa6411e2SAugustin Cavalier /* Time to skip some zeros */
242*aa6411e2SAugustin Cavalier if (p == zero_s)
243*aa6411e2SAugustin Cavalier *cp++ = ':';
244*aa6411e2SAugustin Cavalier if (p == words - 1)
245*aa6411e2SAugustin Cavalier *cp++ = ':';
246*aa6411e2SAugustin Cavalier s++;
247*aa6411e2SAugustin Cavalier s++;
248*aa6411e2SAugustin Cavalier continue;
249*aa6411e2SAugustin Cavalier }
250*aa6411e2SAugustin Cavalier
251*aa6411e2SAugustin Cavalier if (is_ipv4 && p > 5 ) {
252*aa6411e2SAugustin Cavalier *cp++ = (p == 6) ? ':' : '.';
253*aa6411e2SAugustin Cavalier cp += SPRINTF((cp, "%u", *s++));
254*aa6411e2SAugustin Cavalier /* we can potentially drop the last octet */
255*aa6411e2SAugustin Cavalier if (p != 7 || bits > 120) {
256*aa6411e2SAugustin Cavalier *cp++ = '.';
257*aa6411e2SAugustin Cavalier cp += SPRINTF((cp, "%u", *s++));
258*aa6411e2SAugustin Cavalier }
259*aa6411e2SAugustin Cavalier } else {
260*aa6411e2SAugustin Cavalier if (cp != outbuf)
261*aa6411e2SAugustin Cavalier *cp++ = ':';
262*aa6411e2SAugustin Cavalier cp += SPRINTF((cp, "%x", *s * 256 + s[1]));
263*aa6411e2SAugustin Cavalier s += 2;
264*aa6411e2SAugustin Cavalier }
265*aa6411e2SAugustin Cavalier }
266*aa6411e2SAugustin Cavalier }
267*aa6411e2SAugustin Cavalier /* Format CIDR /width. */
268*aa6411e2SAugustin Cavalier (void)SPRINTF((cp, "/%u", bits));
269*aa6411e2SAugustin Cavalier if (strlen(outbuf) + 1 > size)
270*aa6411e2SAugustin Cavalier goto emsgsize;
271*aa6411e2SAugustin Cavalier strcpy(dst, outbuf);
272*aa6411e2SAugustin Cavalier
273*aa6411e2SAugustin Cavalier return (dst);
274*aa6411e2SAugustin Cavalier
275*aa6411e2SAugustin Cavalier emsgsize:
276*aa6411e2SAugustin Cavalier errno = EMSGSIZE;
277*aa6411e2SAugustin Cavalier return (NULL);
278*aa6411e2SAugustin Cavalier }
279*aa6411e2SAugustin Cavalier
280*aa6411e2SAugustin Cavalier #undef inet_net_ntop
281*aa6411e2SAugustin Cavalier #pragma weak inet_net_ntop = __inet_net_ntop
282