]>
Commit | Line | Data |
---|---|---|
6465356a A |
1 | |
2 | #include <sys/types.h> | |
3 | #include <netinet/in.h> | |
4 | #include <arpa/inet.h> | |
5 | #include <stdio.h> | |
6 | #include <stdint.h> | |
7 | #include <string.h> | |
8 | #include <errno.h> | |
9 | #include <sys/socket.h> | |
10 | ||
11 | #define MAX_V4_ADDR_LEN 16 | |
12 | #define MAX_V6_ADDR_LEN 64 | |
13 | ||
14 | static const char *hexchars = "0123456789abcdef"; | |
15 | ||
16 | const char * | |
17 | inet_ntop6(const struct in6_addr *addr, char *dst, socklen_t size) | |
18 | { | |
19 | char hexa[8][5], tmp[MAX_V6_ADDR_LEN]; | |
20 | int zr[8]; | |
21 | socklen_t len; | |
22 | int32_t i, j, k, skip; | |
23 | uint8_t x8, hx8; | |
24 | uint16_t x16; | |
25 | struct in_addr a4; | |
26 | ||
27 | if (addr == NULL) | |
28 | { | |
29 | errno = EAFNOSUPPORT; | |
30 | return NULL; | |
31 | } | |
32 | ||
33 | if (dst == NULL) | |
34 | { | |
35 | errno = ENOSPC; | |
36 | return NULL; | |
37 | } | |
38 | ||
39 | memset(tmp, 0, MAX_V6_ADDR_LEN); | |
40 | ||
41 | /* check for mapped or compat addresses */ | |
42 | i = IN6_IS_ADDR_V4MAPPED(addr); | |
43 | j = IN6_IS_ADDR_V4COMPAT(addr); | |
44 | if ((i != 0) || (j != 0)) | |
45 | { | |
46 | a4.s_addr = addr->__u6_addr.__u6_addr32[3]; | |
47 | sprintf(tmp, "::%s%s", (i != 0) ? "ffff:" : "", inet_ntoa(a4)); | |
48 | len = strlen(tmp) + 1; | |
49 | if (len > size) | |
50 | { | |
51 | errno = ENOSPC; | |
52 | return NULL; | |
53 | } | |
54 | ||
55 | memcpy(dst, tmp, len); | |
56 | return dst; | |
57 | } | |
58 | ||
59 | k = 0; | |
60 | for (i = 0; i < 16; i += 2) | |
61 | { | |
62 | j = 0; | |
63 | skip = 1; | |
64 | ||
65 | memset(hexa[k], 0, 5); | |
66 | ||
67 | x8 = addr->__u6_addr.__u6_addr8[i]; | |
68 | ||
69 | hx8 = x8 >> 4; | |
70 | if (hx8 != 0) | |
71 | { | |
72 | skip = 0; | |
73 | hexa[k][j++] = hexchars[hx8]; | |
74 | } | |
75 | ||
76 | hx8 = x8 & 0x0f; | |
77 | if ((skip == 0) || ((skip == 1) && (hx8 != 0))) | |
78 | { | |
79 | skip = 0; | |
80 | hexa[k][j++] = hexchars[hx8]; | |
81 | } | |
82 | ||
83 | x8 = addr->__u6_addr.__u6_addr8[i + 1]; | |
84 | ||
85 | hx8 = x8 >> 4; | |
86 | if ((skip == 0) || ((skip == 1) && (hx8 != 0))) | |
87 | { | |
88 | hexa[k][j++] = hexchars[hx8]; | |
89 | } | |
90 | ||
91 | hx8 = x8 & 0x0f; | |
92 | hexa[k][j++] = hexchars[hx8]; | |
93 | ||
94 | k++; | |
95 | } | |
96 | ||
97 | /* find runs of zeros for :: convention */ | |
98 | j = 0; | |
99 | for (i = 7; i >= 0; i--) | |
100 | { | |
101 | zr[i] = j; | |
102 | x16 = addr->__u6_addr.__u6_addr16[i]; | |
103 | if (x16 == 0) j++; | |
104 | else j = 0; | |
105 | zr[i] = j; | |
106 | } | |
107 | ||
108 | /* find longest run of zeros */ | |
109 | k = -1; | |
110 | j = 0; | |
111 | for(i = 0; i < 8; i++) | |
112 | { | |
113 | if (zr[i] > j) | |
114 | { | |
115 | k = i; | |
116 | j = zr[i]; | |
117 | } | |
118 | } | |
119 | ||
120 | for(i = 0; i < 8; i++) | |
121 | { | |
122 | if (i != k) zr[i] = 0; | |
123 | } | |
124 | ||
125 | len = 0; | |
126 | for (i = 0; i < 8; i++) | |
127 | { | |
128 | if (zr[i] != 0) | |
129 | { | |
130 | /* check for leading zero */ | |
131 | if (i == 0) tmp[len++] = ':'; | |
132 | tmp[len++] = ':'; | |
133 | i += (zr[i] - 1); | |
134 | continue; | |
135 | } | |
136 | for (j = 0; hexa[i][j] != '\0'; j++) tmp[len++] = hexa[i][j]; | |
137 | if (i != 7) tmp[len++] = ':'; | |
138 | } | |
139 | ||
140 | /* trailing NULL */ | |
141 | len++; | |
142 | ||
143 | if (len > size) | |
144 | { | |
145 | errno = ENOSPC; | |
146 | return NULL; | |
147 | } | |
148 | ||
149 | memcpy(dst, tmp, len); | |
150 | return dst; | |
151 | } | |
152 | ||
153 | const char * | |
154 | inet_ntop4(const struct in_addr *addr, char *dst, socklen_t size) | |
155 | { | |
156 | char tmp[MAX_V4_ADDR_LEN], *p; | |
157 | const u_int8_t *ap = (u_int8_t *)&addr->s_addr; | |
158 | int i, ql, len; | |
159 | ||
160 | if (addr == NULL) | |
161 | { | |
162 | errno = EAFNOSUPPORT; | |
163 | return NULL; | |
164 | } | |
165 | ||
166 | if (dst == NULL) | |
167 | { | |
168 | errno = ENOSPC; | |
169 | return NULL; | |
170 | } | |
171 | ||
172 | memset(tmp, 0, MAX_V4_ADDR_LEN); | |
173 | ||
174 | /* 3 dots, trailing nul */ | |
175 | len = 4; | |
176 | ||
177 | p = tmp; | |
178 | ||
179 | for (i = 0; i < 4; i++, ap++) | |
180 | { | |
181 | snprintf(p, 4, "%d", *ap); | |
182 | ql = strlen(p); | |
183 | len += ql; | |
184 | p += ql; | |
185 | if (i < 3) *p++ = '.'; | |
186 | } | |
187 | ||
188 | if (len > size) | |
189 | { | |
190 | errno = ENOSPC; | |
191 | return NULL; | |
192 | } | |
193 | ||
194 | memcpy(dst, tmp, len); | |
195 | return dst; | |
196 | } | |
197 | ||
198 | const char * | |
199 | inet_ntop(int af, const void *addr, char *buf, socklen_t len) | |
200 | { | |
201 | if (af == AF_INET6) return inet_ntop6(addr, buf, len); | |
202 | if (af == AF_INET) return inet_ntop4(addr, buf, len); | |
203 | ||
204 | errno = EAFNOSUPPORT; | |
205 | return NULL; | |
206 | } |