Annotation of src/lib/libc/inet/inet_cidr_pton.c, Revision 1.5
1.5 ! christos 1: /* $NetBSD: inet_cidr_pton.c,v 1.4 2007/03/30 20:23:03 ghen Exp $ */
1.1 christos 2:
3: /*
4: * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5: * Copyright (c) 1998,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 ISC DISCLAIMS ALL WARRANTIES
12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR
14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18: */
19:
1.2 christos 20: #include <sys/cdefs.h>
1.1 christos 21: #if defined(LIBC_SCCS) && !defined(lint)
1.2 christos 22: #if 0
1.5 ! christos 23: static const char rcsid[] = "Id: inet_cidr_pton.c,v 1.6 2005/04/27 04:56:19 sra Exp";
1.2 christos 24: #else
1.5 ! christos 25: __RCSID("$NetBSD: inet_cidr_pton.c,v 1.4 2007/03/30 20:23:03 ghen Exp $");
1.2 christos 26: #endif
1.1 christos 27: #endif
28:
29: #include "port_before.h"
30:
1.2 christos 31: #include "namespace.h"
1.1 christos 32: #include <sys/types.h>
33: #include <sys/socket.h>
34: #include <netinet/in.h>
35: #include <arpa/nameser.h>
36: #include <arpa/inet.h>
37:
38: #include <isc/assertions.h>
39: #include <ctype.h>
40: #include <errno.h>
41: #include <stdio.h>
42: #include <string.h>
43: #include <stdlib.h>
44:
45: #include "port_after.h"
46:
47: #ifdef SPRINTF_CHAR
48: # define SPRINTF(x) strlen(sprintf/**/x)
49: #else
50: # define SPRINTF(x) ((size_t)sprintf x)
51: #endif
52:
1.2 christos 53: #ifdef __weak_alias
54: __weak_alias(inet_cidr_pton,_inet_cidr_pton)
55: #endif
56:
1.1 christos 57: static int inet_cidr_pton_ipv4 __P((const char *src, u_char *dst,
58: int *bits, int ipv6));
59: static int inet_cidr_pton_ipv6 __P((const char *src, u_char *dst,
60: int *bits));
61:
62: static int getbits(const char *, int ipv6);
63:
1.3 christos 64: /*%
1.1 christos 65: * int
66: * inet_cidr_pton(af, src, dst, *bits)
67: * convert network address from presentation to network format.
68: * accepts inet_pton()'s input for this "af" plus trailing "/CIDR".
69: * "dst" is assumed large enough for its "af". "bits" is set to the
70: * /CIDR prefix length, which can have defaults (like /32 for IPv4).
71: * return:
72: * -1 if an error occurred (inspect errno; ENOENT means bad format).
73: * 0 if successful conversion occurred.
74: * note:
75: * 192.5.5.1/28 has a nonzero host part, which means it isn't a network
76: * as called for by inet_net_pton() but it can be a host address with
77: * an included netmask.
78: * author:
79: * Paul Vixie (ISC), October 1998
80: */
81: int
82: inet_cidr_pton(int af, const char *src, void *dst, int *bits) {
83: switch (af) {
84: case AF_INET:
85: return (inet_cidr_pton_ipv4(src, dst, bits, 0));
86: case AF_INET6:
87: return (inet_cidr_pton_ipv6(src, dst, bits));
88: default:
89: errno = EAFNOSUPPORT;
90: return (-1);
91: }
92: }
93:
94: static const char digits[] = "0123456789";
95:
96: static int
97: inet_cidr_pton_ipv4(const char *src, u_char *dst, int *pbits, int ipv6) {
98: const u_char *odst = dst;
99: int n, ch, tmp, bits;
100: size_t size = 4;
101:
102: /* Get the mantissa. */
103: while (ch = *src++, (isascii(ch) && isdigit(ch))) {
104: tmp = 0;
105: do {
106: n = strchr(digits, ch) - digits;
107: INSIST(n >= 0 && n <= 9);
108: tmp *= 10;
109: tmp += n;
110: if (tmp > 255)
111: goto enoent;
112: } while ((ch = *src++) != '\0' && isascii(ch) && isdigit(ch));
113: if (size-- == 0U)
114: goto emsgsize;
115: *dst++ = (u_char) tmp;
116: if (ch == '\0' || ch == '/')
117: break;
118: if (ch != '.')
119: goto enoent;
120: }
121:
122: /* Get the prefix length if any. */
123: bits = -1;
124: if (ch == '/' && dst > odst) {
125: bits = getbits(src, ipv6);
126: if (bits == -2)
127: goto enoent;
128: } else if (ch != '\0')
129: goto enoent;
130:
131: /* Prefix length can default to /32 only if all four octets spec'd. */
132: if (bits == -1) {
133: if (dst - odst == 4)
134: bits = ipv6 ? 128 : 32;
135: else
136: goto enoent;
137: }
138:
139: /* If nothing was written to the destination, we found no address. */
140: if (dst == odst)
141: goto enoent;
142:
143: /* If prefix length overspecifies mantissa, life is bad. */
144: if (((bits - (ipv6 ? 96 : 0)) / 8) > (dst - odst))
145: goto enoent;
146:
147: /* Extend address to four octets. */
148: while (size-- > 0U)
149: *dst++ = 0;
150:
151: *pbits = bits;
152: return (0);
153:
154: enoent:
155: errno = ENOENT;
156: return (-1);
157:
158: emsgsize:
159: errno = EMSGSIZE;
160: return (-1);
161: }
162:
163: static int
164: inet_cidr_pton_ipv6(const char *src, u_char *dst, int *pbits) {
165: static const char xdigits_l[] = "0123456789abcdef",
166: xdigits_u[] = "0123456789ABCDEF";
167: u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp;
168: const char *xdigits, *curtok;
169: int ch, saw_xdigit;
170: u_int val;
171: int bits;
172:
173: memset((tp = tmp), '\0', NS_IN6ADDRSZ);
174: endp = tp + NS_IN6ADDRSZ;
175: colonp = NULL;
176: /* Leading :: requires some special handling. */
177: if (*src == ':')
178: if (*++src != ':')
179: return (0);
180: curtok = src;
181: saw_xdigit = 0;
182: val = 0;
183: bits = -1;
184: while ((ch = *src++) != '\0') {
185: const char *pch;
186:
187: if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
188: pch = strchr((xdigits = xdigits_u), ch);
189: if (pch != NULL) {
190: val <<= 4;
191: val |= (pch - xdigits);
192: if (val > 0xffff)
193: return (0);
194: saw_xdigit = 1;
195: continue;
196: }
197: if (ch == ':') {
198: curtok = src;
199: if (!saw_xdigit) {
200: if (colonp)
201: return (0);
202: colonp = tp;
203: continue;
204: } else if (*src == '\0') {
205: return (0);
206: }
207: if (tp + NS_INT16SZ > endp)
208: return (0);
209: *tp++ = (u_char) (val >> 8) & 0xff;
210: *tp++ = (u_char) val & 0xff;
211: saw_xdigit = 0;
212: val = 0;
213: continue;
214: }
215: if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) &&
216: inet_cidr_pton_ipv4(curtok, tp, &bits, 1) == 0) {
217: tp += NS_INADDRSZ;
218: saw_xdigit = 0;
1.3 christos 219: break; /*%< '\\0' was seen by inet_pton4(). */
1.1 christos 220: }
221: if (ch == '/') {
222: bits = getbits(src, 1);
223: if (bits == -2)
224: goto enoent;
225: break;
226: }
227: goto enoent;
228: }
229: if (saw_xdigit) {
230: if (tp + NS_INT16SZ > endp)
231: goto emsgsize;
232: *tp++ = (u_char) (val >> 8) & 0xff;
233: *tp++ = (u_char) val & 0xff;
234: }
235: if (colonp != NULL) {
236: /*
237: * Since some memmove()'s erroneously fail to handle
238: * overlapping regions, we'll do the shift by hand.
239: */
240: const int n = tp - colonp;
241: int i;
242:
243: if (tp == endp)
244: goto enoent;
245: for (i = 1; i <= n; i++) {
246: endp[- i] = colonp[n - i];
247: colonp[n - i] = 0;
248: }
249: tp = endp;
250: }
251:
252: memcpy(dst, tmp, NS_IN6ADDRSZ);
253:
254: *pbits = bits;
255: return (0);
256:
257: enoent:
258: errno = ENOENT;
259: return (-1);
260:
261: emsgsize:
262: errno = EMSGSIZE;
263: return (-1);
264: }
265:
266: static int
267: getbits(const char *src, int ipv6) {
268: int bits = 0;
269: char *cp, ch;
270:
1.3 christos 271: if (*src == '\0') /*%< syntax */
1.1 christos 272: return (-2);
273: do {
274: ch = *src++;
275: cp = strchr(digits, ch);
1.3 christos 276: if (cp == NULL) /*%< syntax */
1.1 christos 277: return (-2);
278: bits *= 10;
279: bits += cp - digits;
1.3 christos 280: if (bits == 0 && *src != '\0') /*%< no leading zeros */
1.1 christos 281: return (-2);
1.3 christos 282: if (bits > (ipv6 ? 128 : 32)) /*%< range error */
1.1 christos 283: return (-2);
284: } while (*src != '\0');
285:
286: return (bits);
287: }
1.3 christos 288:
289: /*! \file */
CVSweb <webmaster@jp.NetBSD.org>