1 /*
2  * inet_ntop.c --
3  *   provides inet_ntop()
4  *
5  * $Id: inet_ntop.c, v 1.4 2003/11/28 20:01:23 [Xp-AvR] Exp $
6  */
7 
8 #include "main.h"
9 #include "inet_ntop.h"
10 
11 #if defined(USE_IPV6) && !defined(HAVE_INET_NTOP)
12 
13 #include <sys/param.h>
14 #include <sys/types.h>
15 #include <sys/socket.h>
16 
17 #include <netinet/in.h>
18 #include <arpa/inet.h>
19 
20 #include <errno.h>
21 #include <stdio.h>
22 #include <string.h>
23 
24 #ifdef SPRINTF_CHAR
25 # define SPRINTF(x) strlen(sprintf/**/x)
26 #else
27 # define SPRINTF(x) ((size_t)sprintf x)
28 #endif
29 
30 #define NS_INADDRSZ     4
31 #define NS_IN6ADDRSZ    16
32 #define NS_INT16SZ      2
33 
34 static const char *EvangelineInet_ntop4 (const u_char *src, char *dst, socklen_t size);
35 static const char *EvangelineInet_ntop6 (const u_char *src, char *dst, socklen_t size);
36 
EvangelineInet_ntop(af,src,dst,size)37 const char *EvangelineInet_ntop(af, src, dst, size)
38 	int af;
39 	const void *src;
40 	char *dst;
41 	socklen_t size;
42 {
43 	switch (af) {
44 	case AF_INET:
45 		return (EvangelineInet_ntop4(src, dst, size));
46 	case AF_INET6:
47 		return (EvangelineInet_ntop6(src, dst, size));
48 	default:
49 		return (NULL);
50 	}
51 }
52 
EvangelineInet_ntop4(src,dst,size)53 static const char *EvangelineInet_ntop4(src, dst, size)
54 	const u_char *src;
55 	char *dst;
56 	socklen_t size;
57 {
58 	static const char fmt[] = "%u.%u.%u.%u";
59 	char tmp[sizeof "255.255.255.255"];
60 
61 	if (SPRINTF((tmp, fmt, src[0], src[1], src[2], src[3])) > size) {
62 		return (NULL);
63 	}
64 	return strcpy(dst, tmp);
65 }
66 
EvangelineInet_ntop6(src,dst,size)67 static const char *EvangelineInet_ntop6(src, dst, size)
68 	const u_char *src;
69 	char *dst;
70 	socklen_t size;
71 {
72 	char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp;
73 	struct { int base, len; } best, cur;
74 	u_int words[NS_IN6ADDRSZ / NS_INT16SZ];
75 	int i;
76 
77 	EvangelineMemset(words, '\0', sizeof words);
78 	for (i = 0; i < NS_IN6ADDRSZ; i += 2)
79 		words[i / 2] = (src[i] << 8) | src[i + 1];
80 	best.base = -1;
81 	cur.base = -1;
82 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
83 		if (words[i] == 0) {
84 			if (cur.base == -1)
85 				cur.base = i, cur.len = 1;
86 			else
87 				cur.len++;
88 		} else {
89 			if (cur.base != -1) {
90 				if (best.base == -1 || cur.len > best.len)
91 					best = cur;
92 				cur.base = -1;
93 			}
94 		}
95 	}
96 	if (cur.base != -1) {
97 		if (best.base == -1 || cur.len > best.len)
98 			best = cur;
99 	}
100 	if (best.base != -1 && best.len < 2)
101 		best.base = -1;
102 
103 	tp = tmp;
104 	for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) {
105 		if (best.base != -1 && i >= best.base &&
106 		    i < (best.base + best.len)) {
107 			if (i == best.base)
108 				*tp++ = ':';
109 			continue;
110 		}
111 		if (i != 0)
112 			*tp++ = ':';
113 		if (i == 6 && best.base == 0 &&
114 		    (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
115 			if (!EvangelineInet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)))
116 				return (NULL);
117 			tp += strlen(tp);
118 			break;
119 		}
120 		tp += SPRINTF((tp, "%x", words[i]));
121 	}
122 	if (best.base != -1 && (best.base + best.len) ==
123 	    (NS_IN6ADDRSZ / NS_INT16SZ))
124 		*tp++ = ':';
125 	*tp++ = '\0';
126 
127 	if ((socklen_t)(tp - tmp) > size) {
128 		return (NULL);
129 	}
130 	return strcpy(dst, tmp);
131 }
132 #endif /* !HAVE_INET_NTOP */
133