1240075Sdes/* $OpenBSD: inet_ntop.c,v 1.8 2008/12/09 19:38:38 otto Exp $ */ 2126274Sdes 398937Sdes/* Copyright (c) 1996 by Internet Software Consortium. 498937Sdes * 598937Sdes * Permission to use, copy, modify, and distribute this software for any 698937Sdes * purpose with or without fee is hereby granted, provided that the above 798937Sdes * copyright notice and this permission notice appear in all copies. 898937Sdes * 998937Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS 1098937Sdes * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES 1198937Sdes * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE 1298937Sdes * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL 1398937Sdes * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR 1498937Sdes * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS 1598937Sdes * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 1698937Sdes * SOFTWARE. 1798937Sdes */ 1898937Sdes 19157016Sdes/* OPENBSD ORIGINAL: lib/libc/net/inet_ntop.c */ 20157016Sdes 21106121Sdes#include "includes.h" 2298937Sdes 2398937Sdes#ifndef HAVE_INET_NTOP 2498937Sdes 2598937Sdes#include <sys/param.h> 2698937Sdes#include <sys/types.h> 2798937Sdes#include <sys/socket.h> 2898937Sdes#include <netinet/in.h> 2998937Sdes#include <arpa/inet.h> 3098937Sdes#include <arpa/nameser.h> 3198937Sdes#include <string.h> 3298937Sdes#include <errno.h> 3398937Sdes#include <stdio.h> 3498937Sdes 3598937Sdes#ifndef IN6ADDRSZ 3698937Sdes#define IN6ADDRSZ 16 /* IPv6 T_AAAA */ 3798937Sdes#endif 3898937Sdes 3998937Sdes#ifndef INT16SZ 4098937Sdes#define INT16SZ 2 /* for systems without 16-bit ints */ 4198937Sdes#endif 4298937Sdes 4398937Sdes/* 4498937Sdes * WARNING: Don't even consider trying to compile this on a system where 4598937Sdes * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. 4698937Sdes */ 4798937Sdes 48106121Sdesstatic const char *inet_ntop4(const u_char *src, char *dst, size_t size); 49106121Sdesstatic const char *inet_ntop6(const u_char *src, char *dst, size_t size); 5098937Sdes 5198937Sdes/* char * 5298937Sdes * inet_ntop(af, src, dst, size) 5398937Sdes * convert a network format address to presentation format. 5498937Sdes * return: 5598937Sdes * pointer to presentation format address (`dst'), or NULL (see errno). 5698937Sdes * author: 5798937Sdes * Paul Vixie, 1996. 5898937Sdes */ 5998937Sdesconst char * 60240075Sdesinet_ntop(int af, const void *src, char *dst, socklen_t size) 6198937Sdes{ 6298937Sdes switch (af) { 6398937Sdes case AF_INET: 64240075Sdes return (inet_ntop4(src, dst, (size_t)size)); 6598937Sdes case AF_INET6: 66240075Sdes return (inet_ntop6(src, dst, (size_t)size)); 6798937Sdes default: 6898937Sdes errno = EAFNOSUPPORT; 6998937Sdes return (NULL); 7098937Sdes } 7198937Sdes /* NOTREACHED */ 7298937Sdes} 7398937Sdes 7498937Sdes/* const char * 7598937Sdes * inet_ntop4(src, dst, size) 7698937Sdes * format an IPv4 address, more or less like inet_ntoa() 7798937Sdes * return: 7898937Sdes * `dst' (as a const) 7998937Sdes * notes: 8098937Sdes * (1) uses no statics 8198937Sdes * (2) takes a u_char* not an in_addr as input 8298937Sdes * author: 8398937Sdes * Paul Vixie, 1996. 8498937Sdes */ 8598937Sdesstatic const char * 86157016Sdesinet_ntop4(const u_char *src, char *dst, size_t size) 8798937Sdes{ 8898937Sdes static const char fmt[] = "%u.%u.%u.%u"; 8998937Sdes char tmp[sizeof "255.255.255.255"]; 90106121Sdes int l; 9198937Sdes 92106121Sdes l = snprintf(tmp, size, fmt, src[0], src[1], src[2], src[3]); 93106121Sdes if (l <= 0 || l >= size) { 9498937Sdes errno = ENOSPC; 9598937Sdes return (NULL); 9698937Sdes } 97106121Sdes strlcpy(dst, tmp, size); 9898937Sdes return (dst); 9998937Sdes} 10098937Sdes 10198937Sdes/* const char * 10298937Sdes * inet_ntop6(src, dst, size) 10398937Sdes * convert IPv6 binary address into presentation (printable) format 10498937Sdes * author: 10598937Sdes * Paul Vixie, 1996. 10698937Sdes */ 10798937Sdesstatic const char * 108157016Sdesinet_ntop6(const u_char *src, char *dst, size_t size) 10998937Sdes{ 11098937Sdes /* 11198937Sdes * Note that int32_t and int16_t need only be "at least" large enough 11298937Sdes * to contain a value of the specified size. On some systems, like 11398937Sdes * Crays, there is no such thing as an integer variable with 16 bits. 11498937Sdes * Keep this in mind if you think this function should have been coded 11598937Sdes * to use pointer overlays. All the world's not a VAX. 11698937Sdes */ 117106121Sdes char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"]; 118106121Sdes char *tp, *ep; 11998937Sdes struct { int base, len; } best, cur; 12098937Sdes u_int words[IN6ADDRSZ / INT16SZ]; 12198937Sdes int i; 122106121Sdes int advance; 12398937Sdes 12498937Sdes /* 12598937Sdes * Preprocess: 12698937Sdes * Copy the input (bytewise) array into a wordwise array. 12798937Sdes * Find the longest run of 0x00's in src[] for :: shorthanding. 12898937Sdes */ 12998937Sdes memset(words, '\0', sizeof words); 13098937Sdes for (i = 0; i < IN6ADDRSZ; i++) 13198937Sdes words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); 13298937Sdes best.base = -1; 13398937Sdes cur.base = -1; 13498937Sdes for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 13598937Sdes if (words[i] == 0) { 13698937Sdes if (cur.base == -1) 13798937Sdes cur.base = i, cur.len = 1; 13898937Sdes else 13998937Sdes cur.len++; 14098937Sdes } else { 14198937Sdes if (cur.base != -1) { 14298937Sdes if (best.base == -1 || cur.len > best.len) 14398937Sdes best = cur; 14498937Sdes cur.base = -1; 14598937Sdes } 14698937Sdes } 14798937Sdes } 14898937Sdes if (cur.base != -1) { 14998937Sdes if (best.base == -1 || cur.len > best.len) 15098937Sdes best = cur; 15198937Sdes } 15298937Sdes if (best.base != -1 && best.len < 2) 15398937Sdes best.base = -1; 15498937Sdes 15598937Sdes /* 15698937Sdes * Format the result. 15798937Sdes */ 15898937Sdes tp = tmp; 159106121Sdes ep = tmp + sizeof(tmp); 160106121Sdes for (i = 0; i < (IN6ADDRSZ / INT16SZ) && tp < ep; i++) { 16198937Sdes /* Are we inside the best run of 0x00's? */ 16298937Sdes if (best.base != -1 && i >= best.base && 16398937Sdes i < (best.base + best.len)) { 164106121Sdes if (i == best.base) { 165106121Sdes if (tp + 1 >= ep) 166106121Sdes return (NULL); 16798937Sdes *tp++ = ':'; 168106121Sdes } 16998937Sdes continue; 17098937Sdes } 17198937Sdes /* Are we following an initial run of 0x00s or any real hex? */ 172106121Sdes if (i != 0) { 173106121Sdes if (tp + 1 >= ep) 174106121Sdes return (NULL); 17598937Sdes *tp++ = ':'; 176106121Sdes } 17798937Sdes /* Is this address an encapsulated IPv4? */ 17898937Sdes if (i == 6 && best.base == 0 && 17998937Sdes (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { 180106121Sdes if (!inet_ntop4(src+12, tp, (size_t)(ep - tp))) 18198937Sdes return (NULL); 18298937Sdes tp += strlen(tp); 18398937Sdes break; 18498937Sdes } 185106121Sdes advance = snprintf(tp, ep - tp, "%x", words[i]); 186106121Sdes if (advance <= 0 || advance >= ep - tp) 187106121Sdes return (NULL); 188106121Sdes tp += advance; 18998937Sdes } 19098937Sdes /* Was it a trailing run of 0x00's? */ 191106121Sdes if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) { 192106121Sdes if (tp + 1 >= ep) 193106121Sdes return (NULL); 19498937Sdes *tp++ = ':'; 195106121Sdes } 196106121Sdes if (tp + 1 >= ep) 197106121Sdes return (NULL); 19898937Sdes *tp++ = '\0'; 19998937Sdes 20098937Sdes /* 20198937Sdes * Check for overflow, copy, and we're done. 20298937Sdes */ 20398937Sdes if ((size_t)(tp - tmp) > size) { 20498937Sdes errno = ENOSPC; 20598937Sdes return (NULL); 20698937Sdes } 207106121Sdes strlcpy(dst, tmp, size); 20898937Sdes return (dst); 20998937Sdes} 21098937Sdes 21198937Sdes#endif /* !HAVE_INET_NTOP */ 212