1 1.1 christos /* 2 1.1 christos * Copyright (c) 1999 Kungliga Tekniska Hgskolan 3 1.1 christos * (Royal Institute of Technology, Stockholm, Sweden). 4 1.1 christos * All rights reserved. 5 1.1 christos * 6 1.1 christos * Redistribution and use in source and binary forms, with or without 7 1.1 christos * modification, are permitted provided that the following conditions 8 1.1 christos * are met: 9 1.1 christos * 10 1.1 christos * 1. Redistributions of source code must retain the above copyright 11 1.1 christos * notice, this list of conditions and the following disclaimer. 12 1.1 christos * 13 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 christos * notice, this list of conditions and the following disclaimer in the 15 1.1 christos * documentation and/or other materials provided with the distribution. 16 1.1 christos * 17 1.1 christos * 3. All advertising materials mentioning features or use of this software 18 1.1 christos * must display the following acknowledgement: 19 1.1 christos * This product includes software developed by the Kungliga Tekniska 20 1.1 christos * Hgskolan and its contributors. 21 1.1 christos * 22 1.1 christos * 4. Neither the name of the Institute nor the names of its contributors 23 1.1 christos * may be used to endorse or promote products derived from this software 24 1.1 christos * without specific prior written permission. 25 1.1 christos * 26 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 27 1.1 christos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 28 1.1 christos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 29 1.1 christos * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 30 1.1 christos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 31 1.1 christos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 32 1.1 christos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 33 1.1 christos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 34 1.1 christos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 35 1.1 christos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 36 1.1 christos * SUCH DAMAGE. 37 1.1 christos */ 38 1.1 christos 39 1.2 christos #include <sys/cdefs.h> 40 1.2 christos #ifndef lint 41 1.7 christos __RCSID("$NetBSD: addrtostr.c,v 1.7 2026/03/19 00:05:13 christos Exp $"); 42 1.2 christos #endif 43 1.2 christos 44 1.5 christos #include <config.h> 45 1.1 christos 46 1.5 christos #include "netdissect-stdinc.h" 47 1.1 christos #include "addrtostr.h" 48 1.1 christos 49 1.1 christos #include <stdio.h> 50 1.1 christos #include <string.h> 51 1.1 christos 52 1.1 christos /* 53 1.1 christos * 54 1.1 christos */ 55 1.1 christos 56 1.1 christos #ifndef IN6ADDRSZ 57 1.1 christos #define IN6ADDRSZ 16 /* IPv6 T_AAAA */ 58 1.1 christos #endif 59 1.1 christos 60 1.1 christos #ifndef INT16SZ 61 1.1 christos #define INT16SZ 2 /* word size */ 62 1.1 christos #endif 63 1.1 christos 64 1.1 christos const char * 65 1.1 christos addrtostr (const void *src, char *dst, size_t size) 66 1.1 christos { 67 1.1 christos const u_char *srcaddr = (const u_char *)src; 68 1.1 christos const char digits[] = "0123456789"; 69 1.1 christos int i; 70 1.1 christos const char *orig_dst = dst; 71 1.1 christos 72 1.1 christos if (size < INET_ADDRSTRLEN) { 73 1.1 christos errno = ENOSPC; 74 1.1 christos return NULL; 75 1.1 christos } 76 1.1 christos for (i = 0; i < 4; ++i) { 77 1.5 christos int n = *srcaddr++; 78 1.1 christos int non_zerop = 0; 79 1.1 christos 80 1.1 christos if (non_zerop || n / 100 > 0) { 81 1.1 christos *dst++ = digits[n / 100]; 82 1.1 christos n %= 100; 83 1.1 christos non_zerop = 1; 84 1.1 christos } 85 1.1 christos if (non_zerop || n / 10 > 0) { 86 1.1 christos *dst++ = digits[n / 10]; 87 1.1 christos n %= 10; 88 1.1 christos non_zerop = 1; 89 1.1 christos } 90 1.1 christos *dst++ = digits[n]; 91 1.1 christos if (i != 3) 92 1.1 christos *dst++ = '.'; 93 1.1 christos } 94 1.1 christos *dst++ = '\0'; 95 1.1 christos return orig_dst; 96 1.1 christos } 97 1.1 christos 98 1.1 christos /* 99 1.1 christos * Convert IPv6 binary address into presentation (printable) format. 100 1.1 christos */ 101 1.1 christos const char * 102 1.1 christos addrtostr6 (const void *src, char *dst, size_t size) 103 1.1 christos { 104 1.1 christos /* 105 1.1 christos * Note that int32_t and int16_t need only be "at least" large enough 106 1.1 christos * to contain a value of the specified size. On some systems, like 107 1.1 christos * Crays, there is no such thing as an integer variable with 16 bits. 108 1.1 christos * Keep this in mind if you think this function should have been coded 109 1.1 christos * to use pointer overlays. All the world's not a VAX. 110 1.1 christos */ 111 1.1 christos const u_char *srcaddr = (const u_char *)src; 112 1.3 spz char *dp; 113 1.3 spz size_t space_left, added_space; 114 1.3 spz int snprintfed; 115 1.1 christos struct { 116 1.4 christos int base; 117 1.4 christos int len; 118 1.1 christos } best, cur; 119 1.4 christos uint16_t words [IN6ADDRSZ / INT16SZ]; 120 1.4 christos int i; 121 1.1 christos 122 1.1 christos /* Preprocess: 123 1.1 christos * Copy the input (bytewise) array into a wordwise array. 124 1.1 christos * Find the longest run of 0x00's in src[] for :: shorthanding. 125 1.1 christos */ 126 1.4 christos for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) 127 1.4 christos words[i] = (srcaddr[2*i] << 8) | srcaddr[2*i + 1]; 128 1.1 christos 129 1.1 christos best.len = 0; 130 1.1 christos best.base = -1; 131 1.1 christos cur.len = 0; 132 1.1 christos cur.base = -1; 133 1.6 christos for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 134 1.6 christos if (words[i] == 0) { 135 1.7 christos if (cur.base == -1) { 136 1.7 christos cur.base = i; 137 1.7 christos cur.len = 1; 138 1.7 christos } else 139 1.7 christos cur.len++; 140 1.6 christos } else if (cur.base != -1) { 141 1.1 christos if (best.base == -1 || cur.len > best.len) 142 1.1 christos best = cur; 143 1.1 christos cur.base = -1; 144 1.1 christos } 145 1.1 christos } 146 1.1 christos if ((cur.base != -1) && (best.base == -1 || cur.len > best.len)) 147 1.1 christos best = cur; 148 1.1 christos if (best.base != -1 && best.len < 2) 149 1.1 christos best.base = -1; 150 1.1 christos 151 1.1 christos /* Format the result. 152 1.1 christos */ 153 1.3 spz dp = dst; 154 1.3 spz space_left = size; 155 1.3 spz #define APPEND_CHAR(c) \ 156 1.3 spz { \ 157 1.3 spz if (space_left == 0) { \ 158 1.3 spz errno = ENOSPC; \ 159 1.3 spz return (NULL); \ 160 1.3 spz } \ 161 1.3 spz *dp++ = c; \ 162 1.3 spz space_left--; \ 163 1.3 spz } 164 1.6 christos for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) { 165 1.1 christos /* Are we inside the best run of 0x00's? 166 1.1 christos */ 167 1.6 christos if (best.base != -1 && i >= best.base && i < (best.base + best.len)) { 168 1.1 christos if (i == best.base) 169 1.5 christos APPEND_CHAR(':'); 170 1.1 christos continue; 171 1.1 christos } 172 1.1 christos 173 1.1 christos /* Are we following an initial run of 0x00s or any real hex? 174 1.1 christos */ 175 1.1 christos if (i != 0) 176 1.3 spz APPEND_CHAR(':'); 177 1.1 christos 178 1.1 christos /* Is this address an encapsulated IPv4? 179 1.1 christos */ 180 1.1 christos if (i == 6 && best.base == 0 && 181 1.1 christos (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) 182 1.1 christos { 183 1.6 christos if (!addrtostr(srcaddr+12, dp, space_left)) { 184 1.1 christos errno = ENOSPC; 185 1.1 christos return (NULL); 186 1.1 christos } 187 1.3 spz added_space = strlen(dp); 188 1.3 spz dp += added_space; 189 1.3 spz space_left -= added_space; 190 1.1 christos break; 191 1.1 christos } 192 1.4 christos snprintfed = snprintf (dp, space_left, "%x", words[i]); 193 1.3 spz if (snprintfed < 0) 194 1.3 spz return (NULL); 195 1.6 christos if ((size_t) snprintfed >= space_left) { 196 1.3 spz errno = ENOSPC; 197 1.3 spz return (NULL); 198 1.3 spz } 199 1.3 spz dp += snprintfed; 200 1.3 spz space_left -= snprintfed; 201 1.1 christos } 202 1.1 christos 203 1.1 christos /* Was it a trailing run of 0x00's? 204 1.1 christos */ 205 1.1 christos if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ)) 206 1.3 spz APPEND_CHAR(':'); 207 1.3 spz APPEND_CHAR('\0'); 208 1.1 christos 209 1.3 spz return (dst); 210 1.1 christos } 211