xref: /netbsd-src/external/bsd/tcpdump/dist/addrtostr.c (revision 26ba0b503b498a5194a71ac319838b7f5497f3fe)
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