1 |
/* $NetBSD: inet_pton.c,v 1.9 2007/07/23 11:45:52 lukem Exp $ */ |
2 |
/* from NetBSD: inet_pton.c,v 1.3 2006/09/26 05:59:18 lukem Exp */ |
3 |
|
4 |
/* |
5 |
* Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") |
6 |
* Copyright (c) 1996,1999 by Internet Software Consortium. |
7 |
* |
8 |
* Permission to use, copy, modify, and distribute this software for any |
9 |
* purpose with or without fee is hereby granted, provided that the above |
10 |
* copyright notice and this permission notice appear in all copies. |
11 |
* |
12 |
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES |
13 |
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
14 |
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR |
15 |
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
16 |
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
17 |
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT |
18 |
* OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
19 |
*/ |
20 |
|
21 |
#include "tnftp.h" |
22 |
|
23 |
#if defined(HAVE_ARPA_NAMESER_H) |
24 |
# include <arpa/nameser.h> |
25 |
#endif |
26 |
#if !defined(NS_INADDRSZ) |
27 |
# define NS_INADDRSZ 4 |
28 |
#endif |
29 |
#if !defined(NS_IN6ADDRSZ) |
30 |
# define NS_IN6ADDRSZ 16 |
31 |
#endif |
32 |
#if !defined(NS_INT16SZ) |
33 |
# define NS_INT16SZ 2 |
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 int inet_pton4(const char *src, unsigned char *dst, int pton); |
42 |
#ifdef INET6 |
43 |
static int inet_pton6(const char *src, unsigned char *dst); |
44 |
#endif /* INET6 */ |
45 |
|
46 |
/* int |
47 |
* inet_pton(af, src, dst) |
48 |
* convert from presentation format (which usually means ASCII printable) |
49 |
* to network format (which is usually some kind of binary format). |
50 |
* return: |
51 |
* 1 if the address was valid for the specified address family |
52 |
* 0 if the address wasn't valid (`dst' is untouched in this case) |
53 |
* -1 if some other error occurred (`dst' is untouched in this case, too) |
54 |
* author: |
55 |
* Paul Vixie, 1996. |
56 |
*/ |
57 |
int |
58 |
inet_pton(int af, const char *src, void *dst) |
59 |
{ |
60 |
|
61 |
switch (af) { |
62 |
case AF_INET: |
63 |
return (inet_pton4(src, dst, 1)); |
64 |
#ifdef INET6 |
65 |
case AF_INET6: |
66 |
return (inet_pton6(src, dst)); |
67 |
#endif /* INET6 */ |
68 |
default: |
69 |
errno = EAFNOSUPPORT; |
70 |
return (-1); |
71 |
} |
72 |
/* NOTREACHED */ |
73 |
} |
74 |
|
75 |
/* int |
76 |
* inet_pton4(src, dst, pton) |
77 |
* when last arg is 0: inet_aton(). with hexadecimal, octal and shorthand. |
78 |
* when last arg is 1: inet_pton(). decimal dotted-quad only. |
79 |
* return: |
80 |
* 1 if `src' is a valid input, else 0. |
81 |
* notice: |
82 |
* does not touch `dst' unless it's returning 1. |
83 |
* author: |
84 |
* Paul Vixie, 1996. |
85 |
*/ |
86 |
static int |
87 |
inet_pton4(const char *src, unsigned char *dst, int pton) |
88 |
{ |
89 |
uint32_t val; |
90 |
unsigned int digit, base; |
91 |
int n; |
92 |
unsigned char c; |
93 |
unsigned int parts[4]; |
94 |
register unsigned int *pp = parts; |
95 |
|
96 |
c = *src; |
97 |
for (;;) { |
98 |
/* |
99 |
* Collect number up to ``.''. |
100 |
* Values are specified as for C: |
101 |
* 0x=hex, 0=octal, isdigit=decimal. |
102 |
*/ |
103 |
if (!isdigit(c)) |
104 |
return (0); |
105 |
val = 0; base = 10; |
106 |
if (c == '0') { |
107 |
c = *++src; |
108 |
if (c == 'x' || c == 'X') |
109 |
base = 16, c = *++src; |
110 |
else if (isdigit(c) && c != '9') |
111 |
base = 8; |
112 |
} |
113 |
/* inet_pton() takes decimal only */ |
114 |
if (pton && base != 10) |
115 |
return (0); |
116 |
for (;;) { |
117 |
if (isdigit(c)) { |
118 |
digit = c - '0'; |
119 |
if (digit >= base) |
120 |
break; |
121 |
val = (val * base) + digit; |
122 |
c = *++src; |
123 |
} else if (base == 16 && isxdigit(c)) { |
124 |
digit = c + 10 - (islower(c) ? 'a' : 'A'); |
125 |
if (digit >= 16) |
126 |
break; |
127 |
val = (val << 4) | digit; |
128 |
c = *++src; |
129 |
} else |
130 |
break; |
131 |
} |
132 |
if (c == '.') { |
133 |
/* |
134 |
* Internet format: |
135 |
* a.b.c.d |
136 |
* a.b.c (with c treated as 16 bits) |
137 |
* a.b (with b treated as 24 bits) |
138 |
* a (with a treated as 32 bits) |
139 |
*/ |
140 |
if (pp >= parts + 3) |
141 |
return (0); |
142 |
*pp++ = val; |
143 |
c = *++src; |
144 |
} else |
145 |
break; |
146 |
} |
147 |
/* |
148 |
* Check for trailing characters. |
149 |
*/ |
150 |
if (c != '\0' && !isspace(c)) |
151 |
return (0); |
152 |
/* |
153 |
* Concoct the address according to |
154 |
* the number of parts specified. |
155 |
*/ |
156 |
n = pp - parts + 1; |
157 |
/* inet_pton() takes dotted-quad only. it does not take shorthand. */ |
158 |
if (pton && n != 4) |
159 |
return (0); |
160 |
switch (n) { |
161 |
|
162 |
case 0: |
163 |
return (0); /* initial nondigit */ |
164 |
|
165 |
case 1: /* a -- 32 bits */ |
166 |
break; |
167 |
|
168 |
case 2: /* a.b -- 8.24 bits */ |
169 |
if (parts[0] > 0xff || val > 0xffffff) |
170 |
return (0); |
171 |
val |= parts[0] << 24; |
172 |
break; |
173 |
|
174 |
case 3: /* a.b.c -- 8.8.16 bits */ |
175 |
if ((parts[0] | parts[1]) > 0xff || val > 0xffff) |
176 |
return (0); |
177 |
val |= (parts[0] << 24) | (parts[1] << 16); |
178 |
break; |
179 |
|
180 |
case 4: /* a.b.c.d -- 8.8.8.8 bits */ |
181 |
if ((parts[0] | parts[1] | parts[2] | val) > 0xff) |
182 |
return (0); |
183 |
val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); |
184 |
break; |
185 |
} |
186 |
if (dst) { |
187 |
val = htonl(val); |
188 |
memcpy(dst, &val, NS_INADDRSZ); |
189 |
} |
190 |
return (1); |
191 |
} |
192 |
|
193 |
#ifdef INET6 |
194 |
/* int |
195 |
* inet_pton6(src, dst) |
196 |
* convert presentation level address to network order binary form. |
197 |
* return: |
198 |
* 1 if `src' is a valid [RFC1884 2.2] address, else 0. |
199 |
* notice: |
200 |
* (1) does not touch `dst' unless it's returning 1. |
201 |
* (2) :: in a full address is silently ignored. |
202 |
* credit: |
203 |
* inspired by Mark Andrews. |
204 |
* author: |
205 |
* Paul Vixie, 1996. |
206 |
*/ |
207 |
static int |
208 |
inet_pton6(const char *src, unsigned char *dst) |
209 |
{ |
210 |
static const char xdigits_l[] = "0123456789abcdef", |
211 |
xdigits_u[] = "0123456789ABCDEF"; |
212 |
unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; |
213 |
const char *xdigits, *curtok; |
214 |
int ch, saw_xdigit; |
215 |
unsigned int val; |
216 |
|
217 |
memset((tp = tmp), '\0', NS_IN6ADDRSZ); |
218 |
endp = tp + NS_IN6ADDRSZ; |
219 |
colonp = NULL; |
220 |
/* Leading :: requires some special handling. */ |
221 |
if (*src == ':') |
222 |
if (*++src != ':') |
223 |
return (0); |
224 |
curtok = src; |
225 |
saw_xdigit = 0; |
226 |
val = 0; |
227 |
while ((ch = *src++) != '\0') { |
228 |
const char *pch; |
229 |
|
230 |
if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) |
231 |
pch = strchr((xdigits = xdigits_u), ch); |
232 |
if (pch != NULL) { |
233 |
val <<= 4; |
234 |
val |= (pch - xdigits); |
235 |
if (val > 0xffff) |
236 |
return (0); |
237 |
saw_xdigit = 1; |
238 |
continue; |
239 |
} |
240 |
if (ch == ':') { |
241 |
curtok = src; |
242 |
if (!saw_xdigit) { |
243 |
if (colonp) |
244 |
return (0); |
245 |
colonp = tp; |
246 |
continue; |
247 |
} else if (*src == '\0') |
248 |
return (0); |
249 |
if (tp + NS_INT16SZ > endp) |
250 |
return (0); |
251 |
*tp++ = (unsigned char) (val >> 8) & 0xff; |
252 |
*tp++ = (unsigned char) val & 0xff; |
253 |
saw_xdigit = 0; |
254 |
val = 0; |
255 |
continue; |
256 |
} |
257 |
if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && |
258 |
inet_pton4(curtok, tp, 1) > 0) { |
259 |
tp += NS_INADDRSZ; |
260 |
saw_xdigit = 0; |
261 |
break; /* '\0' was seen by inet_pton4(). */ |
262 |
} |
263 |
return (0); |
264 |
} |
265 |
if (saw_xdigit) { |
266 |
if (tp + NS_INT16SZ > endp) |
267 |
return (0); |
268 |
*tp++ = (unsigned char) (val >> 8) & 0xff; |
269 |
*tp++ = (unsigned char) val & 0xff; |
270 |
} |
271 |
if (colonp != NULL) { |
272 |
/* |
273 |
* Since some memmove()'s erroneously fail to handle |
274 |
* overlapping regions, we'll do the shift by hand. |
275 |
*/ |
276 |
const int n = tp - colonp; |
277 |
int i; |
278 |
|
279 |
if (tp == endp) |
280 |
return (0); |
281 |
for (i = 1; i <= n; i++) { |
282 |
endp[- i] = colonp[n - i]; |
283 |
colonp[n - i] = 0; |
284 |
} |
285 |
tp = endp; |
286 |
} |
287 |
if (tp != endp) |
288 |
return (0); |
289 |
memcpy(dst, tmp, NS_IN6ADDRSZ); |
290 |
return (1); |
291 |
} |
292 |
#endif /* INET6 */ |