1784088dfSchristos /* 2784088dfSchristos * Copyright (c) 1999 Kungliga Tekniska Högskolan 3784088dfSchristos * (Royal Institute of Technology, Stockholm, Sweden). 4784088dfSchristos * All rights reserved. 5784088dfSchristos * 6784088dfSchristos * Redistribution and use in source and binary forms, with or without 7784088dfSchristos * modification, are permitted provided that the following conditions 8784088dfSchristos * are met: 9784088dfSchristos * 10784088dfSchristos * 1. Redistributions of source code must retain the above copyright 11784088dfSchristos * notice, this list of conditions and the following disclaimer. 12784088dfSchristos * 13784088dfSchristos * 2. Redistributions in binary form must reproduce the above copyright 14784088dfSchristos * notice, this list of conditions and the following disclaimer in the 15784088dfSchristos * documentation and/or other materials provided with the distribution. 16784088dfSchristos * 17784088dfSchristos * 3. All advertising materials mentioning features or use of this software 18784088dfSchristos * must display the following acknowledgement: 19784088dfSchristos * This product includes software developed by the Kungliga Tekniska 20784088dfSchristos * Högskolan and its contributors. 21784088dfSchristos * 22784088dfSchristos * 4. Neither the name of the Institute nor the names of its contributors 23784088dfSchristos * may be used to endorse or promote products derived from this software 24784088dfSchristos * without specific prior written permission. 25784088dfSchristos * 26784088dfSchristos * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 27784088dfSchristos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28784088dfSchristos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29784088dfSchristos * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 30784088dfSchristos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31784088dfSchristos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32784088dfSchristos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33784088dfSchristos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34784088dfSchristos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35784088dfSchristos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36784088dfSchristos * SUCH DAMAGE. 37784088dfSchristos */ 38784088dfSchristos 39fdccd7e4Schristos #include <sys/cdefs.h> 40fdccd7e4Schristos #ifndef lint 41*26ba0b50Schristos __RCSID("$NetBSD: addrtostr.c,v 1.6 2024/09/02 16:15:29 christos Exp $"); 42fdccd7e4Schristos #endif 43fdccd7e4Schristos 44c74ad251Schristos #include <config.h> 45784088dfSchristos 46c74ad251Schristos #include "netdissect-stdinc.h" 47784088dfSchristos #include "addrtostr.h" 48784088dfSchristos 49784088dfSchristos #include <stdio.h> 50784088dfSchristos #include <string.h> 51784088dfSchristos 52784088dfSchristos /* 53784088dfSchristos * 54784088dfSchristos */ 55784088dfSchristos 56784088dfSchristos #ifndef IN6ADDRSZ 57784088dfSchristos #define IN6ADDRSZ 16 /* IPv6 T_AAAA */ 58784088dfSchristos #endif 59784088dfSchristos 60784088dfSchristos #ifndef INT16SZ 61784088dfSchristos #define INT16SZ 2 /* word size */ 62784088dfSchristos #endif 63784088dfSchristos 64784088dfSchristos const char * 65784088dfSchristos addrtostr (const void *src, char *dst, size_t size) 66784088dfSchristos { 67784088dfSchristos const u_char *srcaddr = (const u_char *)src; 68784088dfSchristos const char digits[] = "0123456789"; 69784088dfSchristos int i; 70784088dfSchristos const char *orig_dst = dst; 71784088dfSchristos 72784088dfSchristos if (size < INET_ADDRSTRLEN) { 73784088dfSchristos errno = ENOSPC; 74784088dfSchristos return NULL; 75784088dfSchristos } 76784088dfSchristos for (i = 0; i < 4; ++i) { 77784088dfSchristos int n = *srcaddr++; 78784088dfSchristos int non_zerop = 0; 79784088dfSchristos 80784088dfSchristos if (non_zerop || n / 100 > 0) { 81784088dfSchristos *dst++ = digits[n / 100]; 82784088dfSchristos n %= 100; 83784088dfSchristos non_zerop = 1; 84784088dfSchristos } 85784088dfSchristos if (non_zerop || n / 10 > 0) { 86784088dfSchristos *dst++ = digits[n / 10]; 87784088dfSchristos n %= 10; 88784088dfSchristos non_zerop = 1; 89784088dfSchristos } 90784088dfSchristos *dst++ = digits[n]; 91784088dfSchristos if (i != 3) 92784088dfSchristos *dst++ = '.'; 93784088dfSchristos } 94784088dfSchristos *dst++ = '\0'; 95784088dfSchristos return orig_dst; 96784088dfSchristos } 97784088dfSchristos 98784088dfSchristos /* 99784088dfSchristos * Convert IPv6 binary address into presentation (printable) format. 100784088dfSchristos */ 101784088dfSchristos const char * 102784088dfSchristos addrtostr6 (const void *src, char *dst, size_t size) 103784088dfSchristos { 104784088dfSchristos /* 105784088dfSchristos * Note that int32_t and int16_t need only be "at least" large enough 106784088dfSchristos * to contain a value of the specified size. On some systems, like 107784088dfSchristos * Crays, there is no such thing as an integer variable with 16 bits. 108784088dfSchristos * Keep this in mind if you think this function should have been coded 109784088dfSchristos * to use pointer overlays. All the world's not a VAX. 110784088dfSchristos */ 111784088dfSchristos const u_char *srcaddr = (const u_char *)src; 112dc860a36Sspz char *dp; 113dc860a36Sspz size_t space_left, added_space; 114dc860a36Sspz int snprintfed; 115784088dfSchristos struct { 11672c96ff3Schristos int base; 11772c96ff3Schristos int len; 118784088dfSchristos } best, cur; 11972c96ff3Schristos uint16_t words [IN6ADDRSZ / INT16SZ]; 12072c96ff3Schristos int i; 121784088dfSchristos 122784088dfSchristos /* Preprocess: 123784088dfSchristos * Copy the input (bytewise) array into a wordwise array. 124784088dfSchristos * Find the longest run of 0x00's in src[] for :: shorthanding. 125784088dfSchristos */ 12672c96ff3Schristos for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) 12772c96ff3Schristos words[i] = (srcaddr[2*i] << 8) | srcaddr[2*i + 1]; 128784088dfSchristos 129784088dfSchristos best.len = 0; 130784088dfSchristos best.base = -1; 131784088dfSchristos cur.len = 0; 132784088dfSchristos cur.base = -1; 133*26ba0b50Schristos for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 134*26ba0b50Schristos if (words[i] == 0) { 135784088dfSchristos if (cur.base == -1) 136784088dfSchristos cur.base = i, cur.len = 1; 137784088dfSchristos else cur.len++; 138*26ba0b50Schristos } else if (cur.base != -1) { 139784088dfSchristos if (best.base == -1 || cur.len > best.len) 140784088dfSchristos best = cur; 141784088dfSchristos cur.base = -1; 142784088dfSchristos } 143784088dfSchristos } 144784088dfSchristos if ((cur.base != -1) && (best.base == -1 || cur.len > best.len)) 145784088dfSchristos best = cur; 146784088dfSchristos if (best.base != -1 && best.len < 2) 147784088dfSchristos best.base = -1; 148784088dfSchristos 149784088dfSchristos /* Format the result. 150784088dfSchristos */ 151dc860a36Sspz dp = dst; 152dc860a36Sspz space_left = size; 153dc860a36Sspz #define APPEND_CHAR(c) \ 154dc860a36Sspz { \ 155dc860a36Sspz if (space_left == 0) { \ 156dc860a36Sspz errno = ENOSPC; \ 157dc860a36Sspz return (NULL); \ 158dc860a36Sspz } \ 159dc860a36Sspz *dp++ = c; \ 160dc860a36Sspz space_left--; \ 161dc860a36Sspz } 162*26ba0b50Schristos for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 163784088dfSchristos /* Are we inside the best run of 0x00's? 164784088dfSchristos */ 165*26ba0b50Schristos if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { 166784088dfSchristos if (i == best.base) 167dc860a36Sspz APPEND_CHAR(':'); 168784088dfSchristos continue; 169784088dfSchristos } 170784088dfSchristos 171784088dfSchristos /* Are we following an initial run of 0x00s or any real hex? 172784088dfSchristos */ 173784088dfSchristos if (i != 0) 174dc860a36Sspz APPEND_CHAR(':'); 175784088dfSchristos 176784088dfSchristos /* Is this address an encapsulated IPv4? 177784088dfSchristos */ 178784088dfSchristos if (i == 6 && best.base == 0 && 179784088dfSchristos (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) 180784088dfSchristos { 181*26ba0b50Schristos if (!addrtostr(srcaddr+12, dp, space_left)) { 182784088dfSchristos errno = ENOSPC; 183784088dfSchristos return (NULL); 184784088dfSchristos } 185dc860a36Sspz added_space = strlen(dp); 186dc860a36Sspz dp += added_space; 187dc860a36Sspz space_left -= added_space; 188784088dfSchristos break; 189784088dfSchristos } 19072c96ff3Schristos snprintfed = snprintf (dp, space_left, "%x", words[i]); 191dc860a36Sspz if (snprintfed < 0) 192dc860a36Sspz return (NULL); 193*26ba0b50Schristos if ((size_t) snprintfed >= space_left) { 194dc860a36Sspz errno = ENOSPC; 195dc860a36Sspz return (NULL); 196dc860a36Sspz } 197dc860a36Sspz dp += snprintfed; 198dc860a36Sspz space_left -= snprintfed; 199784088dfSchristos } 200784088dfSchristos 201784088dfSchristos /* Was it a trailing run of 0x00's? 202784088dfSchristos */ 203784088dfSchristos if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) 204dc860a36Sspz APPEND_CHAR(':'); 205dc860a36Sspz APPEND_CHAR('\0'); 206784088dfSchristos 207dc860a36Sspz return (dst); 208784088dfSchristos } 209