(root)/
glibc-2.38/
resolv/
inet_ntop.c
       1  /*
       2   * Copyright (c) 1996-1999 by Internet Software Consortium.
       3   *
       4   * Permission to use, copy, modify, and distribute this software for any
       5   * purpose with or without fee is hereby granted, provided that the above
       6   * copyright notice and this permission notice appear in all copies.
       7   *
       8   * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
       9   * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
      10   * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
      11   * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
      12   * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
      13   * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
      14   * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
      15   * SOFTWARE.
      16   */
      17  
      18  #include <sys/param.h>
      19  #include <sys/types.h>
      20  #include <sys/socket.h>
      21  
      22  #include <netinet/in.h>
      23  #include <arpa/inet.h>
      24  #include <arpa/nameser.h>
      25  
      26  #include <errno.h>
      27  #include <stdio.h>
      28  #include <string.h>
      29  
      30  #ifdef SPRINTF_CHAR
      31  # define SPRINTF(x) strlen(sprintf/**/x)
      32  #else
      33  # define SPRINTF(x) ((size_t)sprintf x)
      34  #endif
      35  
      36  /*
      37   * WARNING: Don't even consider trying to compile this on a system where
      38   * sizeof(int) < 4.  sizeof(int) > 4 is fine; all the world's not a VAX.
      39   */
      40  
      41  static const char *inet_ntop4 (const u_char *src, char *dst, socklen_t size);
      42  static const char *inet_ntop6 (const u_char *src, char *dst, socklen_t size);
      43  
      44  /* char *
      45   * inet_ntop(af, src, dst, size)
      46   *	convert a network format address to presentation format.
      47   * return:
      48   *	pointer to presentation format address (`dst'), or NULL (see errno).
      49   * author:
      50   *	Paul Vixie, 1996.
      51   */
      52  const char *
      53  inet_ntop (int af, const void *src, char *dst, socklen_t size)
      54  {
      55  	switch (af) {
      56  	case AF_INET:
      57  		return (inet_ntop4(src, dst, size));
      58  	case AF_INET6:
      59  		return (inet_ntop6(src, dst, size));
      60  	default:
      61  		__set_errno (EAFNOSUPPORT);
      62  		return (NULL);
      63  	}
      64  	/* NOTREACHED */
      65  }
      66  libc_hidden_def (inet_ntop)
      67  
      68  /* const char *
      69   * inet_ntop4(src, dst, size)
      70   *	format an IPv4 address
      71   * return:
      72   *	`dst' (as a const)
      73   * notes:
      74   *	(1) uses no statics
      75   *	(2) takes a u_char* not an in_addr as input
      76   * author:
      77   *	Paul Vixie, 1996.
      78   */
      79  static const char *
      80  inet_ntop4 (const u_char *src, char *dst, socklen_t size)
      81  {
      82  	static const char fmt[] = "%u.%u.%u.%u";
      83  	char tmp[sizeof "255.255.255.255"];
      84  
      85  	if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) >= size) {
      86  		__set_errno (ENOSPC);
      87  		return (NULL);
      88  	}
      89  	return strcpy(dst, tmp);
      90  }
      91  
      92  /* const char *
      93   * inet_ntop6(src, dst, size)
      94   *	convert IPv6 binary address into presentation (printable) format
      95   * author:
      96   *	Paul Vixie, 1996.
      97   */
      98  static const char *
      99  inet_ntop6 (const u_char *src, char *dst, socklen_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[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
     109  	struct { int base, len; } best, cur;
     110  	u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
     111  	int i;
     112  
     113  	/*
     114  	 * Preprocess:
     115  	 *	Copy the input (bytewise) array into a wordwise array.
     116  	 *	Find the longest run of 0x00's in src[] for :: shorthanding.
     117  	 */
     118  	memset(words, '\0', sizeof words);
     119  	for (i = 0; i < NS_IN6ADDRSZ; i += 2)
     120  		words[i / 2] = (src[i] << 8) | src[i + 1];
     121  	best.base = -1;
     122  	cur.base = -1;
     123  	best.len = 0;
     124  	cur.len = 0;
     125  	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
     126  		if (words[i] == 0) {
     127  			if (cur.base == -1)
     128  				cur.base = i, cur.len = 1;
     129  			else
     130  				cur.len++;
     131  		} else {
     132  			if (cur.base != -1) {
     133  				if (best.base == -1 || cur.len > best.len)
     134  					best = cur;
     135  				cur.base = -1;
     136  			}
     137  		}
     138  	}
     139  	if (cur.base != -1) {
     140  		if (best.base == -1 || cur.len > best.len)
     141  			best = cur;
     142  	}
     143  	if (best.base != -1 && best.len < 2)
     144  		best.base = -1;
     145  
     146  	/*
     147  	 * Format the result.
     148  	 */
     149  	tp = tmp;
     150  	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
     151  		/* Are we inside the best run of 0x00's? */
     152  		if (best.base != -1 && i >= best.base &&
     153  		    i < (best.base + best.len)) {
     154  			if (i == best.base)
     155  				*tp++ = ':';
     156  			continue;
     157  		}
     158  		/* Are we following an initial run of 0x00s or any real hex? */
     159  		if (i != 0)
     160  			*tp++ = ':';
     161  		/* Is this address an encapsulated IPv4? */
     162  		if (i == 6 && best.base == 0 &&
     163  		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
     164  			if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
     165  				return (NULL);
     166  			tp += strlen(tp);
     167  			break;
     168  		}
     169  		tp += SPRINTF((tp, "%x", words[i]));
     170  	}
     171  	/* Was it a trailing run of 0x00's? */
     172  	if (best.base != -1 && (best.base + best.len) ==
     173  	    (NS_IN6ADDRSZ / NS_INT16SZ))
     174  		*tp++ = ':';
     175  	*tp++ = '\0';
     176  
     177  	/*
     178  	 * Check for overflow, copy, and we're done.
     179  	 */
     180  	if ((socklen_t)(tp - tmp) > size) {
     181  		__set_errno (ENOSPC);
     182  		return (NULL);
     183  	}
     184  	return strcpy(dst, tmp);
     185  }