1/* inet_ntop.c -- convert IPv4 and IPv6 addresses from binary to text form 2 3 Copyright (C) 2005-2006, 2008-2022 Free Software Foundation, Inc. 4 5 This file is free software: you can redistribute it and/or modify 6 it under the terms of the GNU Lesser General Public License as 7 published by the Free Software Foundation; either version 2.1 of the 8 License, or (at your option) any later version. 9 10 This file is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public License 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ 17 18/* 19 * Copyright (c) 1996-1999 by Internet Software Consortium. 20 * 21 * Permission to use, copy, modify, and distribute this software for any 22 * purpose with or without fee is hereby granted, provided that the above 23 * copyright notice and this permission notice appear in all copies. 24 * 25 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 26 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 27 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 28 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 29 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 30 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 31 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 32 * SOFTWARE. 33 */ 34 35#include <config.h> 36 37/* Specification. */ 38#include <arpa/inet.h> 39 40/* Use this to suppress gcc's "...may be used before initialized" warnings. 41 Beware: The Code argument must not contain commas. */ 42#ifndef IF_LINT 43# if defined GCC_LINT || defined lint 44# define IF_LINT(Code) Code 45# else 46# define IF_LINT(Code) /* empty */ 47# endif 48#endif 49 50#if HAVE_DECL_INET_NTOP 51 52# undef inet_ntop 53 54const char * 55rpl_inet_ntop (int af, const void *restrict src, 56 char *restrict dst, socklen_t cnt) 57{ 58 return inet_ntop (af, src, dst, cnt); 59} 60 61#else 62 63# include <stdio.h> 64# include <string.h> 65# include <errno.h> 66 67# define NS_IN6ADDRSZ 16 68# define NS_INT16SZ 2 69 70/* 71 * WARNING: Don't even consider trying to compile this on a system where 72 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 73 */ 74typedef int verify_int_size[4 <= sizeof (int) ? 1 : -1]; 75 76static const char *inet_ntop4 (const unsigned char *src, char *dst, socklen_t size); 77# if HAVE_IPV6 78static const char *inet_ntop6 (const unsigned char *src, char *dst, socklen_t size); 79# endif 80 81 82/* char * 83 * inet_ntop(af, src, dst, size) 84 * convert a network format address to presentation format. 85 * return: 86 * pointer to presentation format address ('dst'), or NULL (see errno). 87 * author: 88 * Paul Vixie, 1996. 89 */ 90const char * 91inet_ntop (int af, const void *restrict src, 92 char *restrict dst, socklen_t cnt) 93{ 94 switch (af) 95 { 96# if HAVE_IPV4 97 case AF_INET: 98 return (inet_ntop4 (src, dst, cnt)); 99# endif 100 101# if HAVE_IPV6 102 case AF_INET6: 103 return (inet_ntop6 (src, dst, cnt)); 104# endif 105 106 default: 107 errno = EAFNOSUPPORT; 108 return (NULL); 109 } 110 /* NOTREACHED */ 111} 112 113/* const char * 114 * inet_ntop4(src, dst, size) 115 * format an IPv4 address 116 * return: 117 * 'dst' (as a const) 118 * notes: 119 * (1) uses no statics 120 * (2) takes a u_char* not an in_addr as input 121 * author: 122 * Paul Vixie, 1996. 123 */ 124static const char * 125inet_ntop4 (const unsigned char *src, char *dst, socklen_t size) 126{ 127 char tmp[sizeof "255.255.255.255"]; 128 int len; 129 130 len = sprintf (tmp, "%u.%u.%u.%u", src[0], src[1], src[2], src[3]); 131 if (len < 0) 132 return NULL; 133 134 if (len > size) 135 { 136 errno = ENOSPC; 137 return NULL; 138 } 139 140 return strcpy (dst, tmp); 141} 142 143# if HAVE_IPV6 144 145/* const char * 146 * inet_ntop6(src, dst, size) 147 * convert IPv6 binary address into presentation (printable) format 148 * author: 149 * Paul Vixie, 1996. 150 */ 151static const char * 152inet_ntop6 (const unsigned char *src, char *dst, socklen_t size) 153{ 154 /* 155 * Note that int32_t and int16_t need only be "at least" large enough 156 * to contain a value of the specified size. On some systems, like 157 * Crays, there is no such thing as an integer variable with 16 bits. 158 * Keep this in mind if you think this function should have been coded 159 * to use pointer overlays. All the world's not a VAX. 160 */ 161 char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; 162 struct 163 { 164 int base, len; 165 } best, cur; 166 unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; 167 int i; 168 169 /* 170 * Preprocess: 171 * Copy the input (bytewise) array into a wordwise array. 172 * Find the longest run of 0x00's in src[] for :: shorthanding. 173 */ 174 memset (words, '\0', sizeof words); 175 for (i = 0; i < NS_IN6ADDRSZ; i += 2) 176 words[i / 2] = (src[i] << 8) | src[i + 1]; 177 best.base = -1; 178 cur.base = -1; 179 IF_LINT(best.len = 0); 180 IF_LINT(cur.len = 0); 181 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) 182 { 183 if (words[i] == 0) 184 { 185 if (cur.base == -1) 186 cur.base = i, cur.len = 1; 187 else 188 cur.len++; 189 } 190 else 191 { 192 if (cur.base != -1) 193 { 194 if (best.base == -1 || cur.len > best.len) 195 best = cur; 196 cur.base = -1; 197 } 198 } 199 } 200 if (cur.base != -1) 201 { 202 if (best.base == -1 || cur.len > best.len) 203 best = cur; 204 } 205 if (best.base != -1 && best.len < 2) 206 best.base = -1; 207 208 /* 209 * Format the result. 210 */ 211 tp = tmp; 212 for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) 213 { 214 /* Are we inside the best run of 0x00's? */ 215 if (best.base != -1 && i >= best.base && i < (best.base + best.len)) 216 { 217 if (i == best.base) 218 *tp++ = ':'; 219 continue; 220 } 221 /* Are we following an initial run of 0x00s or any real hex? */ 222 if (i != 0) 223 *tp++ = ':'; 224 /* Is this address an encapsulated IPv4? */ 225 if (i == 6 && best.base == 0 && 226 (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) 227 { 228 if (!inet_ntop4 (src + 12, tp, sizeof tmp - (tp - tmp))) 229 return (NULL); 230 tp += strlen (tp); 231 break; 232 } 233 { 234 int len = sprintf (tp, "%x", words[i]); 235 if (len < 0) 236 return NULL; 237 tp += len; 238 } 239 } 240 /* Was it a trailing run of 0x00's? */ 241 if (best.base != -1 && (best.base + best.len) == 242 (NS_IN6ADDRSZ / NS_INT16SZ)) 243 *tp++ = ':'; 244 *tp++ = '\0'; 245 246 /* 247 * Check for overflow, copy, and we're done. 248 */ 249 if ((socklen_t) (tp - tmp) > size) 250 { 251 errno = ENOSPC; 252 return NULL; 253 } 254 255 return strcpy (dst, tmp); 256} 257 258# endif 259 260#endif 261