1132451Sroberto/* 2132451Sroberto * Copyright (C) 1996-2001 Internet Software Consortium. 3132451Sroberto * 4132451Sroberto * Permission to use, copy, modify, and distribute this software for any 5132451Sroberto * purpose with or without fee is hereby granted, provided that the above 6132451Sroberto * copyright notice and this permission notice appear in all copies. 7132451Sroberto * 8132451Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM 9132451Sroberto * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 10132451Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL 11132451Sroberto * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, 12132451Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING 13132451Sroberto * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, 14132451Sroberto * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 15132451Sroberto * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16132451Sroberto */ 17132451Sroberto 18132451Sroberto#if defined(LIBC_SCCS) && !defined(lint) 19132451Srobertostatic char rcsid[] = 20132451Sroberto "$Id: inet_ntop.c,v 1.13 2001/11/27 01:56:00 gson Exp $"; 21132451Sroberto#endif /* LIBC_SCCS and not lint */ 22132451Sroberto 23132451Sroberto#include <config.h> 24132451Sroberto 25132451Sroberto#include <errno.h> 26132451Sroberto#include <stdio.h> 27132451Sroberto#include <string.h> 28132451Sroberto 29132451Sroberto#include <isc/net.h> 30132451Sroberto 31132451Sroberto#include "ntp_sprintf.h" 32132451Sroberto 33132451Sroberto#define NS_INT16SZ 2 34132451Sroberto#define NS_IN6ADDRSZ 16 35132451Sroberto 36132451Sroberto/* 37132451Sroberto * WARNING: Don't even consider trying to compile this on a system where 38132451Sroberto * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 39132451Sroberto */ 40132451Sroberto 41132451Srobertostatic const char *inet_ntop4(const unsigned char *src, char *dst, 42132451Sroberto size_t size); 43132451Sroberto 44132451Sroberto#ifdef AF_INET6 45132451Srobertostatic const char *inet_ntop6(const unsigned char *src, char *dst, 46132451Sroberto size_t size); 47132451Sroberto#endif 48132451Sroberto 49132451Sroberto/* char * 50132451Sroberto * isc_net_ntop(af, src, dst, size) 51132451Sroberto * convert a network format address to presentation format. 52132451Sroberto * return: 53132451Sroberto * pointer to presentation format address (`dst'), or NULL (see errno). 54132451Sroberto * author: 55132451Sroberto * Paul Vixie, 1996. 56132451Sroberto */ 57132451Srobertoconst char * 58132451Srobertoisc_net_ntop(int af, const void *src, char *dst, size_t size) 59132451Sroberto{ 60132451Sroberto switch (af) { 61132451Sroberto case AF_INET: 62132451Sroberto return (inet_ntop4(src, dst, size)); 63132451Sroberto#ifdef AF_INET6 64132451Sroberto case AF_INET6: 65132451Sroberto return (inet_ntop6(src, dst, size)); 66132451Sroberto#endif 67132451Sroberto default: 68132451Sroberto errno = EAFNOSUPPORT; 69132451Sroberto return (NULL); 70132451Sroberto } 71132451Sroberto /* NOTREACHED */ 72132451Sroberto} 73132451Sroberto 74132451Sroberto/* const char * 75132451Sroberto * inet_ntop4(src, dst, size) 76132451Sroberto * format an IPv4 address 77132451Sroberto * return: 78132451Sroberto * `dst' (as a const) 79132451Sroberto * notes: 80132451Sroberto * (1) uses no statics 81132451Sroberto * (2) takes a unsigned char* not an in_addr as input 82132451Sroberto * author: 83132451Sroberto * Paul Vixie, 1996. 84132451Sroberto */ 85132451Srobertostatic const char * 86132451Srobertoinet_ntop4(const unsigned char *src, char *dst, size_t size) 87132451Sroberto{ 88132451Sroberto static const char *fmt = "%u.%u.%u.%u"; 89132451Sroberto char tmp[sizeof("255.255.255.255")]; 90132451Sroberto 91132451Sroberto if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) 92132451Sroberto { 93132451Sroberto errno = ENOSPC; 94132451Sroberto return (NULL); 95132451Sroberto } 96132451Sroberto strcpy(dst, tmp); 97132451Sroberto 98132451Sroberto return (dst); 99132451Sroberto} 100132451Sroberto 101132451Sroberto/* const char * 102132451Sroberto * isc_inet_ntop6(src, dst, size) 103132451Sroberto * convert IPv6 binary address into presentation (printable) format 104132451Sroberto * author: 105132451Sroberto * Paul Vixie, 1996. 106132451Sroberto */ 107132451Sroberto#ifdef AF_INET6 108132451Srobertostatic const char * 109132451Srobertoinet_ntop6(const unsigned char *src, char *dst, size_t size) 110132451Sroberto{ 111132451Sroberto /* 112132451Sroberto * Note that int32_t and int16_t need only be "at least" large enough 113132451Sroberto * to contain a value of the specified size. On some systems, like 114132451Sroberto * Crays, there is no such thing as an integer variable with 16 bits. 115132451Sroberto * Keep this in mind if you think this function should have been coded 116132451Sroberto * to use pointer overlays. All the world's not a VAX. 117132451Sroberto */ 118132451Sroberto char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")], *tp; 119132451Sroberto struct { int base, len; } best, cur; 120132451Sroberto unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; 121132451Sroberto int i; 122132451Sroberto 123132451Sroberto /* 124132451Sroberto * Preprocess: 125132451Sroberto * Copy the input (bytewise) array into a wordwise array. 126132451Sroberto * Find the longest run of 0x00's in src[] for :: shorthanding. 127132451Sroberto */ 128132451Sroberto memset(words, '\0', sizeof(words)); 129132451Sroberto for (i = 0; i < NS_IN6ADDRSZ; i++) 130132451Sroberto words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 131132451Sroberto best.base = -1; 132132451Sroberto best.len = 0; 133132451Sroberto cur.base = -1; 134132451Sroberto cur.len = 0; 135132451Sroberto for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { 136132451Sroberto if (words[i] == 0) { 137132451Sroberto if (cur.base == -1) 138132451Sroberto cur.base = i, cur.len = 1; 139132451Sroberto else 140132451Sroberto cur.len++; 141132451Sroberto } else { 142132451Sroberto if (cur.base != -1) { 143132451Sroberto if (best.base == -1 || cur.len > best.len) 144132451Sroberto best = cur; 145132451Sroberto cur.base = -1; 146132451Sroberto } 147132451Sroberto } 148132451Sroberto } 149132451Sroberto if (cur.base != -1) { 150132451Sroberto if (best.base == -1 || cur.len > best.len) 151132451Sroberto best = cur; 152132451Sroberto } 153132451Sroberto if (best.base != -1 && best.len < 2) 154132451Sroberto best.base = -1; 155132451Sroberto 156132451Sroberto /* 157132451Sroberto * Format the result. 158132451Sroberto */ 159132451Sroberto tp = tmp; 160132451Sroberto for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { 161132451Sroberto /* Are we inside the best run of 0x00's? */ 162132451Sroberto if (best.base != -1 && i >= best.base && 163132451Sroberto i < (best.base + best.len)) { 164132451Sroberto if (i == best.base) 165132451Sroberto *tp++ = ':'; 166132451Sroberto continue; 167132451Sroberto } 168132451Sroberto /* Are we following an initial run of 0x00s or any real hex? */ 169132451Sroberto if (i != 0) 170132451Sroberto *tp++ = ':'; 171132451Sroberto /* Is this address an encapsulated IPv4? */ 172132451Sroberto if (i == 6 && best.base == 0 && 173132451Sroberto (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { 174132451Sroberto if (!inet_ntop4(src+12, tp, 175132451Sroberto sizeof(tmp) - (tp - tmp))) 176132451Sroberto return (NULL); 177132451Sroberto tp += strlen(tp); 178132451Sroberto break; 179132451Sroberto } 180132451Sroberto tp += SPRINTF((tp, "%x", words[i])); 181132451Sroberto } 182132451Sroberto /* Was it a trailing run of 0x00's? */ 183132451Sroberto if (best.base != -1 && (best.base + best.len) == 184132451Sroberto (NS_IN6ADDRSZ / NS_INT16SZ)) 185132451Sroberto *tp++ = ':'; 186132451Sroberto *tp++ = '\0'; 187132451Sroberto 188132451Sroberto /* 189132451Sroberto * Check for overflow, copy, and we're done. 190132451Sroberto */ 191132451Sroberto if ((size_t)(tp - tmp) > size) { 192132451Sroberto errno = ENOSPC; 193132451Sroberto return (NULL); 194132451Sroberto } 195132451Sroberto strcpy(dst, tmp); 196132451Sroberto return (dst); 197132451Sroberto} 198132451Sroberto#endif /* AF_INET6 */ 199