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