1/* Copyright (c) 1996 by Internet Software Consortium. 2 * 3 * Permission to use, copy, modify, and distribute this software for any 4 * purpose with or without fee is hereby granted, provided that the above 5 * copyright notice and this permission notice appear in all copies. 6 * 7 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 8 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 9 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 10 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 11 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 12 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 13 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 14 * SOFTWARE. 15 */ 16 17#include "apr_private.h" 18#include "apr_arch_networkio.h" 19#include "apr_strings.h" 20 21#if APR_HAVE_SYS_TYPES_H 22#include <sys/types.h> 23#endif 24#if APR_HAVE_SYS_SOCKET_H 25#include <sys/socket.h> 26#endif 27#if APR_HAVE_NETINET_IN_H 28#include <netinet/in.h> 29#endif 30#if APR_HAVE_ARPA_INET_H 31#include <arpa/inet.h> 32#endif 33#include <string.h> 34#if APR_HAVE_ERRNO_H 35#include <errno.h> 36#endif 37#include <stdio.h> 38 39#ifndef IN6ADDRSZ 40#define IN6ADDRSZ 16 41#endif 42 43#ifndef INT16SZ 44#define INT16SZ sizeof(apr_int16_t) 45#endif 46 47#ifndef __P 48#define __P(x) x 49#endif 50 51#if !defined(EAFNOSUPPORT) && defined(WSAEAFNOSUPPORT) 52#define EAFNOSUPPORT WSAEAFNOSUPPORT 53#endif 54 55/* 56 * WARNING: Don't even consider trying to compile this on a system where 57 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 58 */ 59 60static const char *inet_ntop4 __P((const unsigned char *src, char *dst, apr_size_t size)); 61#if APR_HAVE_IPV6 62static const char *inet_ntop6 __P((const unsigned char *src, char *dst, apr_size_t size)); 63#endif 64 65/* char * 66 * inet_ntop(af, src, dst, size) 67 * convert a network format address to presentation format. 68 * return: 69 * pointer to presentation format address (`dst'), or NULL (see errno). 70 * author: 71 * Paul Vixie, 1996. 72 */ 73const char * 74apr_inet_ntop(int af, const void *src, char *dst, apr_size_t size) 75{ 76 switch (af) { 77 case AF_INET: 78 return (inet_ntop4(src, dst, size)); 79#if APR_HAVE_IPV6 80 case AF_INET6: 81 return (inet_ntop6(src, dst, size)); 82#endif 83 default: 84 errno = EAFNOSUPPORT; 85 return (NULL); 86 } 87 /* NOTREACHED */ 88} 89 90/* const char * 91 * inet_ntop4(src, dst, size) 92 * format an IPv4 address, more or less like inet_ntoa() 93 * return: 94 * `dst' (as a const) 95 * notes: 96 * (1) uses no statics 97 * (2) takes a u_char* not an in_addr as input 98 * author: 99 * Paul Vixie, 1996. 100 */ 101static const char * 102inet_ntop4(const unsigned char *src, char *dst, apr_size_t size) 103{ 104 const apr_size_t MIN_SIZE = 16; /* space for 255.255.255.255\0 */ 105 int n = 0; 106 char *next = dst; 107 108 if (size < MIN_SIZE) { 109 errno = ENOSPC; 110 return NULL; 111 } 112 do { 113 unsigned char u = *src++; 114 if (u > 99) { 115 *next++ = '0' + u/100; 116 u %= 100; 117 *next++ = '0' + u/10; 118 u %= 10; 119 } 120 else if (u > 9) { 121 *next++ = '0' + u/10; 122 u %= 10; 123 } 124 *next++ = '0' + u; 125 *next++ = '.'; 126 n++; 127 } while (n < 4); 128 *--next = 0; 129 return dst; 130} 131 132#if APR_HAVE_IPV6 133/* const char * 134 * inet_ntop6(src, dst, size) 135 * convert IPv6 binary address into presentation (printable) format 136 * author: 137 * Paul Vixie, 1996. 138 */ 139static const char * 140inet_ntop6(const unsigned char *src, char *dst, apr_size_t size) 141{ 142 /* 143 * Note that int32_t and int16_t need only be "at least" large enough 144 * to contain a value of the specified size. On some systems, like 145 * Crays, there is no such thing as an integer variable with 16 bits. 146 * Keep this in mind if you think this function should have been coded 147 * to use pointer overlays. All the world's not a VAX. 148 */ 149 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; 150 struct { int base, len; } best = {-1, 0}, cur = {-1, 0}; 151 unsigned int words[IN6ADDRSZ / INT16SZ]; 152 int i; 153 const unsigned char *next_src, *src_end; 154 unsigned int *next_dest; 155 156 /* 157 * Preprocess: 158 * Copy the input (bytewise) array into a wordwise array. 159 * Find the longest run of 0x00's in src[] for :: shorthanding. 160 */ 161 next_src = src; 162 src_end = src + IN6ADDRSZ; 163 next_dest = words; 164 i = 0; 165 do { 166 unsigned int next_word = (unsigned int)*next_src++; 167 next_word <<= 8; 168 next_word |= (unsigned int)*next_src++; 169 *next_dest++ = next_word; 170 171 if (next_word == 0) { 172 if (cur.base == -1) { 173 cur.base = i; 174 cur.len = 1; 175 } 176 else { 177 cur.len++; 178 } 179 } else { 180 if (cur.base != -1) { 181 if (best.base == -1 || cur.len > best.len) { 182 best = cur; 183 } 184 cur.base = -1; 185 } 186 } 187 188 i++; 189 } while (next_src < src_end); 190 191 if (cur.base != -1) { 192 if (best.base == -1 || cur.len > best.len) { 193 best = cur; 194 } 195 } 196 if (best.base != -1 && best.len < 2) { 197 best.base = -1; 198 } 199 200 /* 201 * Format the result. 202 */ 203 tp = tmp; 204 for (i = 0; i < (IN6ADDRSZ / INT16SZ);) { 205 /* Are we inside the best run of 0x00's? */ 206 if (i == best.base) { 207 *tp++ = ':'; 208 i += best.len; 209 continue; 210 } 211 /* Are we following an initial run of 0x00s or any real hex? */ 212 if (i != 0) { 213 *tp++ = ':'; 214 } 215 /* Is this address an encapsulated IPv4? */ 216 if (i == 6 && best.base == 0 && 217 (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { 218 if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) { 219 return (NULL); 220 } 221 tp += strlen(tp); 222 break; 223 } 224 tp += apr_snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]); 225 i++; 226 } 227 /* Was it a trailing run of 0x00's? */ 228 if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { 229 *tp++ = ':'; 230 } 231 *tp++ = '\0'; 232 233 /* 234 * Check for overflow, copy, and we're done. 235 */ 236 if ((apr_size_t)(tp - tmp) > size) { 237 errno = ENOSPC; 238 return (NULL); 239 } 240 strcpy(dst, tmp); 241 return (dst); 242} 243#endif 244