1ee65b806SJan Lentfer /*
2ee65b806SJan Lentfer * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
3ee65b806SJan Lentfer * Copyright (c) 1998,1999 by Internet Software Consortium.
4ee65b806SJan Lentfer *
5ee65b806SJan Lentfer * Permission to use, copy, modify, and distribute this software for any
6ee65b806SJan Lentfer * purpose with or without fee is hereby granted, provided that the above
7ee65b806SJan Lentfer * copyright notice and this permission notice appear in all copies.
8ee65b806SJan Lentfer *
9ee65b806SJan Lentfer * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
10ee65b806SJan Lentfer * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11ee65b806SJan Lentfer * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
12ee65b806SJan Lentfer * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13ee65b806SJan Lentfer * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14ee65b806SJan Lentfer * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
15ee65b806SJan Lentfer * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16*63373b25SSascha Wildner *
17*63373b25SSascha Wildner * $Id: inet_cidr_ntop.c,v 1.7 2006/10/11 02:18:18 marka Exp $
18ee65b806SJan Lentfer */
19ee65b806SJan Lentfer
20ee65b806SJan Lentfer #include "port_before.h"
21ee65b806SJan Lentfer
22ee65b806SJan Lentfer #include <sys/types.h>
23ee65b806SJan Lentfer #include <sys/socket.h>
24ee65b806SJan Lentfer #include <netinet/in.h>
25ee65b806SJan Lentfer #include <arpa/nameser.h>
26ee65b806SJan Lentfer #include <arpa/inet.h>
27ee65b806SJan Lentfer
28ee65b806SJan Lentfer #include <errno.h>
29ee65b806SJan Lentfer #include <stdio.h>
30ee65b806SJan Lentfer #include <string.h>
31ee65b806SJan Lentfer #include <stdlib.h>
32ee65b806SJan Lentfer
33ee65b806SJan Lentfer #include "port_after.h"
34ee65b806SJan Lentfer
35ee65b806SJan Lentfer static char *
36ee65b806SJan Lentfer inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size);
37ee65b806SJan Lentfer static char *
38ee65b806SJan Lentfer inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size);
39ee65b806SJan Lentfer
40ee65b806SJan Lentfer /*%
41ee65b806SJan Lentfer * char *
42ee65b806SJan Lentfer * inet_cidr_ntop(af, src, bits, dst, size)
43ee65b806SJan Lentfer * convert network address from network to presentation format.
44ee65b806SJan Lentfer * "src"'s size is determined from its "af".
45ee65b806SJan Lentfer * return:
46ee65b806SJan Lentfer * pointer to dst, or NULL if an error occurred (check errno).
47ee65b806SJan Lentfer * note:
48ee65b806SJan Lentfer * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
49ee65b806SJan Lentfer * as called for by inet_net_ntop() but it can be a host address with
50ee65b806SJan Lentfer * an included netmask.
51ee65b806SJan Lentfer * author:
52ee65b806SJan Lentfer * Paul Vixie (ISC), October 1998
53ee65b806SJan Lentfer */
54ee65b806SJan Lentfer char *
inet_cidr_ntop(int af,const void * src,int bits,char * dst,size_t size)55ee65b806SJan Lentfer inet_cidr_ntop(int af, const void *src, int bits, char *dst, size_t size) {
56ee65b806SJan Lentfer switch (af) {
57ee65b806SJan Lentfer case AF_INET:
58ee65b806SJan Lentfer return (inet_cidr_ntop_ipv4(src, bits, dst, size));
59ee65b806SJan Lentfer case AF_INET6:
60ee65b806SJan Lentfer return (inet_cidr_ntop_ipv6(src, bits, dst, size));
61ee65b806SJan Lentfer default:
62ee65b806SJan Lentfer errno = EAFNOSUPPORT;
63ee65b806SJan Lentfer return (NULL);
64ee65b806SJan Lentfer }
65ee65b806SJan Lentfer }
66ee65b806SJan Lentfer
67ee65b806SJan Lentfer static int
decoct(const u_char * src,int bytes,char * dst,size_t size)68ee65b806SJan Lentfer decoct(const u_char *src, int bytes, char *dst, size_t size) {
69ee65b806SJan Lentfer char *odst = dst;
70ee65b806SJan Lentfer char *t;
71ee65b806SJan Lentfer int b;
72ee65b806SJan Lentfer
73ee65b806SJan Lentfer for (b = 1; b <= bytes; b++) {
74ee65b806SJan Lentfer if (size < sizeof "255.")
75ee65b806SJan Lentfer return (0);
76ee65b806SJan Lentfer t = dst;
77*63373b25SSascha Wildner dst += sprintf(dst, "%u", *src++);
78ee65b806SJan Lentfer if (b != bytes) {
79ee65b806SJan Lentfer *dst++ = '.';
80ee65b806SJan Lentfer *dst = '\0';
81ee65b806SJan Lentfer }
82ee65b806SJan Lentfer size -= (size_t)(dst - t);
83ee65b806SJan Lentfer }
84ee65b806SJan Lentfer return (dst - odst);
85ee65b806SJan Lentfer }
86ee65b806SJan Lentfer
87ee65b806SJan Lentfer /*%
88ee65b806SJan Lentfer * static char *
89ee65b806SJan Lentfer * inet_cidr_ntop_ipv4(src, bits, dst, size)
90ee65b806SJan Lentfer * convert IPv4 network address from network to presentation format.
91ee65b806SJan Lentfer * "src"'s size is determined from its "af".
92ee65b806SJan Lentfer * return:
93ee65b806SJan Lentfer * pointer to dst, or NULL if an error occurred (check errno).
94ee65b806SJan Lentfer * note:
95ee65b806SJan Lentfer * network byte order assumed. this means 192.5.5.240/28 has
96ee65b806SJan Lentfer * 0b11110000 in its fourth octet.
97ee65b806SJan Lentfer * author:
98ee65b806SJan Lentfer * Paul Vixie (ISC), October 1998
99ee65b806SJan Lentfer */
100ee65b806SJan Lentfer static char *
inet_cidr_ntop_ipv4(const u_char * src,int bits,char * dst,size_t size)101ee65b806SJan Lentfer inet_cidr_ntop_ipv4(const u_char *src, int bits, char *dst, size_t size) {
102ee65b806SJan Lentfer char *odst = dst;
103ee65b806SJan Lentfer size_t len = 4;
104ee65b806SJan Lentfer size_t b;
105ee65b806SJan Lentfer size_t bytes;
106ee65b806SJan Lentfer
107ee65b806SJan Lentfer if ((bits < -1) || (bits > 32)) {
108ee65b806SJan Lentfer errno = EINVAL;
109ee65b806SJan Lentfer return (NULL);
110ee65b806SJan Lentfer }
111ee65b806SJan Lentfer
112ee65b806SJan Lentfer /* Find number of significant bytes in address. */
113ee65b806SJan Lentfer if (bits == -1)
114ee65b806SJan Lentfer len = 4;
115ee65b806SJan Lentfer else
116ee65b806SJan Lentfer for (len = 1, b = 1 ; b < 4U; b++)
117ee65b806SJan Lentfer if (*(src + b))
118ee65b806SJan Lentfer len = b + 1;
119ee65b806SJan Lentfer
120ee65b806SJan Lentfer /* Format whole octets plus nonzero trailing octets. */
121ee65b806SJan Lentfer bytes = (((bits <= 0) ? 1 : bits) + 7) / 8;
122ee65b806SJan Lentfer if (len > bytes)
123ee65b806SJan Lentfer bytes = len;
124ee65b806SJan Lentfer b = decoct(src, bytes, dst, size);
125ee65b806SJan Lentfer if (b == 0U)
126ee65b806SJan Lentfer goto emsgsize;
127ee65b806SJan Lentfer dst += b;
128ee65b806SJan Lentfer size -= b;
129ee65b806SJan Lentfer
130ee65b806SJan Lentfer if (bits != -1) {
131ee65b806SJan Lentfer /* Format CIDR /width. */
132ee65b806SJan Lentfer if (size < sizeof "/32")
133ee65b806SJan Lentfer goto emsgsize;
134*63373b25SSascha Wildner dst += sprintf(dst, "/%u", bits);
135ee65b806SJan Lentfer }
136ee65b806SJan Lentfer
137ee65b806SJan Lentfer return (odst);
138ee65b806SJan Lentfer
139ee65b806SJan Lentfer emsgsize:
140ee65b806SJan Lentfer errno = EMSGSIZE;
141ee65b806SJan Lentfer return (NULL);
142ee65b806SJan Lentfer }
143ee65b806SJan Lentfer
144ee65b806SJan Lentfer static char *
inet_cidr_ntop_ipv6(const u_char * src,int bits,char * dst,size_t size)145ee65b806SJan Lentfer inet_cidr_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) {
146ee65b806SJan Lentfer /*
147ee65b806SJan Lentfer * Note that int32_t and int16_t need only be "at least" large enough
148ee65b806SJan Lentfer * to contain a value of the specified size. On some systems, like
149ee65b806SJan Lentfer * Crays, there is no such thing as an integer variable with 16 bits.
150ee65b806SJan Lentfer * Keep this in mind if you think this function should have been coded
151ee65b806SJan Lentfer * to use pointer overlays. All the world's not a VAX.
152ee65b806SJan Lentfer */
153ee65b806SJan Lentfer char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255/128"];
154ee65b806SJan Lentfer char *tp;
155ee65b806SJan Lentfer struct { int base, len; } best, cur;
156ee65b806SJan Lentfer u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
157ee65b806SJan Lentfer int i;
158ee65b806SJan Lentfer
159ee65b806SJan Lentfer if ((bits < -1) || (bits > 128)) {
160ee65b806SJan Lentfer errno = EINVAL;
161ee65b806SJan Lentfer return (NULL);
162ee65b806SJan Lentfer }
163ee65b806SJan Lentfer
164ee65b806SJan Lentfer /*
165ee65b806SJan Lentfer * Preprocess:
166ee65b806SJan Lentfer * Copy the input (bytewise) array into a wordwise array.
167ee65b806SJan Lentfer * Find the longest run of 0x00's in src[] for :: shorthanding.
168ee65b806SJan Lentfer */
169ee65b806SJan Lentfer memset(words, '\0', sizeof words);
170ee65b806SJan Lentfer for (i = 0; i < NS_IN6ADDRSZ; i++)
171ee65b806SJan Lentfer words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3));
172ee65b806SJan Lentfer best.base = -1;
173ee65b806SJan Lentfer best.len = 0;
174ee65b806SJan Lentfer cur.base = -1;
175ee65b806SJan Lentfer cur.len = 0;
176ee65b806SJan Lentfer for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
177ee65b806SJan Lentfer if (words[i] == 0) {
178ee65b806SJan Lentfer if (cur.base == -1)
179ee65b806SJan Lentfer cur.base = i, cur.len = 1;
180ee65b806SJan Lentfer else
181ee65b806SJan Lentfer cur.len++;
182ee65b806SJan Lentfer } else {
183ee65b806SJan Lentfer if (cur.base != -1) {
184ee65b806SJan Lentfer if (best.base == -1 || cur.len > best.len)
185ee65b806SJan Lentfer best = cur;
186ee65b806SJan Lentfer cur.base = -1;
187ee65b806SJan Lentfer }
188ee65b806SJan Lentfer }
189ee65b806SJan Lentfer }
190ee65b806SJan Lentfer if (cur.base != -1) {
191ee65b806SJan Lentfer if (best.base == -1 || cur.len > best.len)
192ee65b806SJan Lentfer best = cur;
193ee65b806SJan Lentfer }
194ee65b806SJan Lentfer if (best.base != -1 && best.len < 2)
195ee65b806SJan Lentfer best.base = -1;
196ee65b806SJan Lentfer
197ee65b806SJan Lentfer /*
198ee65b806SJan Lentfer * Format the result.
199ee65b806SJan Lentfer */
200ee65b806SJan Lentfer tp = tmp;
201ee65b806SJan Lentfer for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
202ee65b806SJan Lentfer /* Are we inside the best run of 0x00's? */
203ee65b806SJan Lentfer if (best.base != -1 && i >= best.base &&
204ee65b806SJan Lentfer i < (best.base + best.len)) {
205ee65b806SJan Lentfer if (i == best.base)
206ee65b806SJan Lentfer *tp++ = ':';
207ee65b806SJan Lentfer continue;
208ee65b806SJan Lentfer }
209ee65b806SJan Lentfer /* Are we following an initial run of 0x00s or any real hex? */
210ee65b806SJan Lentfer if (i != 0)
211ee65b806SJan Lentfer *tp++ = ':';
212ee65b806SJan Lentfer /* Is this address an encapsulated IPv4? */
213ee65b806SJan Lentfer if (i == 6 && best.base == 0 && (best.len == 6 ||
214ee65b806SJan Lentfer (best.len == 7 && words[7] != 0x0001) ||
215ee65b806SJan Lentfer (best.len == 5 && words[5] == 0xffff))) {
216ee65b806SJan Lentfer int n;
217ee65b806SJan Lentfer
218ee65b806SJan Lentfer if (src[15] || bits == -1 || bits > 120)
219ee65b806SJan Lentfer n = 4;
220ee65b806SJan Lentfer else if (src[14] || bits > 112)
221ee65b806SJan Lentfer n = 3;
222ee65b806SJan Lentfer else
223ee65b806SJan Lentfer n = 2;
224ee65b806SJan Lentfer n = decoct(src+12, n, tp, sizeof tmp - (tp - tmp));
225ee65b806SJan Lentfer if (n == 0) {
226ee65b806SJan Lentfer errno = EMSGSIZE;
227ee65b806SJan Lentfer return (NULL);
228ee65b806SJan Lentfer }
229ee65b806SJan Lentfer tp += strlen(tp);
230ee65b806SJan Lentfer break;
231ee65b806SJan Lentfer }
232*63373b25SSascha Wildner tp += sprintf(tp, "%x", words[i]);
233ee65b806SJan Lentfer }
234ee65b806SJan Lentfer
235ee65b806SJan Lentfer /* Was it a trailing run of 0x00's? */
236ee65b806SJan Lentfer if (best.base != -1 && (best.base + best.len) ==
237ee65b806SJan Lentfer (NS_IN6ADDRSZ / NS_INT16SZ))
238ee65b806SJan Lentfer *tp++ = ':';
239ee65b806SJan Lentfer *tp = '\0';
240ee65b806SJan Lentfer
241ee65b806SJan Lentfer if (bits != -1)
242*63373b25SSascha Wildner tp += sprintf(tp, "/%u", bits);
243ee65b806SJan Lentfer
244ee65b806SJan Lentfer /*
245ee65b806SJan Lentfer * Check for overflow, copy, and we're done.
246ee65b806SJan Lentfer */
247ee65b806SJan Lentfer if ((size_t)(tp - tmp) > size) {
248ee65b806SJan Lentfer errno = EMSGSIZE;
249ee65b806SJan Lentfer return (NULL);
250ee65b806SJan Lentfer }
251ee65b806SJan Lentfer strcpy(dst, tmp);
252ee65b806SJan Lentfer return (dst);
253ee65b806SJan Lentfer }
254