]> git.saurik.com Git - apple/libc.git/blob - net/inet_net_pton-fbsd.c
fc122b86317a8527e5c5fa2797e0abc973d40370
[apple/libc.git] / net / inet_net_pton-fbsd.c
1 /*
2 * Copyright (c) 1996 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 const char orig_rcsid[] = "From Id: inet_net_pton.c,v 1.8 1996/11/21 10:28:12 vixie Exp $";
20 #endif
21 #include <sys/cdefs.h>
22 __FBSDID("$FreeBSD: src/lib/libc/net/inet_net_pton.c,v 1.9 2003/09/15 23:38:06 fenner Exp $");
23
24 #include "xlocale_private.h"
25
26 #include <sys/types.h>
27 #include <sys/socket.h>
28 #include <netinet/in.h>
29 #include <arpa/inet.h>
30
31 #include <assert.h>
32 #include <ctype.h>
33 #include <errno.h>
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37
38 #ifdef SPRINTF_CHAR
39 # define SPRINTF(x) strlen(sprintf/**/x)
40 #else
41 # define SPRINTF(x) ((size_t)sprintf x)
42 #endif
43
44 static int inet_net_pton_ipv4(const char *src, u_char *dst, size_t size);
45
46 /*
47 * static int
48 * inet_net_pton(af, src, dst, size)
49 * convert network number from presentation to network format.
50 * accepts hex octets, hex strings, decimal octets, and /CIDR.
51 * "size" is in bytes and describes "dst".
52 * return:
53 * number of bits, either imputed classfully or specified with /CIDR,
54 * or -1 if some failure occurred (check errno). ENOENT means it was
55 * not a valid network specification.
56 * author:
57 * Paul Vixie (ISC), June 1996
58 */
59 int
60 inet_net_pton(af, src, dst, size)
61 int af;
62 const char *src;
63 void *dst;
64 size_t size;
65 {
66 switch (af) {
67 case AF_INET:
68 return (inet_net_pton_ipv4(src, dst, size));
69 default:
70 errno = EAFNOSUPPORT;
71 return (-1);
72 }
73 }
74
75 /*
76 * static int
77 * inet_net_pton_ipv4(src, dst, size)
78 * convert IPv4 network number from presentation to network format.
79 * accepts hex octets, hex strings, decimal octets, and /CIDR.
80 * "size" is in bytes and describes "dst".
81 * return:
82 * number of bits, either imputed classfully or specified with /CIDR,
83 * or -1 if some failure occurred (check errno). ENOENT means it was
84 * not an IPv4 network specification.
85 * note:
86 * network byte order assumed. this means 192.5.5.240/28 has
87 * 0x11110000 in its fourth octet.
88 * author:
89 * Paul Vixie (ISC), June 1996
90 */
91 static int
92 inet_net_pton_ipv4(src, dst, size)
93 const char *src;
94 u_char *dst;
95 size_t size;
96 {
97 static const char
98 xdigits[] = "0123456789abcdef",
99 digits[] = "0123456789";
100 int n, ch, tmp, dirty, bits;
101 const u_char *odst = dst;
102 locale_t loc = __current_locale();
103
104 ch = *src++;
105 if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
106 && isascii(src[1]) && isxdigit_l(src[1], loc)) {
107 /* Hexadecimal: Eat nybble string. */
108 if (size <= 0)
109 goto emsgsize;
110 *dst = 0, dirty = 0;
111 src++; /* skip x or X. */
112 while ((ch = *src++) != '\0' &&
113 isascii(ch) && isxdigit_l(ch, loc)) {
114 if (isupper_l(ch, loc))
115 ch = tolower_l(ch, loc);
116 n = strchr(xdigits, ch) - xdigits;
117 assert(n >= 0 && n <= 15);
118 *dst |= n;
119 if (!dirty++)
120 *dst <<= 4;
121 else if (size-- > 0)
122 *++dst = 0, dirty = 0;
123 else
124 goto emsgsize;
125 }
126 if (dirty)
127 size--;
128 } else if (isascii(ch) && isdigit_l(ch, loc)) {
129 /* Decimal: eat dotted digit string. */
130 for (;;) {
131 tmp = 0;
132 do {
133 n = strchr(digits, ch) - digits;
134 assert(n >= 0 && n <= 9);
135 tmp *= 10;
136 tmp += n;
137 if (tmp > 255)
138 goto enoent;
139 } while ((ch = *src++) != '\0' &&
140 isascii(ch) && isdigit_l(ch, loc));
141 if (size-- <= 0)
142 goto emsgsize;
143 *dst++ = (u_char) tmp;
144 if (ch == '\0' || ch == '/')
145 break;
146 if (ch != '.')
147 goto enoent;
148 ch = *src++;
149 if (!isascii(ch) || !isdigit_l(ch, loc))
150 goto enoent;
151 }
152 } else
153 goto enoent;
154
155 bits = -1;
156 if (ch == '/' && isascii(src[0]) && isdigit_l(src[0], loc) && dst > odst) {
157 /* CIDR width specifier. Nothing can follow it. */
158 ch = *src++; /* Skip over the /. */
159 bits = 0;
160 do {
161 n = strchr(digits, ch) - digits;
162 assert(n >= 0 && n <= 9);
163 bits *= 10;
164 bits += n;
165 } while ((ch = *src++) != '\0' && isascii(ch) && isdigit_l(ch, loc));
166 if (ch != '\0')
167 goto enoent;
168 if (bits > 32)
169 goto emsgsize;
170 }
171
172 /* Firey death and destruction unless we prefetched EOS. */
173 if (ch != '\0')
174 goto enoent;
175
176 /* If nothing was written to the destination, we found no address. */
177 if (dst == odst)
178 goto enoent;
179 /* If no CIDR spec was given, infer width from net class. */
180 if (bits == -1) {
181 if (*odst >= 240) /* Class E */
182 bits = 32;
183 else if (*odst >= 224) /* Class D */
184 bits = 4;
185 else if (*odst >= 192) /* Class C */
186 bits = 24;
187 else if (*odst >= 128) /* Class B */
188 bits = 16;
189 else /* Class A */
190 bits = 8;
191 /* If imputed mask is narrower than specified octets, widen. */
192 if (bits < ((dst - odst) * 8))
193 bits = (dst - odst) * 8;
194 }
195 /* Extend network to cover the actual mask. */
196 while (bits > ((dst - odst) * 8)) {
197 if (size-- <= 0)
198 goto emsgsize;
199 *dst++ = '\0';
200 }
201 return (bits);
202
203 enoent:
204 errno = ENOENT;
205 return (-1);
206
207 emsgsize:
208 errno = EMSGSIZE;
209 return (-1);
210 }
211
212 /*
213 * Weak aliases for applications that use certain private entry points,
214 * and fail to include <arpa/inet.h>.
215 */
216 #undef inet_net_pton
217 __weak_reference(__inet_net_pton, inet_net_pton);