1251875Speter/* Copyright (c) 1996 by Internet Software Consortium.
2251875Speter *
3251875Speter * Permission to use, copy, modify, and distribute this software for any
4251875Speter * purpose with or without fee is hereby granted, provided that the above
5251875Speter * copyright notice and this permission notice appear in all copies.
6251875Speter *
7251875Speter * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
8251875Speter * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
9251875Speter * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
10251875Speter * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
11251875Speter * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
12251875Speter * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
13251875Speter * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
14251875Speter * SOFTWARE.
15251875Speter */
16251875Speter
17251875Speter#include "apr_private.h"
18251875Speter#include "apr_arch_networkio.h"
19251875Speter#include "apr_strings.h"
20251875Speter
21251875Speter#if APR_HAVE_SYS_TYPES_H
22251875Speter#include <sys/types.h>
23251875Speter#endif
24251875Speter#if APR_HAVE_SYS_SOCKET_H
25251875Speter#include <sys/socket.h>
26251875Speter#endif
27251875Speter#if APR_HAVE_NETINET_IN_H
28251875Speter#include <netinet/in.h>
29251875Speter#endif
30251875Speter#if APR_HAVE_ARPA_INET_H
31251875Speter#include <arpa/inet.h>
32251875Speter#endif
33251875Speter#include <string.h>
34251875Speter#if APR_HAVE_ERRNO_H
35251875Speter#include <errno.h>
36251875Speter#endif
37251875Speter#include <stdio.h>
38251875Speter
39251875Speter#ifndef IN6ADDRSZ
40251875Speter#define IN6ADDRSZ   16
41251875Speter#endif
42251875Speter
43251875Speter#ifndef INT16SZ
44251875Speter#define INT16SZ sizeof(apr_int16_t)
45251875Speter#endif
46251875Speter
47251875Speter#ifndef __P
48251875Speter#define __P(x) x
49251875Speter#endif
50251875Speter
51251875Speter#if !defined(EAFNOSUPPORT) && defined(WSAEAFNOSUPPORT)
52251875Speter#define EAFNOSUPPORT WSAEAFNOSUPPORT
53251875Speter#endif
54251875Speter
55251875Speter/*
56251875Speter * WARNING: Don't even consider trying to compile this on a system where
57251875Speter * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
58251875Speter */
59251875Speter
60251875Speterstatic const char *inet_ntop4 __P((const unsigned char *src, char *dst, apr_size_t size));
61251875Speter#if APR_HAVE_IPV6
62251875Speterstatic const char *inet_ntop6 __P((const unsigned char *src, char *dst, apr_size_t size));
63251875Speter#endif
64251875Speter
65251875Speter/* char *
66251875Speter * inet_ntop(af, src, dst, size)
67251875Speter *	convert a network format address to presentation format.
68251875Speter * return:
69251875Speter *	pointer to presentation format address (`dst'), or NULL (see errno).
70251875Speter * author:
71251875Speter *	Paul Vixie, 1996.
72251875Speter */
73251875Speterconst char *
74251875Speterapr_inet_ntop(int af, const void *src, char *dst, apr_size_t size)
75251875Speter{
76251875Speter	switch (af) {
77251875Speter	case AF_INET:
78251875Speter		return (inet_ntop4(src, dst, size));
79251875Speter#if APR_HAVE_IPV6
80251875Speter	case AF_INET6:
81251875Speter		return (inet_ntop6(src, dst, size));
82251875Speter#endif
83251875Speter	default:
84251875Speter		errno = EAFNOSUPPORT;
85251875Speter		return (NULL);
86251875Speter	}
87251875Speter	/* NOTREACHED */
88251875Speter}
89251875Speter
90251875Speter/* const char *
91251875Speter * inet_ntop4(src, dst, size)
92251875Speter *	format an IPv4 address, more or less like inet_ntoa()
93251875Speter * return:
94251875Speter *	`dst' (as a const)
95251875Speter * notes:
96251875Speter *	(1) uses no statics
97251875Speter *	(2) takes a u_char* not an in_addr as input
98251875Speter * author:
99251875Speter *	Paul Vixie, 1996.
100251875Speter */
101251875Speterstatic const char *
102251875Speterinet_ntop4(const unsigned char *src, char *dst, apr_size_t size)
103251875Speter{
104251875Speter	const apr_size_t MIN_SIZE = 16; /* space for 255.255.255.255\0 */
105251875Speter	int n = 0;
106251875Speter	char *next = dst;
107251875Speter
108251875Speter	if (size < MIN_SIZE) {
109251875Speter	    errno = ENOSPC;
110251875Speter	    return NULL;
111251875Speter	}
112251875Speter	do {
113251875Speter	    unsigned char u = *src++;
114251875Speter	    if (u > 99) {
115251875Speter		*next++ = '0' + u/100;
116251875Speter		u %= 100;
117251875Speter		*next++ = '0' + u/10;
118251875Speter		u %= 10;
119251875Speter	    }
120251875Speter	    else if (u > 9) {
121251875Speter		*next++ = '0' + u/10;
122251875Speter		u %= 10;
123251875Speter	    }
124251875Speter	    *next++ = '0' + u;
125251875Speter	    *next++ = '.';
126251875Speter	    n++;
127251875Speter	} while (n < 4);
128251875Speter	*--next = 0;
129251875Speter	return dst;
130251875Speter}
131251875Speter
132251875Speter#if APR_HAVE_IPV6
133251875Speter/* const char *
134251875Speter * inet_ntop6(src, dst, size)
135251875Speter *	convert IPv6 binary address into presentation (printable) format
136251875Speter * author:
137251875Speter *	Paul Vixie, 1996.
138251875Speter */
139251875Speterstatic const char *
140251875Speterinet_ntop6(const unsigned char *src, char *dst, apr_size_t size)
141251875Speter{
142251875Speter    /*
143251875Speter     * Note that int32_t and int16_t need only be "at least" large enough
144251875Speter     * to contain a value of the specified size.  On some systems, like
145251875Speter     * Crays, there is no such thing as an integer variable with 16 bits.
146251875Speter     * Keep this in mind if you think this function should have been coded
147251875Speter     * to use pointer overlays.  All the world's not a VAX.
148251875Speter     */
149251875Speter    char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
150251875Speter    struct { int base, len; } best = {-1, 0}, cur = {-1, 0};
151251875Speter    unsigned int words[IN6ADDRSZ / INT16SZ];
152251875Speter    int i;
153251875Speter    const unsigned char *next_src, *src_end;
154251875Speter    unsigned int *next_dest;
155251875Speter
156251875Speter    /*
157251875Speter     * Preprocess:
158251875Speter     *	Copy the input (bytewise) array into a wordwise array.
159251875Speter     *	Find the longest run of 0x00's in src[] for :: shorthanding.
160251875Speter     */
161251875Speter    next_src = src;
162251875Speter    src_end = src + IN6ADDRSZ;
163251875Speter    next_dest = words;
164251875Speter    i = 0;
165251875Speter    do {
166251875Speter        unsigned int next_word = (unsigned int)*next_src++;
167251875Speter        next_word <<= 8;
168251875Speter        next_word |= (unsigned int)*next_src++;
169251875Speter        *next_dest++ = next_word;
170251875Speter
171251875Speter        if (next_word == 0) {
172251875Speter            if (cur.base == -1) {
173251875Speter                cur.base = i;
174251875Speter                cur.len = 1;
175251875Speter            }
176251875Speter            else {
177251875Speter                cur.len++;
178251875Speter            }
179251875Speter        } else {
180251875Speter            if (cur.base != -1) {
181251875Speter                if (best.base == -1 || cur.len > best.len) {
182251875Speter                    best = cur;
183251875Speter                }
184251875Speter                cur.base = -1;
185251875Speter            }
186251875Speter        }
187251875Speter
188251875Speter        i++;
189251875Speter    } while (next_src < src_end);
190251875Speter
191251875Speter    if (cur.base != -1) {
192251875Speter        if (best.base == -1 || cur.len > best.len) {
193251875Speter            best = cur;
194251875Speter        }
195251875Speter    }
196251875Speter    if (best.base != -1 && best.len < 2) {
197251875Speter        best.base = -1;
198251875Speter    }
199251875Speter
200251875Speter    /*
201251875Speter     * Format the result.
202251875Speter     */
203251875Speter    tp = tmp;
204251875Speter    for (i = 0; i < (IN6ADDRSZ / INT16SZ);) {
205251875Speter        /* Are we inside the best run of 0x00's? */
206251875Speter        if (i == best.base) {
207251875Speter            *tp++ = ':';
208251875Speter            i += best.len;
209251875Speter            continue;
210251875Speter        }
211251875Speter        /* Are we following an initial run of 0x00s or any real hex? */
212251875Speter        if (i != 0) {
213251875Speter            *tp++ = ':';
214251875Speter        }
215251875Speter        /* Is this address an encapsulated IPv4? */
216251875Speter        if (i == 6 && best.base == 0 &&
217251875Speter            (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
218251875Speter            if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) {
219251875Speter                return (NULL);
220251875Speter            }
221251875Speter            tp += strlen(tp);
222251875Speter            break;
223251875Speter        }
224251875Speter        tp += apr_snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]);
225251875Speter        i++;
226251875Speter    }
227251875Speter    /* Was it a trailing run of 0x00's? */
228251875Speter    if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) {
229251875Speter        *tp++ = ':';
230251875Speter    }
231251875Speter    *tp++ = '\0';
232251875Speter
233251875Speter    /*
234251875Speter     * Check for overflow, copy, and we're done.
235251875Speter     */
236251875Speter    if ((apr_size_t)(tp - tmp) > size) {
237251875Speter        errno = ENOSPC;
238251875Speter        return (NULL);
239251875Speter    }
240251875Speter    strcpy(dst, tmp);
241251875Speter    return (dst);
242251875Speter}
243251875Speter#endif
244