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