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 /*
19  * Portions copyright (c) 1999, 2000
20  * Intel Corporation.
21  * All rights reserved.
22  *
23  * Redistribution and use in source and binary forms, with or without
24  * modification, are permitted provided that the following conditions
25  * are met:
26  *
27  * 1. Redistributions of source code must retain the above copyright
28  *    notice, this list of conditions and the following disclaimer.
29  *
30  * 2. Redistributions in binary form must reproduce the above copyright
31  *    notice, this list of conditions and the following disclaimer in the
32  *    documentation and/or other materials provided with the distribution.
33  *
34  * 3. All advertising materials mentioning features or use of this software
35  *    must display the following acknowledgement:
36  *
37  *    This product includes software developed by Intel Corporation and
38  *    its contributors.
39  *
40  * 4. Neither the name of Intel Corporation or its contributors may be
41  *    used to endorse or promote products derived from this software
42  *    without specific prior written permission.
43  *
44  * THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION AND CONTRIBUTORS ``AS IS''
45  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47  * ARE DISCLAIMED.  IN NO EVENT SHALL INTEL CORPORATION OR CONTRIBUTORS BE
48  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
49  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
50  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
51  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
52  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
53  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
54  * THE POSSIBILITY OF SUCH DAMAGE.
55  *
56  */
57 
58 #if defined(LIBC_SCCS) && !defined(lint)
59 static const char orig_rcsid[] = "From Id: inet_net_pton.c,v 1.8 1996/11/21 10:28:12 vixie Exp $";
60 static const char rcsid[] = "$Id: inet_net_pton.c,v 1.1.1.1 2003/11/19 01:51:29 kyu3 Exp $";
61 #endif
62 
63 #include <sys/types.h>
64 #include <sys/socket.h>
65 #include <netinet/in.h>
66 #include <arpa/inet.h>
67 
68 #include <assert.h>
69 #include <ctype.h>
70 #include <errno.h>
71 #include <stdio.h>
72 #include <string.h>
73 #include <stdlib.h>
74 
75 #ifdef SPRINTF_CHAR
76 # define SPRINTF(x) strlen(sprintf/**/x)
77 #else
78 # define SPRINTF(x) ((size_t)sprintf x)
79 #endif
80 
81 static int	inet_net_pton_ipv4 (const char *src, u_char *dst,
82 					size_t size);
83 
84 /*
85  * static int
86  * inet_net_pton(af, src, dst, size)
87  *	convert network number from presentation to network format.
88  *	accepts hex octets, hex strings, decimal octets, and /CIDR.
89  *	"size" is in bytes and describes "dst".
90  * return:
91  *	number of bits, either imputed classfully or specified with /CIDR,
92  *	or -1 if some failure occurred (check errno).  ENOENT means it was
93  *	not a valid network specification.
94  * author:
95  *	Paul Vixie (ISC), June 1996
96  */
97 int
inet_net_pton(int af,const char * src,void * dst,size_t size)98 inet_net_pton(
99 	int af,
100 	const char *src,
101 	void *dst,
102 	size_t size
103 	)
104 {
105 	switch (af) {
106 	case AF_INET:
107 		return (inet_net_pton_ipv4(src, dst, size));
108 	default:
109 		errno = EAFNOSUPPORT;
110 		return (-1);
111 	}
112 }
113 
114 /*
115  * static int
116  * inet_net_pton_ipv4(src, dst, size)
117  *	convert IPv4 network number from presentation to network format.
118  *	accepts hex octets, hex strings, decimal octets, and /CIDR.
119  *	"size" is in bytes and describes "dst".
120  * return:
121  *	number of bits, either imputed classfully or specified with /CIDR,
122  *	or -1 if some failure occurred (check errno).  ENOENT means it was
123  *	not an IPv4 network specification.
124  * note:
125  *	network byte order assumed.  this means 192.5.5.240/28 has
126  *	0x11110000 in its fourth octet.
127  * author:
128  *	Paul Vixie (ISC), June 1996
129  */
130 static int
inet_net_pton_ipv4(const char * src,u_char * dst,size_t size)131 inet_net_pton_ipv4(
132 	const char *src,
133 	u_char *dst,
134 	size_t size
135 	)
136 {
137 	static const char xdigits[] = "0123456789abcdef";
138 	static const char digits[] = "0123456789";
139 	int n;
140   int ch;
141   int tmp;
142   int dirty;
143   int bits;
144 	const u_char *odst = dst;
145 
146 	ch = *src++;
147 	if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
148 	    && isascii(src[1]) && isxdigit(src[1])) {
149 		/* Hexadecimal: Eat nybble string. */
150 		if (size <= 0)
151 			goto emsgsize;
152 		*dst = 0, dirty = 0;
153 		src++;	/* skip x or X. */
154 		while ((ch = *src++) != '\0' &&
155 		       isascii(ch) && isxdigit(ch)) {
156 			if (isupper(ch))
157 				ch = tolower(ch);
158 			n = (int)(strchr(xdigits, ch) - xdigits);
159 			assert(n >= 0 && n <= 15);
160 			*dst |= n;
161 			if (!dirty++)
162 				*dst <<= 4;
163 			else if (size-- > 0)
164 				*++dst = 0, dirty = 0;
165 			else
166 				goto emsgsize;
167 		}
168 		if (dirty)
169 			size--;
170 	} else if (isascii(ch) && isdigit(ch)) {
171 		/* Decimal: eat dotted digit string. */
172 		for (;;) {
173 			tmp = 0;
174 			do {
175 				n = (int)(strchr(digits, ch) - digits);
176 				assert(n >= 0 && n <= 9);
177 				tmp *= 10;
178 				tmp += n;
179 				if (tmp > 255)
180 					goto enoent;
181 			} while ((ch = *src++) != '\0' &&
182 				 isascii(ch) && isdigit(ch));
183 			if (size-- <= 0)
184 				goto emsgsize;
185 			*dst++ = (u_char) tmp;
186 			if (ch == '\0' || ch == '/')
187 				break;
188 			if (ch != '.')
189 				goto enoent;
190 			ch = *src++;
191 			if (!isascii(ch) || !isdigit(ch))
192 				goto enoent;
193 		}
194 	} else
195 		goto enoent;
196 
197 	bits = -1;
198 	if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
199 		/* CIDR width specifier.  Nothing can follow it. */
200 		ch = *src++;	/* Skip over the /. */
201 		bits = 0;
202 		do {
203 			n = (int)(strchr(digits, ch) - digits);
204 			assert(n >= 0 && n <= 9);
205 			bits *= 10;
206 			bits += n;
207 		} while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
208 		if (ch != '\0')
209 			goto enoent;
210 		if (bits > 32)
211 			goto emsgsize;
212 	}
213 
214 	/* Firey death and destruction unless we prefetched EOS. */
215 	if (ch != '\0')
216 		goto enoent;
217 
218 	/* If nothing was written to the destination, we found no address. */
219 	if (dst == odst)
220 		goto enoent;
221 	/* If no CIDR spec was given, infer width from net class. */
222 	if (bits == -1) {
223 		if (*odst >= 240)	/* Class E */
224 			bits = 32;
225 		else if (*odst >= 224)	/* Class D */
226 			bits = 4;
227 		else if (*odst >= 192)	/* Class C */
228 			bits = 24;
229 		else if (*odst >= 128)	/* Class B */
230 			bits = 16;
231 		else			/* Class A */
232 			bits = 8;
233 		/* If imputed mask is narrower than specified octets, widen. */
234 		if (bits >= 8 && bits < ((dst - odst) * 8))
235 			bits = (int)(dst - odst) * 8;
236 	}
237 	/* Extend network to cover the actual mask. */
238 	while (bits > ((dst - odst) * 8)) {
239 		if (size-- <= 0)
240 			goto emsgsize;
241 		*dst++ = '\0';
242 	}
243 	return (bits);
244 
245  enoent:
246 	errno = ENOENT;
247 	return (-1);
248 
249  emsgsize:
250 	errno = EMSGSIZE;
251 	return (-1);
252 }
253