Libinfo-330.10.tar.gz
[apple/libinfo.git] / gen.subproj / inet_pton.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 #if defined(LIBC_SCCS) && !defined(lint)
19 static char rcsid[] = "$Id: inet_pton.c,v 1.3 2003/04/10 18:53:29 majka Exp $";
20 #endif /* LIBC_SCCS and not lint */
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <sys/param.h>
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
31 #include <net/if.h>
32 #include <arpa/nameser.h>
33 #include <string.h>
34 #include <stdlib.h>
35 #include <errno.h>
36
37 #define IN6ADDRSZ 16
38
39 #if 0
40 #ifndef HAVE_PORTABLE_PROTOTYPE
41 #include "cdecl_ext.h"
42 #endif
43
44 #ifndef HAVE_U_INT16_T
45 #include "bittypes.h"
46 #endif
47 #if !(defined(HAVE_INADDRSZ) && defined(HAVE_IN6ADDRSZ))
48 #include "addrsize.h"
49 #endif
50 #endif
51 #ifndef NS_INADDRSZ
52 #define NS_INADDRSZ INADDRSZ
53 #endif
54 #ifndef NS_IN6ADDRSZ
55 #define NS_IN6ADDRSZ IN6ADDRSZ
56 #endif
57 #ifndef NS_INT16SZ
58 #define NS_INT16SZ sizeof(u_int16_t)
59 #endif
60
61 /*
62 * WARNING: Don't even consider trying to compile this on a system where
63 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
64 */
65
66 static int inet_pton4 __P((const char *src, u_char *dst));
67 #ifdef INET6
68 static int inet_pton6 __P((const char *src, u_char *dst));
69 #endif
70
71 /* int
72 * inet_pton(af, src, dst)
73 * convert from presentation format (which usually means ASCII printable)
74 * to network format (which is usually some kind of binary format).
75 * return:
76 * 1 if the address was valid for the specified address family
77 * 0 if the address wasn't valid (`dst' is untouched in this case)
78 * -1 if some other error occurred (`dst' is untouched in this case, too)
79 * author:
80 * Paul Vixie, 1996.
81 */
82 int
83 inet_pton(int af, const char *src, void *dst)
84 {
85 int status;
86 unsigned short ifnum;
87 char *p, *s;
88
89 switch (af)
90 {
91 case AF_INET:
92 {
93 return (inet_pton4(src, dst));
94 }
95
96 #ifdef INET6
97 case AF_INET6:
98 {
99 ifnum = 0;
100 p = NULL;
101 s = (char *)src;
102
103 if (src != NULL) p = strrchr(src, '%');
104 if (p != NULL)
105 {
106 s = strdup(src);
107 if (s == NULL)
108 {
109 errno = ENOMEM;
110 return -1;
111 }
112
113 s[p - src] = '\0';
114 }
115
116 status = inet_pton6(s, dst);
117 if (p != NULL) free(s);
118 if (status != 1) return status;
119
120 if ((p != NULL) && IN6_IS_ADDR_LINKLOCAL((struct in6_addr *)dst))
121 {
122 ifnum = if_nametoindex(++p);
123 ifnum = htons(ifnum);
124 ((struct in6_addr *)dst)->__u6_addr.__u6_addr16[1] = ifnum;
125 }
126
127 return 1;
128 }
129 #endif
130
131 default:
132 {
133 errno = EAFNOSUPPORT;
134 return -1;
135 }
136 }
137
138 /* NOTREACHED */
139 return -1;
140 }
141
142 /* int
143 * inet_pton4(src, dst)
144 * like inet_aton() but without all the hexadecimal and shorthand.
145 * return:
146 * 1 if `src' is a valid dotted quad, else 0.
147 * notice:
148 * does not touch `dst' unless it's returning 1.
149 * author:
150 * Paul Vixie, 1996.
151 */
152 static int
153 inet_pton4(const char *src, u_char *dst)
154 {
155 static const char digits[] = "0123456789";
156 int saw_digit, octets, ch;
157 u_char tmp[NS_INADDRSZ], *tp;
158
159 saw_digit = 0;
160 octets = 0;
161 *(tp = tmp) = 0;
162 while ((ch = *src++) != '\0') {
163 const char *pch;
164
165 if ((pch = strchr(digits, ch)) != NULL) {
166 u_int new = *tp * 10 + (pch - digits);
167
168 if (new > 255)
169 return (0);
170 *tp = new;
171 if (! saw_digit) {
172 if (++octets > 4)
173 return (0);
174 saw_digit = 1;
175 }
176 } else if (ch == '.' && saw_digit) {
177 if (octets == 4)
178 return (0);
179 *++tp = 0;
180 saw_digit = 0;
181 } else
182 return (0);
183 }
184 if (octets < 4)
185 return (0);
186 memcpy(dst, tmp, NS_INADDRSZ);
187 return (1);
188 }
189
190 #ifdef INET6
191 /* int
192 * inet_pton6(src, dst)
193 * convert presentation level address to network order binary form.
194 * return:
195 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
196 * notice:
197 * (1) does not touch `dst' unless it's returning 1.
198 * (2) :: in a full address is silently ignored.
199 * credit:
200 * inspired by Mark Andrews.
201 * author:
202 * Paul Vixie, 1996.
203 */
204 static int
205 inet_pton6(const char *src, u_char *dst)
206 {
207 static const char xdigits_l[] = "0123456789abcdef",
208 xdigits_u[] = "0123456789ABCDEF";
209 u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
210 const char *xdigits, *curtok;
211 int ch, saw_xdigit;
212 u_int val;
213
214 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
215 endp = tp + NS_IN6ADDRSZ;
216 colonp = NULL;
217 /* Leading :: requires some special handling. */
218 if (*src == ':')
219 if (*++src != ':')
220 return (0);
221 curtok = src;
222 saw_xdigit = 0;
223 val = 0;
224 while ((ch = *src++) != '\0') {
225 const char *pch;
226
227 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
228 pch = strchr((xdigits = xdigits_u), ch);
229 if (pch != NULL) {
230 val <<= 4;
231 val |= (pch - xdigits);
232 if (val > 0xffff)
233 return (0);
234 saw_xdigit = 1;
235 continue;
236 }
237 if (ch == ':') {
238 curtok = src;
239 if (!saw_xdigit) {
240 if (colonp)
241 return (0);
242 colonp = tp;
243 continue;
244 } else if (*src == '\0') {
245 return (0);
246 }
247 if (tp + NS_INT16SZ > endp)
248 return (0);
249 *tp++ = (u_char) (val >> 8) & 0xff;
250 *tp++ = (u_char) val & 0xff;
251 saw_xdigit = 0;
252 val = 0;
253 continue;
254 }
255 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
256 inet_pton4(curtok, tp) > 0) {
257 tp += NS_INADDRSZ;
258 saw_xdigit = 0;
259 break; /* '\0' was seen by inet_pton4(). */
260 }
261 return (0);
262 }
263 if (saw_xdigit) {
264 if (tp + NS_INT16SZ > endp)
265 return (0);
266 *tp++ = (u_char) (val >> 8) & 0xff;
267 *tp++ = (u_char) val & 0xff;
268 }
269 if (colonp != NULL) {
270 /*
271 * Since some memmove()'s erroneously fail to handle
272 * overlapping regions, we'll do the shift by hand.
273 */
274 const int n = tp - colonp;
275 int i;
276
277 if (tp == endp)
278 return (0);
279 for (i = 1; i <= n; i++) {
280 endp[- i] = colonp[n - i];
281 colonp[n - i] = 0;
282 }
283 tp = endp;
284 }
285 if (tp != endp)
286 return (0);
287 memcpy(dst, tmp, NS_IN6ADDRSZ);
288 return (1);
289 }
290 #endif /*INET6*/