inet_net_ntop.c revision 156953
1169691Skan/* 297403Sobrien * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") 397403Sobrien * Copyright (c) 1996,1999 by Internet Software Consortium. 497403Sobrien * 597403Sobrien * Permission to use, copy, modify, and distribute this software for any 697403Sobrien * purpose with or without fee is hereby granted, provided that the above 797403Sobrien * copyright notice and this permission notice appear in all copies. 897403Sobrien * 997403Sobrien * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES 1097403Sobrien * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1197403Sobrien * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR 1297403Sobrien * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1397403Sobrien * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1497403Sobrien * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT 1597403Sobrien * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1697403Sobrien */ 17169691Skan 1897403Sobrien#if defined(LIBC_SCCS) && !defined(lint) 1997403Sobrienstatic const char rcsid[] = "$Id: inet_net_ntop.c,v 1.1.2.1.8.1 2004/03/09 08:33:32 marka Exp $"; 2097403Sobrien#endif 2197403Sobrien 2297403Sobrien#include "port_before.h" 2397403Sobrien 2497403Sobrien#include <sys/types.h> 2597403Sobrien#include <sys/socket.h> 2697403Sobrien#include <netinet/in.h> 2797403Sobrien#include <arpa/inet.h> 2897403Sobrien 2997403Sobrien#include <errno.h> 3097403Sobrien#include <stdio.h> 3197403Sobrien#include <string.h> 3297403Sobrien#include <stdlib.h> 33169691Skan 34169691Skan#include "port_after.h" 35107606Sobrien 36107606Sobrien#ifdef SPRINTF_CHAR 37132720Skan# define SPRINTF(x) strlen(sprintf/**/x) 3897403Sobrien#else 39132720Skan# define SPRINTF(x) ((size_t)sprintf x) 40132720Skan#endif 41132720Skan 42132720Skanstatic char * inet_net_ntop_ipv4 __P((const u_char *src, int bits, 43132720Skan char *dst, size_t size)); 44132720Skanstatic char * inet_net_ntop_ipv6 __P((const u_char *src, int bits, 45132720Skan char *dst, size_t size)); 46132720Skan 47132720Skan/* 48132720Skan * char * 49132720Skan * inet_net_ntop(af, src, bits, dst, size) 50132720Skan * convert network number from network to presentation format. 51132720Skan * generates CIDR style result always. 52132720Skan * return: 53132720Skan * pointer to dst, or NULL if an error occurred (check errno). 54132720Skan * author: 55132720Skan * Paul Vixie (ISC), July 1996 56132720Skan */ 57132720Skanchar * 58132720Skaninet_net_ntop(af, src, bits, dst, size) 59132720Skan int af; 60132720Skan const void *src; 61132720Skan int bits; 62169691Skan char *dst; 63169691Skan size_t size; 64132720Skan{ 65132720Skan switch (af) { 66132720Skan case AF_INET: 67169691Skan return (inet_net_ntop_ipv4(src, bits, dst, size)); 68132720Skan case AF_INET6: 69169691Skan return (inet_net_ntop_ipv6(src, bits, dst, size)); 70132720Skan default: 71132720Skan errno = EAFNOSUPPORT; 72132720Skan return (NULL); 73132720Skan } 74169691Skan} 75132720Skan 76132720Skan/* 77132720Skan * static char * 78132720Skan * inet_net_ntop_ipv4(src, bits, dst, size) 79132720Skan * convert IPv4 network number from network to presentation format. 80132720Skan * generates CIDR style result always. 81132720Skan * return: 82132720Skan * pointer to dst, or NULL if an error occurred (check errno). 83132720Skan * note: 84132720Skan * network byte order assumed. this means 192.5.5.240/28 has 85132720Skan * 0b11110000 in its fourth octet. 86132720Skan * author: 87132720Skan * Paul Vixie (ISC), July 1996 88169691Skan */ 89132720Skanstatic char * 90132720Skaninet_net_ntop_ipv4(src, bits, dst, size) 91132720Skan const u_char *src; 92132720Skan int bits; 93132720Skan char *dst; 94132720Skan size_t size; 95132720Skan{ 96132720Skan char *odst = dst; 97169691Skan char *t; 98132720Skan u_int m; 99132720Skan int b; 100132720Skan 101132720Skan if (bits < 0 || bits > 32) { 102169691Skan errno = EINVAL; 103132720Skan return (NULL); 104132720Skan } 105132720Skan 106132720Skan if (bits == 0) { 107132720Skan if (size < sizeof "0") 108132720Skan goto emsgsize; 109169691Skan *dst++ = '0'; 110132720Skan size--; 111132720Skan *dst = '\0'; 112132720Skan } 113169691Skan 114132720Skan /* Format whole octets. */ 115132720Skan for (b = bits / 8; b > 0; b--) { 116132720Skan if (size <= sizeof "255.") 117169691Skan goto emsgsize; 118132720Skan t = dst; 119132720Skan dst += SPRINTF((dst, "%u", *src++)); 120132720Skan if (b > 1) { 121132720Skan *dst++ = '.'; 122169691Skan *dst = '\0'; 123132720Skan } 124132720Skan size -= (size_t)(dst - t); 125132720Skan } 126132720Skan 127132720Skan /* Format partial octet. */ 128132720Skan b = bits % 8; 129132720Skan if (b > 0) { 130132720Skan if (size <= sizeof ".255") 131132720Skan goto emsgsize; 132132720Skan t = dst; 133132720Skan if (dst != odst) 134132720Skan *dst++ = '.'; 135169691Skan m = ((1 << b) - 1) << (8 - b); 136132720Skan dst += SPRINTF((dst, "%u", *src & m)); 137132720Skan size -= (size_t)(dst - t); 138169691Skan } 139132720Skan 140132720Skan /* Format CIDR /width. */ 141132720Skan if (size <= sizeof "/32") 142132720Skan goto emsgsize; 143132720Skan dst += SPRINTF((dst, "/%u", bits)); 144132720Skan return (odst); 145107606Sobrien 146132720Skan emsgsize: 147132720Skan errno = EMSGSIZE; 148132720Skan return (NULL); 149132720Skan} 150132720Skan 151132720Skan/* 152132720Skan * static char * 153132720Skan * inet_net_ntop_ipv6(src, bits, fakebits, dst, size) 15497403Sobrien * convert IPv6 network number from network to presentation format. 15597403Sobrien * generates CIDR style result always. Picks the shortest representation 156132720Skan * unless the IP is really IPv4. 157132720Skan * always prints specified number of bits (bits). 158132720Skan * return: 159132720Skan * pointer to dst, or NULL if an error occurred (check errno). 160132720Skan * note: 161132720Skan * network byte order assumed. this means 192.5.5.240/28 has 162132720Skan * 0x11110000 in its fourth octet. 16397403Sobrien * author: 164132720Skan * Vadim Kogan (UCB), June 2001 165132720Skan * Original version (IPv4) by Paul Vixie (ISC), July 1996 166132720Skan */ 167132720Skan 168132720Skanstatic char * 169132720Skaninet_net_ntop_ipv6(const u_char *src, int bits, char *dst, size_t size) { 17097403Sobrien u_int m; 171132720Skan int b; 17297403Sobrien int p; 17397403Sobrien int zero_s, zero_l, tmp_zero_s, tmp_zero_l; 17497403Sobrien int i; 17597403Sobrien int is_ipv4 = 0; 17697403Sobrien unsigned char inbuf[16]; 17797403Sobrien char outbuf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255.255.255.255/128")]; 178169691Skan char *cp; 179132720Skan int words; 180169691Skan u_char *s; 18197403Sobrien 182132720Skan if (bits < 0 || bits > 128) { 183132720Skan errno = EINVAL; 18497403Sobrien return (NULL); 18597403Sobrien } 18697403Sobrien 18797403Sobrien cp = outbuf; 188117397Skan 189132720Skan if (bits == 0) { 190132720Skan *cp++ = ':'; 19197403Sobrien *cp++ = ':'; 192132720Skan *cp = '\0'; 193132720Skan } else { 194132720Skan /* Copy src to private buffer. Zero host part. */ 195132720Skan p = (bits + 7) / 8; 196132720Skan memcpy(inbuf, src, p); 197132720Skan memset(inbuf + p, 0, 16 - p); 19897403Sobrien b = bits % 8; 199169691Skan if (b != 0) { 200132720Skan m = ~0 << (8 - b); 201169691Skan inbuf[p-1] &= m; 202107606Sobrien } 203169691Skan 204169691Skan s = inbuf; 205107606Sobrien 206132720Skan /* how many words need to be displayed in output */ 207107606Sobrien words = (bits + 15) / 16; 208146897Skan if (words == 1) 209132720Skan words = 2; 210132720Skan 211146897Skan /* Find the longest substring of zero's */ 212146897Skan zero_s = zero_l = tmp_zero_s = tmp_zero_l = 0; 213132720Skan for (i = 0; i < (words * 2); i += 2) { 214132720Skan if ((s[i] | s[i+1]) == 0) { 215169691Skan if (tmp_zero_l == 0) 216169691Skan tmp_zero_s = i / 2; 217169691Skan tmp_zero_l++; 218132720Skan } else { 219107606Sobrien if (tmp_zero_l && zero_l < tmp_zero_l) { 220132720Skan zero_s = tmp_zero_s; 221132720Skan zero_l = tmp_zero_l; 222132720Skan tmp_zero_l = 0; 223132720Skan } 224132720Skan } 225132720Skan } 226132720Skan 227132720Skan if (tmp_zero_l && zero_l < tmp_zero_l) { 228132720Skan zero_s = tmp_zero_s; 229132720Skan zero_l = tmp_zero_l; 230132720Skan } 231132720Skan 232132720Skan if (zero_l != words && zero_s == 0 && ((zero_l == 6) || 233132720Skan ((zero_l == 5 && s[10] == 0xff && s[11] == 0xff) || 234132720Skan ((zero_l == 7 && s[14] != 0 && s[15] != 1))))) 235132720Skan is_ipv4 = 1; 23697403Sobrien 237132720Skan /* Format whole words. */ 238132720Skan for (p = 0; p < words; p++) { 239132720Skan if (zero_l != 0 && p >= zero_s && p < zero_s + zero_l) { 240132720Skan /* Time to skip some zeros */ 241132720Skan if (p == zero_s) 242132720Skan *cp++ = ':'; 243132720Skan if (p == words - 1) 244132720Skan *cp++ = ':'; 245132720Skan s++; 246132720Skan s++; 247132720Skan continue; 248132720Skan } 249132720Skan 250132720Skan if (is_ipv4 && p > 5 ) { 251132720Skan *cp++ = (p == 6) ? ':' : '.'; 25297403Sobrien cp += SPRINTF((cp, "%u", *s++)); 253132720Skan /* we can potentially drop the last octet */ 254132720Skan if (p != 7 || bits > 120) { 255132720Skan *cp++ = '.'; 256132720Skan cp += SPRINTF((cp, "%u", *s++)); 257132720Skan } 258132720Skan } else { 259132720Skan if (cp != outbuf) 260132720Skan *cp++ = ':'; 26197403Sobrien cp += SPRINTF((cp, "%x", *s * 256 + s[1])); 26297403Sobrien s += 2; 26397403Sobrien } 26497403Sobrien } 26597403Sobrien } 26697403Sobrien /* Format CIDR /width. */ 267169691Skan SPRINTF((cp, "/%u", bits)); 268169691Skan if (strlen(outbuf) + 1 > size) 269169691Skan goto emsgsize; 27097403Sobrien strcpy(dst, outbuf); 27197403Sobrien 27297403Sobrien return (dst); 27397403Sobrien 27497403Sobrienemsgsize: 27597403Sobrien errno = EMSGSIZE; 276169691Skan return (NULL); 277107606Sobrien} 278169691Skan