inet_net_ntop.c revision 225736
1229970Sadrian/* 2229970Sadrian * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 3229970Sadrian * Copyright (c) 1996,1999 by Internet Software Consortium. 4229970Sadrian * 5229970Sadrian * Permission to use, copy, modify, and distribute this software for any 6229970Sadrian * purpose with or without fee is hereby granted, provided that the above 7229970Sadrian * copyright notice and this permission notice appear in all copies. 8229970Sadrian * 9229970Sadrian * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 10229970Sadrian * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11229970Sadrian * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 12229970Sadrian * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13229970Sadrian * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14229970Sadrian * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 15229970Sadrian * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16229970Sadrian */ 17229970Sadrian 18229970Sadrian#if defined(LIBC_SCCS) && !defined(lint) 19229970Sadrianstatic const char rcsid[] = "$Id: inet_net_ntop.c,v 1.3.18.2 2006/06/20 02:51:32 marka Exp $"; 20229970Sadrian#endif 21229970Sadrian#include <sys/cdefs.h> 22229970Sadrian__FBSDID("$FreeBSD: stable/9/lib/libc/inet/inet_net_ntop.c 170244 2007-06-03 17:20:27Z ume $"); 23229970Sadrian 24229970Sadrian#include "port_before.h" 25229970Sadrian 26229970Sadrian#include <sys/types.h> 27229970Sadrian#include <sys/socket.h> 28229970Sadrian#include <netinet/in.h> 29229970Sadrian#include <arpa/inet.h> 30229970Sadrian 31229970Sadrian#include <errno.h> 32229970Sadrian#include <stdio.h> 33229970Sadrian#include <string.h> 34229970Sadrian#include <stdlib.h> 35229970Sadrian 36229970Sadrian#include "port_after.h" 37229970Sadrian 38229970Sadrian#ifdef SPRINTF_CHAR 39229970Sadrian# define SPRINTF(x) strlen(sprintf/**/x) 40229970Sadrian#else 41229970Sadrian# define SPRINTF(x) ((size_t)sprintf x) 42229970Sadrian#endif 43229970Sadrian 44229970Sadrianstatic char * inet_net_ntop_ipv4(const u_char *src, int bits, char *dst, 45229970Sadrian size_t size); 46229970Sadrianstatic char * inet_net_ntop_ipv6(const u_char *src, int bits, char *dst, 47229970Sadrian size_t size); 48229970Sadrian 49229970Sadrian/*% 50229970Sadrian * char * 51229970Sadrian * inet_net_ntop(af, src, bits, dst, size) 52229970Sadrian * convert network number from network to presentation format. 53229970Sadrian * generates CIDR style result always. 54229970Sadrian * return: 55229970Sadrian * pointer to dst, or NULL if an error occurred (check errno). 56229970Sadrian * author: 57229970Sadrian * Paul Vixie (ISC), July 1996 58229970Sadrian */ 59229970Sadrianchar * 60229970Sadrianinet_net_ntop(af, src, bits, dst, size) 61229970Sadrian int af; 62229970Sadrian const void *src; 63229970Sadrian int bits; 64229970Sadrian char *dst; 65229970Sadrian size_t size; 66229970Sadrian{ 67229970Sadrian switch (af) { 68229970Sadrian case AF_INET: 69229970Sadrian return (inet_net_ntop_ipv4(src, bits, dst, size)); 70229970Sadrian case AF_INET6: 71229970Sadrian return (inet_net_ntop_ipv6(src, bits, dst, size)); 72229970Sadrian default: 73229970Sadrian errno = EAFNOSUPPORT; 74229970Sadrian return (NULL); 75229970Sadrian } 76229970Sadrian} 77229970Sadrian 78229970Sadrian/*% 79229970Sadrian * static char * 80229970Sadrian * inet_net_ntop_ipv4(src, bits, dst, size) 81229970Sadrian * convert IPv4 network number from network to presentation format. 82229970Sadrian * generates CIDR style result always. 83229970Sadrian * return: 84229970Sadrian * pointer to dst, or NULL if an error occurred (check errno). 85229970Sadrian * note: 86229970Sadrian * network byte order assumed. this means 192.5.5.240/28 has 87229970Sadrian * 0b11110000 in its fourth octet. 88229970Sadrian * author: 89229970Sadrian * Paul Vixie (ISC), July 1996 90229970Sadrian */ 91229970Sadrianstatic char * 92229970Sadrianinet_net_ntop_ipv4(src, bits, dst, size) 93229970Sadrian const u_char *src; 94229970Sadrian int bits; 95229970Sadrian char *dst; 96229970Sadrian size_t size; 97229970Sadrian{ 98229970Sadrian char *odst = dst; 99229970Sadrian char *t; 100229970Sadrian u_int m; 101229970Sadrian int b; 102229970Sadrian 103229970Sadrian if (bits < 0 || bits > 32) { 104229970Sadrian errno = EINVAL; 105229970Sadrian return (NULL); 106229970Sadrian } 107229970Sadrian 108229970Sadrian if (bits == 0) { 109229970Sadrian if (size < sizeof "0") 110229970Sadrian goto emsgsize; 111229970Sadrian *dst++ = '0'; 112229970Sadrian size--; 113229970Sadrian *dst = '\0'; 114229970Sadrian } 115229970Sadrian 116229970Sadrian /* Format whole octets. */ 117229970Sadrian for (b = bits / 8; b > 0; b--) { 118229970Sadrian if (size <= sizeof "255.") 119229970Sadrian goto emsgsize; 120229970Sadrian t = dst; 121229970Sadrian dst += SPRINTF((dst, "%u", *src++)); 122229970Sadrian if (b > 1) { 123229970Sadrian *dst++ = '.'; 124229970Sadrian *dst = '\0'; 125229970Sadrian } 126229970Sadrian size -= (size_t)(dst - t); 127229970Sadrian } 128229970Sadrian 129229970Sadrian /* Format partial octet. */ 130229970Sadrian b = bits % 8; 131229970Sadrian if (b > 0) { 132229970Sadrian if (size <= sizeof ".255") 133229970Sadrian goto emsgsize; 134229970Sadrian t = dst; 135229970Sadrian if (dst != odst) 136229970Sadrian *dst++ = '.'; 137229970Sadrian m = ((1 << b) - 1) << (8 - b); 138229970Sadrian dst += SPRINTF((dst, "%u", *src & m)); 139229970Sadrian size -= (size_t)(dst - t); 140229970Sadrian } 141229970Sadrian 142229970Sadrian /* Format CIDR /width. */ 143229970Sadrian if (size <= sizeof "/32") 144229970Sadrian goto emsgsize; 145229970Sadrian dst += SPRINTF((dst, "/%u", bits)); 146229970Sadrian return (odst); 147229970Sadrian 148229970Sadrian emsgsize: 149229970Sadrian errno = EMSGSIZE; 150229970Sadrian return (NULL); 151229970Sadrian} 152229970Sadrian 153229970Sadrian/*% 154229970Sadrian * static char * 155229970Sadrian * inet_net_ntop_ipv6(src, bits, fakebits, dst, size) 156229970Sadrian * convert IPv6 network number from network to presentation format. 157229970Sadrian * generates CIDR style result always. Picks the shortest representation 158229970Sadrian * unless the IP is really IPv4. 159229970Sadrian * always prints specified number of bits (bits). 160229970Sadrian * return: 161229970Sadrian * pointer to dst, or NULL if an error occurred (check errno). 162229970Sadrian * note: 163229970Sadrian * network byte order assumed. this means 192.5.5.240/28 has 164229970Sadrian * 0b11110000 in its fourth octet. 165229970Sadrian * author: 166229970Sadrian * Vadim Kogan (UCB), June 2001 167229970Sadrian * Original version (IPv4) by Paul Vixie (ISC), July 1996 168229970Sadrian */ 169229970Sadrian 170229970Sadrianstatic char * 171229970Sadrianinet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { 172229970Sadrian u_int m; 173229970Sadrian int b; 174229970Sadrian int p; 175229970Sadrian int zero_s, zero_l, tmp_zero_s, tmp_zero_l; 176229970Sadrian int i; 177229970Sadrian int is_ipv4 = 0; 178229970Sadrian unsigned char inbuf[16]; 179229970Sadrian char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; 180229970Sadrian char *cp; 181229970Sadrian int words; 182229970Sadrian u_char *s; 183229970Sadrian 184229970Sadrian if (bits < 0 || bits > 128) { 185229970Sadrian errno = EINVAL; 186229970Sadrian return (NULL); 187229970Sadrian } 188229970Sadrian 189229970Sadrian cp = outbuf; 190229970Sadrian 191229970Sadrian if (bits == 0) { 192229970Sadrian *cp++ = ':'; 193229970Sadrian *cp++ = ':'; 194229970Sadrian *cp = '\0'; 195229970Sadrian } else { 196229970Sadrian /* Copy src to private buffer. Zero host part. */ 197229970Sadrian p = (bits + 7) / 8; 198229970Sadrian memcpy(inbuf, src, p); 199229970Sadrian memset(inbuf + p, 0, 16 - p); 200229970Sadrian b = bits % 8; 201229970Sadrian if (b != 0) { 202229970Sadrian m = ~0 << (8 - b); 203229970Sadrian inbuf[p-1] &= m; 204229970Sadrian } 205229970Sadrian 206229970Sadrian s = inbuf; 207229970Sadrian 208229970Sadrian /* how many words need to be displayed in output */ 209229970Sadrian words = (bits + 15) / 16; 210229970Sadrian if (words == 1) 211229970Sadrian words = 2; 212229970Sadrian 213229970Sadrian /* Find the longest substring of zero's */ 214 zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0; 215 for (i = 0; i < (words * 2); i += 2) { 216 if ((s[i] | s[i+1]) == 0) { 217 if (tmp_zero_l == 0) 218 tmp_zero_s = i / 2; 219 tmp_zero_l++; 220 } else { 221 if (tmp_zero_l && zero_l < tmp_zero_l) { 222 zero_s = tmp_zero_s; 223 zero_l = tmp_zero_l; 224 tmp_zero_l = 0; 225 } 226 } 227 } 228 229 if (tmp_zero_l && zero_l < tmp_zero_l) { 230 zero_s = tmp_zero_s; 231 zero_l = tmp_zero_l; 232 } 233 234 if (zero_l != words && zero_s == 0 && ((zero_l == 6) || 235 ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) || 236 ((zero_l == 7 && s[14] != 0 && s[15] != 1))))) 237 is_ipv4 = 1; 238 239 /* Format whole words. */ 240 for (p = 0; p < words; p++) { 241 if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) { 242 /* Time to skip some zeros */ 243 if (p == zero_s) 244 *cp++ = ':'; 245 if (p == words - 1) 246 *cp++ = ':'; 247 s++; 248 s++; 249 continue; 250 } 251 252 if (is_ipv4 && p > 5 ) { 253 *cp++ = (p == 6) ? ':' : '.'; 254 cp += SPRINTF((cp, "%u", *s++)); 255 /* we can potentially drop the last octet */ 256 if (p != 7 || bits > 120) { 257 *cp++ = '.'; 258 cp += SPRINTF((cp, "%u", *s++)); 259 } 260 } else { 261 if (cp != outbuf) 262 *cp++ = ':'; 263 cp += SPRINTF((cp, "%x", *s * 256 + s[1])); 264 s += 2; 265 } 266 } 267 } 268 /* Format CIDR /width. */ 269 sprintf(cp, "/%u", bits); 270 if (strlen(outbuf) + 1 > size) 271 goto emsgsize; 272 strcpy(dst, outbuf); 273 274 return (dst); 275 276emsgsize: 277 errno = EMSGSIZE; 278 return (NULL); 279} 280 281/* 282 * Weak aliases for applications that use certain private entry points, 283 * and fail to include <arpa/inet.h>. 284 */ 285#undef inet_net_ntop 286__weak_reference(__inet_net_ntop, inet_net_ntop); 287 288/*! \file */ 289