Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / ntp / dist / lib / isc / inet_pton.c
blobc637002bd8ad27bc56385ce1f8992656e850f40e
1 /* $NetBSD$ */
3 /*
4 * Copyright (C) 2004, 2005, 2007 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1996-2003 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /*! \file */
22 #if defined(LIBC_SCCS) && !defined(lint)
23 static char rcsid[] =
24 "Id: inet_pton.c,v 1.19 2007/06/19 23:47:17 tbox Exp";
25 #endif /* LIBC_SCCS and not lint */
27 #include <config.h>
29 #include <errno.h>
30 #include <string.h>
32 #include <isc/net.h>
34 /*% INT16 Size */
35 #define NS_INT16SZ 2
36 /*% IPv4 Address Size */
37 #define NS_INADDRSZ 4
38 /*% IPv6 Address Size */
39 #define NS_IN6ADDRSZ 16
42 * WARNING: Don't even consider trying to compile this on a system where
43 * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
46 static int inet_pton4(const char *src, unsigned char *dst);
47 static int inet_pton6(const char *src, unsigned char *dst);
49 /*%
50 * convert from presentation format (which usually means ASCII printable)
51 * to network format (which is usually some kind of binary format).
52 * \return
53 * 1 if the address was valid for the specified address family
54 * 0 if the address wasn't valid (`dst' is untouched in this case)
55 * -1 if some other error occurred (`dst' is untouched in this case, too)
56 * \author
57 * Paul Vixie, 1996.
59 int
60 isc_net_pton(int af, const char *src, void *dst) {
61 switch (af) {
62 case AF_INET:
63 return (inet_pton4(src, dst));
64 case AF_INET6:
65 return (inet_pton6(src, dst));
66 default:
67 errno = EAFNOSUPPORT;
68 return (-1);
70 /* NOTREACHED */
73 /*!\fn static int inet_pton4(const char *src, unsigned char *dst)
74 * \brief
75 * like inet_aton() but without all the hexadecimal and shorthand.
76 * \return
77 * 1 if `src' is a valid dotted quad, else 0.
78 * \note
79 * does not touch `dst' unless it's returning 1.
80 * \author
81 * Paul Vixie, 1996.
83 static int
84 inet_pton4(const char *src, unsigned char *dst) {
85 static const char digits[] = "0123456789";
86 int saw_digit, octets, ch;
87 unsigned char tmp[NS_INADDRSZ], *tp;
89 saw_digit = 0;
90 octets = 0;
91 *(tp = tmp) = 0;
92 while ((ch = *src++) != '\0') {
93 const char *pch;
95 if ((pch = strchr(digits, ch)) != NULL) {
96 unsigned int new = *tp * 10 + (pch - digits);
98 if (saw_digit && *tp == 0)
99 return (0);
100 if (new > 255)
101 return (0);
102 *tp = new;
103 if (!saw_digit) {
104 if (++octets > 4)
105 return (0);
106 saw_digit = 1;
108 } else if (ch == '.' && saw_digit) {
109 if (octets == 4)
110 return (0);
111 *++tp = 0;
112 saw_digit = 0;
113 } else
114 return (0);
116 if (octets < 4)
117 return (0);
118 memcpy(dst, tmp, NS_INADDRSZ);
119 return (1);
123 * convert presentation level address to network order binary form.
124 * \return
125 * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
126 * \note
127 * (1) does not touch `dst' unless it's returning 1.
128 * \note
129 * (2) :: in a full address is silently ignored.
130 * \author
131 * inspired by Mark Andrews.
132 * \author
133 * Paul Vixie, 1996.
135 static int
136 inet_pton6(const char *src, unsigned char *dst) {
137 static const char xdigits_l[] = "0123456789abcdef",
138 xdigits_u[] = "0123456789ABCDEF";
139 unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
140 const char *xdigits, *curtok;
141 int ch, seen_xdigits;
142 unsigned int val;
144 memset((tp = tmp), '\0', NS_IN6ADDRSZ);
145 endp = tp + NS_IN6ADDRSZ;
146 colonp = NULL;
147 /* Leading :: requires some special handling. */
148 if (*src == ':')
149 if (*++src != ':')
150 return (0);
151 curtok = src;
152 seen_xdigits = 0;
153 val = 0;
154 while ((ch = *src++) != '\0') {
155 const char *pch;
157 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
158 pch = strchr((xdigits = xdigits_u), ch);
159 if (pch != NULL) {
160 val <<= 4;
161 val |= (pch - xdigits);
162 if (++seen_xdigits > 4)
163 return (0);
164 continue;
166 if (ch == ':') {
167 curtok = src;
168 if (!seen_xdigits) {
169 if (colonp)
170 return (0);
171 colonp = tp;
172 continue;
174 if (tp + NS_INT16SZ > endp)
175 return (0);
176 *tp++ = (unsigned char) (val >> 8) & 0xff;
177 *tp++ = (unsigned char) val & 0xff;
178 seen_xdigits = 0;
179 val = 0;
180 continue;
182 if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
183 inet_pton4(curtok, tp) > 0) {
184 tp += NS_INADDRSZ;
185 seen_xdigits = 0;
186 break; /* '\0' was seen by inet_pton4(). */
188 return (0);
190 if (seen_xdigits) {
191 if (tp + NS_INT16SZ > endp)
192 return (0);
193 *tp++ = (unsigned char) (val >> 8) & 0xff;
194 *tp++ = (unsigned char) val & 0xff;
196 if (colonp != NULL) {
198 * Since some memmove()'s erroneously fail to handle
199 * overlapping regions, we'll do the shift by hand.
201 const int n = tp - colonp;
202 int i;
204 if (tp == endp)
205 return (0);
206 for (i = 1; i <= n; i++) {
207 endp[- i] = colonp[n - i];
208 colonp[n - i] = 0;
210 tp = endp;
212 if (tp != endp)
213 return (0);
214 memcpy(dst, tmp, NS_IN6ADDRSZ);
215 return (1);