14b17dab0SDag-Erling Smørgrav /* $OpenBSD: inet_ntop.c,v 1.5 2002/08/23 16:27:31 itojun Exp $ */ 283d2307dSDag-Erling Smørgrav 383d2307dSDag-Erling Smørgrav /* Copyright (c) 1996 by Internet Software Consortium. 483d2307dSDag-Erling Smørgrav * 583d2307dSDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 683d2307dSDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 783d2307dSDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 883d2307dSDag-Erling Smørgrav * 983d2307dSDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 1083d2307dSDag-Erling Smørgrav * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 1183d2307dSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 1283d2307dSDag-Erling Smørgrav * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 1383d2307dSDag-Erling Smørgrav * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 1483d2307dSDag-Erling Smørgrav * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 1583d2307dSDag-Erling Smørgrav * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 1683d2307dSDag-Erling Smørgrav * SOFTWARE. 1783d2307dSDag-Erling Smørgrav */ 1883d2307dSDag-Erling Smørgrav 194b17dab0SDag-Erling Smørgrav #include "includes.h" 2083d2307dSDag-Erling Smørgrav 2183d2307dSDag-Erling Smørgrav #ifndef HAVE_INET_NTOP 2283d2307dSDag-Erling Smørgrav 2383d2307dSDag-Erling Smørgrav #if defined(LIBC_SCCS) && !defined(lint) 2483d2307dSDag-Erling Smørgrav #if 0 2583d2307dSDag-Erling Smørgrav static char rcsid[] = "$From: inet_ntop.c,v 8.7 1996/08/05 08:41:18 vixie Exp $"; 2683d2307dSDag-Erling Smørgrav #else 274b17dab0SDag-Erling Smørgrav static char rcsid[] = "$OpenBSD: inet_ntop.c,v 1.5 2002/08/23 16:27:31 itojun Exp $"; 2883d2307dSDag-Erling Smørgrav #endif 2983d2307dSDag-Erling Smørgrav #endif /* LIBC_SCCS and not lint */ 3083d2307dSDag-Erling Smørgrav 3183d2307dSDag-Erling Smørgrav #include <sys/param.h> 3283d2307dSDag-Erling Smørgrav #include <sys/types.h> 3383d2307dSDag-Erling Smørgrav #include <sys/socket.h> 3483d2307dSDag-Erling Smørgrav #include "openbsd-compat/fake-socket.h" 3583d2307dSDag-Erling Smørgrav #include <netinet/in.h> 3683d2307dSDag-Erling Smørgrav #include <arpa/inet.h> 3783d2307dSDag-Erling Smørgrav #ifndef HAVE_CYGWIN 3883d2307dSDag-Erling Smørgrav #include <arpa/nameser.h> 3983d2307dSDag-Erling Smørgrav #endif 4083d2307dSDag-Erling Smørgrav #include <string.h> 4183d2307dSDag-Erling Smørgrav #include <errno.h> 4283d2307dSDag-Erling Smørgrav #include <stdio.h> 4383d2307dSDag-Erling Smørgrav 4483d2307dSDag-Erling Smørgrav #ifndef IN6ADDRSZ 4583d2307dSDag-Erling Smørgrav #define IN6ADDRSZ 16 /* IPv6 T_AAAA */ 4683d2307dSDag-Erling Smørgrav #endif 4783d2307dSDag-Erling Smørgrav 4883d2307dSDag-Erling Smørgrav #ifndef INT16SZ 4983d2307dSDag-Erling Smørgrav #define INT16SZ 2 /* for systems without 16-bit ints */ 5083d2307dSDag-Erling Smørgrav #endif 5183d2307dSDag-Erling Smørgrav 5283d2307dSDag-Erling Smørgrav /* 5383d2307dSDag-Erling Smørgrav * WARNING: Don't even consider trying to compile this on a system where 5483d2307dSDag-Erling Smørgrav * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 5583d2307dSDag-Erling Smørgrav */ 5683d2307dSDag-Erling Smørgrav 574b17dab0SDag-Erling Smørgrav static const char *inet_ntop4(const u_char *src, char *dst, size_t size); 584b17dab0SDag-Erling Smørgrav static const char *inet_ntop6(const u_char *src, char *dst, size_t size); 5983d2307dSDag-Erling Smørgrav 6083d2307dSDag-Erling Smørgrav /* char * 6183d2307dSDag-Erling Smørgrav * inet_ntop(af, src, dst, size) 6283d2307dSDag-Erling Smørgrav * convert a network format address to presentation format. 6383d2307dSDag-Erling Smørgrav * return: 6483d2307dSDag-Erling Smørgrav * pointer to presentation format address (`dst'), or NULL (see errno). 6583d2307dSDag-Erling Smørgrav * author: 6683d2307dSDag-Erling Smørgrav * Paul Vixie, 1996. 6783d2307dSDag-Erling Smørgrav */ 6883d2307dSDag-Erling Smørgrav const char * 6983d2307dSDag-Erling Smørgrav inet_ntop(af, src, dst, size) 7083d2307dSDag-Erling Smørgrav int af; 7183d2307dSDag-Erling Smørgrav const void *src; 7283d2307dSDag-Erling Smørgrav char *dst; 7383d2307dSDag-Erling Smørgrav size_t size; 7483d2307dSDag-Erling Smørgrav { 7583d2307dSDag-Erling Smørgrav switch (af) { 7683d2307dSDag-Erling Smørgrav case AF_INET: 7783d2307dSDag-Erling Smørgrav return (inet_ntop4(src, dst, size)); 7883d2307dSDag-Erling Smørgrav case AF_INET6: 7983d2307dSDag-Erling Smørgrav return (inet_ntop6(src, dst, size)); 8083d2307dSDag-Erling Smørgrav default: 8183d2307dSDag-Erling Smørgrav errno = EAFNOSUPPORT; 8283d2307dSDag-Erling Smørgrav return (NULL); 8383d2307dSDag-Erling Smørgrav } 8483d2307dSDag-Erling Smørgrav /* NOTREACHED */ 8583d2307dSDag-Erling Smørgrav } 8683d2307dSDag-Erling Smørgrav 8783d2307dSDag-Erling Smørgrav /* const char * 8883d2307dSDag-Erling Smørgrav * inet_ntop4(src, dst, size) 8983d2307dSDag-Erling Smørgrav * format an IPv4 address, more or less like inet_ntoa() 9083d2307dSDag-Erling Smørgrav * return: 9183d2307dSDag-Erling Smørgrav * `dst' (as a const) 9283d2307dSDag-Erling Smørgrav * notes: 9383d2307dSDag-Erling Smørgrav * (1) uses no statics 9483d2307dSDag-Erling Smørgrav * (2) takes a u_char* not an in_addr as input 9583d2307dSDag-Erling Smørgrav * author: 9683d2307dSDag-Erling Smørgrav * Paul Vixie, 1996. 9783d2307dSDag-Erling Smørgrav */ 9883d2307dSDag-Erling Smørgrav static const char * 9983d2307dSDag-Erling Smørgrav inet_ntop4(src, dst, size) 10083d2307dSDag-Erling Smørgrav const u_char *src; 10183d2307dSDag-Erling Smørgrav char *dst; 10283d2307dSDag-Erling Smørgrav size_t size; 10383d2307dSDag-Erling Smørgrav { 10483d2307dSDag-Erling Smørgrav static const char fmt[] = "%u.%u.%u.%u"; 10583d2307dSDag-Erling Smørgrav char tmp[sizeof "255.255.255.255"]; 1064b17dab0SDag-Erling Smørgrav int l; 10783d2307dSDag-Erling Smørgrav 1084b17dab0SDag-Erling Smørgrav l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]); 1094b17dab0SDag-Erling Smørgrav if (l <= 0 || l >= size) { 11083d2307dSDag-Erling Smørgrav errno = ENOSPC; 11183d2307dSDag-Erling Smørgrav return (NULL); 11283d2307dSDag-Erling Smørgrav } 1134b17dab0SDag-Erling Smørgrav strlcpy(dst, tmp, size); 11483d2307dSDag-Erling Smørgrav return (dst); 11583d2307dSDag-Erling Smørgrav } 11683d2307dSDag-Erling Smørgrav 11783d2307dSDag-Erling Smørgrav /* const char * 11883d2307dSDag-Erling Smørgrav * inet_ntop6(src, dst, size) 11983d2307dSDag-Erling Smørgrav * convert IPv6 binary address into presentation (printable) format 12083d2307dSDag-Erling Smørgrav * author: 12183d2307dSDag-Erling Smørgrav * Paul Vixie, 1996. 12283d2307dSDag-Erling Smørgrav */ 12383d2307dSDag-Erling Smørgrav static const char * 12483d2307dSDag-Erling Smørgrav inet_ntop6(src, dst, size) 12583d2307dSDag-Erling Smørgrav const u_char *src; 12683d2307dSDag-Erling Smørgrav char *dst; 12783d2307dSDag-Erling Smørgrav size_t size; 12883d2307dSDag-Erling Smørgrav { 12983d2307dSDag-Erling Smørgrav /* 13083d2307dSDag-Erling Smørgrav * Note that int32_t and int16_t need only be "at least" large enough 13183d2307dSDag-Erling Smørgrav * to contain a value of the specified size. On some systems, like 13283d2307dSDag-Erling Smørgrav * Crays, there is no such thing as an integer variable with 16 bits. 13383d2307dSDag-Erling Smørgrav * Keep this in mind if you think this function should have been coded 13483d2307dSDag-Erling Smørgrav * to use pointer overlays. All the world's not a VAX. 13583d2307dSDag-Erling Smørgrav */ 1364b17dab0SDag-Erling Smørgrav char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; 1374b17dab0SDag-Erling Smørgrav char *tp, *ep; 13883d2307dSDag-Erling Smørgrav struct { int base, len; } best, cur; 13983d2307dSDag-Erling Smørgrav u_int words[IN6ADDRSZ / INT16SZ]; 14083d2307dSDag-Erling Smørgrav int i; 1414b17dab0SDag-Erling Smørgrav int advance; 14283d2307dSDag-Erling Smørgrav 14383d2307dSDag-Erling Smørgrav /* 14483d2307dSDag-Erling Smørgrav * Preprocess: 14583d2307dSDag-Erling Smørgrav * Copy the input (bytewise) array into a wordwise array. 14683d2307dSDag-Erling Smørgrav * Find the longest run of 0x00's in src[] for :: shorthanding. 14783d2307dSDag-Erling Smørgrav */ 14883d2307dSDag-Erling Smørgrav memset(words, '\0', sizeof words); 14983d2307dSDag-Erling Smørgrav for (i = 0; i < IN6ADDRSZ; i++) 15083d2307dSDag-Erling Smørgrav words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 15183d2307dSDag-Erling Smørgrav best.base = -1; 15283d2307dSDag-Erling Smørgrav cur.base = -1; 15383d2307dSDag-Erling Smørgrav for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 15483d2307dSDag-Erling Smørgrav if (words[i] == 0) { 15583d2307dSDag-Erling Smørgrav if (cur.base == -1) 15683d2307dSDag-Erling Smørgrav cur.base = i, cur.len = 1; 15783d2307dSDag-Erling Smørgrav else 15883d2307dSDag-Erling Smørgrav cur.len++; 15983d2307dSDag-Erling Smørgrav } else { 16083d2307dSDag-Erling Smørgrav if (cur.base != -1) { 16183d2307dSDag-Erling Smørgrav if (best.base == -1 || cur.len > best.len) 16283d2307dSDag-Erling Smørgrav best = cur; 16383d2307dSDag-Erling Smørgrav cur.base = -1; 16483d2307dSDag-Erling Smørgrav } 16583d2307dSDag-Erling Smørgrav } 16683d2307dSDag-Erling Smørgrav } 16783d2307dSDag-Erling Smørgrav if (cur.base != -1) { 16883d2307dSDag-Erling Smørgrav if (best.base == -1 || cur.len > best.len) 16983d2307dSDag-Erling Smørgrav best = cur; 17083d2307dSDag-Erling Smørgrav } 17183d2307dSDag-Erling Smørgrav if (best.base != -1 && best.len < 2) 17283d2307dSDag-Erling Smørgrav best.base = -1; 17383d2307dSDag-Erling Smørgrav 17483d2307dSDag-Erling Smørgrav /* 17583d2307dSDag-Erling Smørgrav * Format the result. 17683d2307dSDag-Erling Smørgrav */ 17783d2307dSDag-Erling Smørgrav tp = tmp; 1784b17dab0SDag-Erling Smørgrav ep = tmp + sizeof(tmp); 1794b17dab0SDag-Erling Smørgrav for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { 18083d2307dSDag-Erling Smørgrav /* Are we inside the best run of 0x00's? */ 18183d2307dSDag-Erling Smørgrav if (best.base != -1 && i >= best.base && 18283d2307dSDag-Erling Smørgrav i < (best.base + best.len)) { 1834b17dab0SDag-Erling Smørgrav if (i == best.base) { 1844b17dab0SDag-Erling Smørgrav if (tp + 1 >= ep) 1854b17dab0SDag-Erling Smørgrav return (NULL); 18683d2307dSDag-Erling Smørgrav *tp++ = ':'; 1874b17dab0SDag-Erling Smørgrav } 18883d2307dSDag-Erling Smørgrav continue; 18983d2307dSDag-Erling Smørgrav } 19083d2307dSDag-Erling Smørgrav /* Are we following an initial run of 0x00s or any real hex? */ 1914b17dab0SDag-Erling Smørgrav if (i != 0) { 1924b17dab0SDag-Erling Smørgrav if (tp + 1 >= ep) 1934b17dab0SDag-Erling Smørgrav return (NULL); 19483d2307dSDag-Erling Smørgrav *tp++ = ':'; 1954b17dab0SDag-Erling Smørgrav } 19683d2307dSDag-Erling Smørgrav /* Is this address an encapsulated IPv4? */ 19783d2307dSDag-Erling Smørgrav if (i == 6 && best.base == 0 && 19883d2307dSDag-Erling Smørgrav (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { 1994b17dab0SDag-Erling Smørgrav if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) 20083d2307dSDag-Erling Smørgrav return (NULL); 20183d2307dSDag-Erling Smørgrav tp += strlen(tp); 20283d2307dSDag-Erling Smørgrav break; 20383d2307dSDag-Erling Smørgrav } 2044b17dab0SDag-Erling Smørgrav advance = snprintf(tp, ep - tp, "%x", words[i]); 2054b17dab0SDag-Erling Smørgrav if (advance <= 0 || advance >= ep - tp) 2064b17dab0SDag-Erling Smørgrav return (NULL); 2074b17dab0SDag-Erling Smørgrav tp += advance; 20883d2307dSDag-Erling Smørgrav } 20983d2307dSDag-Erling Smørgrav /* Was it a trailing run of 0x00's? */ 2104b17dab0SDag-Erling Smørgrav if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { 2114b17dab0SDag-Erling Smørgrav if (tp + 1 >= ep) 2124b17dab0SDag-Erling Smørgrav return (NULL); 21383d2307dSDag-Erling Smørgrav *tp++ = ':'; 2144b17dab0SDag-Erling Smørgrav } 2154b17dab0SDag-Erling Smørgrav if (tp + 1 >= ep) 2164b17dab0SDag-Erling Smørgrav return (NULL); 21783d2307dSDag-Erling Smørgrav *tp++ = '\0'; 21883d2307dSDag-Erling Smørgrav 21983d2307dSDag-Erling Smørgrav /* 22083d2307dSDag-Erling Smørgrav * Check for overflow, copy, and we're done. 22183d2307dSDag-Erling Smørgrav */ 22283d2307dSDag-Erling Smørgrav if ((size_t)(tp - tmp) > size) { 22383d2307dSDag-Erling Smørgrav errno = ENOSPC; 22483d2307dSDag-Erling Smørgrav return (NULL); 22583d2307dSDag-Erling Smørgrav } 2264b17dab0SDag-Erling Smørgrav strlcpy(dst, tmp, size); 22783d2307dSDag-Erling Smørgrav return (dst); 22883d2307dSDag-Erling Smørgrav } 22983d2307dSDag-Erling Smørgrav 23083d2307dSDag-Erling Smørgrav #endif /* !HAVE_INET_NTOP */ 231