1 /* $NetBSD: inet_net_pton.c,v 1.4 2008/09/21 16:35:25 lukem Exp $ */
2 /* from	NetBSD: inet_net_pton.c,v 1.1 2004/05/20 23:13:02 christos Exp */
3 
4 /*
5  * Copyright (c) 1996,1999 by Internet Software Consortium.
6  *
7  * Permission to use, copy, modify, and 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.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
12  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
13  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
14  * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
15  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
16  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
17  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
18  * SOFTWARE.
19  */
20 
21 #include "tnftpd.h"
22 
23 
24 #ifdef SPRINTF_CHAR
25 # define SPRINTF(x) strlen(sprintf/**/x)
26 #else
27 # define SPRINTF(x) ((size_t)sprintf x)
28 #endif
29 
30 
31 /*
32  * static int
33  * inet_net_pton_ipv4(src, dst, size)
34  *	convert IPv4 network number from presentation to network format.
35  *	accepts hex octets, hex strings, decimal octets, and /CIDR.
36  *	"size" is in bytes and describes "dst".
37  * return:
38  *	number of bits, either imputed classfully or specified with /CIDR,
39  *	or -1 if some failure occurred (check errno).  ENOENT means it was
40  *	not an IPv4 network specification.
41  * note:
42  *	network byte order assumed.  this means 192.5.5.240/28 has
43  *	0b11110000 in its fourth octet.
44  * author:
45  *	Paul Vixie (ISC), June 1996
46  */
47 static int
inet_net_pton_ipv4(const char * src,unsigned char * dst,size_t size)48 inet_net_pton_ipv4( const char *src, unsigned char *dst, size_t size) {
49 	static const char xdigits[] = "0123456789abcdef";
50 	static const char digits[] = "0123456789";
51 	int n, ch, tmp = 0, dirty, bits;
52 	const unsigned char *odst = dst;
53 
54 	ch = *src++;
55 	if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
56 	    && isascii((unsigned char)(src[1]))
57 	    && isxdigit((unsigned char)(src[1]))) {
58 		/* Hexadecimal: Eat nybble string. */
59 		if (size == 0)
60 			goto emsgsize;
61 		dirty = 0;
62 		src++;	/* skip x or X. */
63 		while ((ch = *src++) != '\0' && isascii((unsigned char)ch)
64 		    && isxdigit((unsigned char)ch)) {
65 			if (isupper((unsigned char)ch))
66 				ch = tolower((unsigned char)ch);
67 			n = strchr(xdigits, ch) - xdigits;
68 			if (dirty == 0)
69 				tmp = n;
70 			else
71 				tmp = (tmp << 4) | n;
72 			if (++dirty == 2) {
73 				if (size-- == 0)
74 					goto emsgsize;
75 				*dst++ = (unsigned char) tmp;
76 				dirty = 0;
77 			}
78 		}
79 		if (dirty) {  /* Odd trailing nybble? */
80 			if (size-- == 0)
81 				goto emsgsize;
82 			*dst++ = (unsigned char) (tmp << 4);
83 		}
84 	} else if (isascii((unsigned char)ch) && isdigit((unsigned char)ch)) {
85 		/* Decimal: eat dotted digit string. */
86 		for (;;) {
87 			tmp = 0;
88 			do {
89 				n = strchr(digits, ch) - digits;
90 				tmp *= 10;
91 				tmp += n;
92 				if (tmp > 255)
93 					goto enoent;
94 			} while ((ch = *src++) != '\0' &&
95 				 isascii((unsigned char)ch) &&
96 				 isdigit((unsigned char)ch));
97 			if (size-- == 0)
98 				goto emsgsize;
99 			*dst++ = (unsigned char) tmp;
100 			if (ch == '\0' || ch == '/')
101 				break;
102 			if (ch != '.')
103 				goto enoent;
104 			ch = *src++;
105 			if (!isascii((unsigned char)ch) ||
106 			    !isdigit((unsigned char)ch))
107 				goto enoent;
108 		}
109 	} else
110 		goto enoent;
111 
112 	bits = -1;
113 	if (ch == '/' && isascii((unsigned char)(src[0])) &&
114 	    isdigit((unsigned char)(src[0])) && dst > odst) {
115 		/* CIDR width specifier.  Nothing can follow it. */
116 		ch = *src++;	/* Skip over the /. */
117 		bits = 0;
118 		do {
119 			n = strchr(digits, ch) - digits;
120 			bits *= 10;
121 			bits += n;
122 		} while ((ch = *src++) != '\0' && isascii((unsigned char)ch)
123 		    && isdigit((unsigned char)ch));
124 		if (ch != '\0')
125 			goto enoent;
126 		if (bits > 32)
127 			goto emsgsize;
128 	}
129 
130 	/* Firey death and destruction unless we prefetched EOS. */
131 	if (ch != '\0')
132 		goto enoent;
133 
134 	/* If nothing was written to the destination, we found no address. */
135 	if (dst == odst)
136 		goto enoent;
137 	/* If no CIDR spec was given, infer width from net class. */
138 	if (bits == -1) {
139 		if (*odst >= 240)	/* Class E */
140 			bits = 32;
141 		else if (*odst >= 224)	/* Class D */
142 			bits = 4;
143 		else if (*odst >= 192)	/* Class C */
144 			bits = 24;
145 		else if (*odst >= 128)	/* Class B */
146 			bits = 16;
147 		else			/* Class A */
148 			bits = 8;
149 		/* If imputed mask is narrower than specified octets, widen. */
150 		if (bits >= 8 && bits < ((dst - odst) * 8))
151 			bits = (dst - odst) * 8;
152 	}
153 	/* Extend network to cover the actual mask. */
154 	while (bits > ((dst - odst) * 8)) {
155 		if (size-- == 0)
156 			goto emsgsize;
157 		*dst++ = '\0';
158 	}
159 	return (bits);
160 
161  enoent:
162 	errno = ENOENT;
163 	return (-1);
164 
165  emsgsize:
166 	errno = EMSGSIZE;
167 	return (-1);
168 }
169 
170 #ifdef INET6
171 static int
getbits(const char * src,int * bitsp)172 getbits(const char *src, int *bitsp) {
173 	static const char digits[] = "0123456789";
174 	int n;
175 	int val;
176 	char ch;
177 
178 	val = 0;
179 	n = 0;
180 	while ((ch = *src++) != '\0') {
181 		const char *pch;
182 
183 		pch = strchr(digits, ch);
184 		if (pch != NULL) {
185 			if (n++ != 0 && val == 0)	/* no leading zeros */
186 				return (0);
187 			val *= 10;
188 			val += (pch - digits);
189 			if (val > 128)			/* range */
190 				return (0);
191 			continue;
192 		}
193 		return (0);
194 	}
195 	if (n == 0)
196 		return (0);
197 	*bitsp = val;
198 	return (1);
199 }
200 
201 static int
getv4(const char * src,unsigned char * dst,int * bitsp)202 getv4(const char *src, unsigned char *dst, int *bitsp) {
203 	static const char digits[] = "0123456789";
204 	unsigned char *odst = dst;
205 	int n;
206 	unsigned int val;
207 	char ch;
208 
209 	val = 0;
210 	n = 0;
211 	while ((ch = *src++) != '\0') {
212 		const char *pch;
213 
214 		pch = strchr(digits, ch);
215 		if (pch != NULL) {
216 			if (n++ != 0 && val == 0)	/* no leading zeros */
217 				return (0);
218 			val *= 10;
219 			val += (pch - digits);
220 			if (val > 255)			/* range */
221 				return (0);
222 			continue;
223 		}
224 		if (ch == '.' || ch == '/') {
225 			if (dst - odst > 3)		/* too many octets? */
226 				return (0);
227 			*dst++ = val;
228 			if (ch == '/')
229 				return (getbits(src, bitsp));
230 			val = 0;
231 			n = 0;
232 			continue;
233 		}
234 		return (0);
235 	}
236 	if (n == 0)
237 		return (0);
238 	if (dst - odst > 3)		/* too many octets? */
239 		return (0);
240 	*dst++ = val;
241 	return (1);
242 }
243 
244 static int
inet_net_pton_ipv6(const char * src,unsigned char * dst,size_t size)245 inet_net_pton_ipv6(const char *src, unsigned char *dst, size_t size) {
246 	static const char xdigits_l[] = "0123456789abcdef",
247 			  xdigits_u[] = "0123456789ABCDEF";
248 	unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
249 	const char *xdigits, *curtok;
250 	int ch, saw_xdigit;
251 	unsigned int val;
252 	int digits;
253 	int bits;
254 	size_t bytes;
255 	int words;
256 	int ipv4;
257 
258 	memset((tp = tmp), '\0', NS_IN6ADDRSZ);
259 	endp = tp + NS_IN6ADDRSZ;
260 	colonp = NULL;
261 	/* Leading :: requires some special handling. */
262 	if (*src == ':')
263 		if (*++src != ':')
264 			goto enoent;
265 	curtok = src;
266 	saw_xdigit = 0;
267 	val = 0;
268 	digits = 0;
269 	bits = -1;
270 	ipv4 = 0;
271 	while ((ch = *src++) != '\0') {
272 		const char *pch;
273 
274 		if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
275 			pch = strchr((xdigits = xdigits_u), ch);
276 		if (pch != NULL) {
277 			val <<= 4;
278 			val |= (pch - xdigits);
279 			if (++digits > 4)
280 				goto enoent;
281 			saw_xdigit = 1;
282 			continue;
283 		}
284 		if (ch == ':') {
285 			curtok = src;
286 			if (!saw_xdigit) {
287 				if (colonp)
288 					goto enoent;
289 				colonp = tp;
290 				continue;
291 			} else if (*src == '\0')
292 				goto enoent;
293 			if (tp + NS_INT16SZ > endp)
294 				return (0);
295 			*tp++ = (unsigned char) (val >> 8) & 0xff;
296 			*tp++ = (unsigned char) val & 0xff;
297 			saw_xdigit = 0;
298 			digits = 0;
299 			val = 0;
300 			continue;
301 		}
302 		if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
303 		     getv4(curtok, tp, &bits) > 0) {
304 			tp += NS_INADDRSZ;
305 			saw_xdigit = 0;
306 			ipv4 = 1;
307 			break;	/* '\0' was seen by inet_pton4(). */
308 		}
309 		if (ch == '/' && getbits(src, &bits) > 0)
310 			break;
311 		goto enoent;
312 	}
313 	if (saw_xdigit) {
314 		if (tp + NS_INT16SZ > endp)
315 			goto enoent;
316 		*tp++ = (unsigned char) (val >> 8) & 0xff;
317 		*tp++ = (unsigned char) val & 0xff;
318 	}
319 	if (bits == -1)
320 		bits = 128;
321 
322 	words = (bits + 15) / 16;
323 	if (words < 2)
324 		words = 2;
325 	if (ipv4)
326 		words = 8;
327 	endp =  tmp + 2 * words;
328 
329 	if (colonp != NULL) {
330 		/*
331 		 * Since some memmove()'s erroneously fail to handle
332 		 * overlapping regions, we'll do the shift by hand.
333 		 */
334 		const int n = tp - colonp;
335 		int i;
336 
337 		if (tp == endp)
338 			goto enoent;
339 		for (i = 1; i <= n; i++) {
340 			endp[- i] = colonp[n - i];
341 			colonp[n - i] = 0;
342 		}
343 		tp = endp;
344 	}
345 	if (tp != endp)
346 		goto enoent;
347 
348 	bytes = (bits + 7) / 8;
349 	if (bytes > size)
350 		goto emsgsize;
351 	memcpy(dst, tmp, bytes);
352 	return (bits);
353 
354  enoent:
355 	errno = ENOENT;
356 	return (-1);
357 
358  emsgsize:
359 	errno = EMSGSIZE;
360 	return (-1);
361 }
362 #endif /* INET6 */
363 
364 /*
365  * int
366  * inet_net_pton(af, src, dst, size)
367  *	convert network number from presentation to network format.
368  *	accepts hex octets, hex strings, decimal octets, and /CIDR.
369  *	"size" is in bytes and describes "dst".
370  * return:
371  *	number of bits, either imputed classfully or specified with /CIDR,
372  *	or -1 if some failure occurred (check errno).  ENOENT means it was
373  *	not a valid network specification.
374  * author:
375  *	Paul Vixie (ISC), June 1996
376  */
377 int
inet_net_pton(int af,const char * src,void * dst,size_t size)378 inet_net_pton(int af, const char *src, void *dst, size_t size) {
379 	switch (af) {
380 	case AF_INET:
381 		return (inet_net_pton_ipv4(src, dst, size));
382 #ifdef INET6
383 	case AF_INET6:
384 		return (inet_net_pton_ipv6(src, dst, size));
385 #endif /* INET6 */
386 	default:
387 		errno = EAFNOSUPPORT;
388 		return (-1);
389 	}
390 }
391