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