summaryrefslogtreecommitdiff
path: root/src/lib/libc/net/inet_net_pton.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/libc/net/inet_net_pton.c')
-rw-r--r--src/lib/libc/net/inet_net_pton.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/src/lib/libc/net/inet_net_pton.c b/src/lib/libc/net/inet_net_pton.c
new file mode 100644
index 0000000000..1683a79043
--- /dev/null
+++ b/src/lib/libc/net/inet_net_pton.c
@@ -0,0 +1,231 @@
1/* $OpenBSD: inet_net_pton.c,v 1.8 2013/11/25 18:23:51 deraadt Exp $ */
2
3/*
4 * Copyright (c) 2012 by Gilles Chehade <gilles@openbsd.org>
5 * Copyright (c) 1996 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 <sys/types.h>
22#include <sys/socket.h>
23#include <netinet/in.h>
24#include <arpa/inet.h>
25
26#include <assert.h>
27#include <ctype.h>
28#include <errno.h>
29#include <stdio.h>
30#include <string.h>
31#include <stdlib.h>
32
33static int inet_net_pton_ipv4(const char *, u_char *, size_t);
34static int inet_net_pton_ipv6(const char *, u_char *, size_t);
35
36/*
37 * static int
38 * inet_net_pton(af, src, dst, size)
39 * convert network number from presentation to network format.
40 * accepts hex octets, hex strings, decimal octets, and /CIDR.
41 * "size" is in bytes and describes "dst".
42 * return:
43 * number of bits, either imputed classfully or specified with /CIDR,
44 * or -1 if some failure occurred (check errno). ENOENT means it was
45 * not a valid network specification.
46 * author:
47 * Paul Vixie (ISC), June 1996
48 */
49int
50inet_net_pton(int af, const char *src, void *dst, size_t size)
51{
52 switch (af) {
53 case AF_INET:
54 return (inet_net_pton_ipv4(src, dst, size));
55 case AF_INET6:
56 return (inet_net_pton_ipv6(src, dst, size));
57 default:
58 errno = EAFNOSUPPORT;
59 return (-1);
60 }
61}
62
63/*
64 * static int
65 * inet_net_pton_ipv4(src, dst, size)
66 * convert IPv4 network number from presentation to network format.
67 * accepts hex octets, hex strings, decimal octets, and /CIDR.
68 * "size" is in bytes and describes "dst".
69 * return:
70 * number of bits, either imputed classfully or specified with /CIDR,
71 * or -1 if some failure occurred (check errno). ENOENT means it was
72 * not an IPv4 network specification.
73 * note:
74 * network byte order assumed. this means 192.5.5.240/28 has
75 * 0x11110000 in its fourth octet.
76 * author:
77 * Paul Vixie (ISC), June 1996
78 */
79static int
80inet_net_pton_ipv4(const char *src, u_char *dst, size_t size)
81{
82 static const char
83 xdigits[] = "0123456789abcdef",
84 digits[] = "0123456789";
85 int n, ch, tmp, dirty, bits;
86 const u_char *odst = dst;
87
88 ch = (unsigned char)*src++;
89 if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
90 && isascii((unsigned char)src[1]) && isxdigit((unsigned char)src[1])) {
91 /* Hexadecimal: Eat nybble string. */
92 if (size <= 0)
93 goto emsgsize;
94 *dst = 0, dirty = 0;
95 src++; /* skip x or X. */
96 while ((ch = (unsigned char)*src++) != '\0' &&
97 isascii(ch) && isxdigit(ch)) {
98 if (isupper(ch))
99 ch = tolower(ch);
100 n = strchr(xdigits, ch) - xdigits;
101 assert(n >= 0 && n <= 15);
102 *dst |= n;
103 if (!dirty++)
104 *dst <<= 4;
105 else if (size-- > 0)
106 *++dst = 0, dirty = 0;
107 else
108 goto emsgsize;
109 }
110 if (dirty)
111 size--;
112 } else if (isascii(ch) && isdigit(ch)) {
113 /* Decimal: eat dotted digit string. */
114 for (;;) {
115 tmp = 0;
116 do {
117 n = strchr(digits, ch) - digits;
118 assert(n >= 0 && n <= 9);
119 tmp *= 10;
120 tmp += n;
121 if (tmp > 255)
122 goto enoent;
123 } while ((ch = (unsigned char)*src++) != '\0' &&
124 isascii(ch) && isdigit(ch));
125 if (size-- <= 0)
126 goto emsgsize;
127 *dst++ = (u_char) tmp;
128 if (ch == '\0' || ch == '/')
129 break;
130 if (ch != '.')
131 goto enoent;
132 ch = (unsigned char)*src++;
133 if (!isascii(ch) || !isdigit(ch))
134 goto enoent;
135 }
136 } else
137 goto enoent;
138
139 bits = -1;
140 if (ch == '/' && isascii((unsigned char)src[0]) &&
141 isdigit((unsigned char)src[0]) && dst > odst) {
142 /* CIDR width specifier. Nothing can follow it. */
143 ch = (unsigned char)*src++; /* Skip over the /. */
144 bits = 0;
145 do {
146 n = strchr(digits, ch) - digits;
147 assert(n >= 0 && n <= 9);
148 bits *= 10;
149 bits += n;
150 if (bits > 32)
151 goto emsgsize;
152 } while ((ch = (unsigned char)*src++) != '\0' &&
153 isascii(ch) && isdigit(ch));
154 if (ch != '\0')
155 goto enoent;
156 }
157
158 /* Firey death and destruction unless we prefetched EOS. */
159 if (ch != '\0')
160 goto enoent;
161
162 /* If nothing was written to the destination, we found no address. */
163 if (dst == odst)
164 goto enoent;
165 /* If no CIDR spec was given, infer width from net class. */
166 if (bits == -1) {
167 if (*odst >= 240) /* Class E */
168 bits = 32;
169 else if (*odst >= 224) /* Class D */
170 bits = 4;
171 else if (*odst >= 192) /* Class C */
172 bits = 24;
173 else if (*odst >= 128) /* Class B */
174 bits = 16;
175 else /* Class A */
176 bits = 8;
177 /* If imputed mask is narrower than specified octets, widen. */
178 if (bits < ((dst - odst) * 8))
179 bits = (dst - odst) * 8;
180 }
181 /* Extend network to cover the actual mask. */
182 while (bits > ((dst - odst) * 8)) {
183 if (size-- <= 0)
184 goto emsgsize;
185 *dst++ = '\0';
186 }
187 return (bits);
188
189 enoent:
190 errno = ENOENT;
191 return (-1);
192
193 emsgsize:
194 errno = EMSGSIZE;
195 return (-1);
196}
197
198
199static int
200inet_net_pton_ipv6(const char *src, u_char *dst, size_t size)
201{
202 int ret;
203 int bits;
204 char buf[sizeof("xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:255:255:255:255/128")];
205 char *sep;
206 const char *errstr;
207
208 if (strlcpy(buf, src, sizeof buf) >= sizeof buf) {
209 errno = EMSGSIZE;
210 return (-1);
211 }
212
213 sep = strchr(buf, '/');
214 if (sep != NULL)
215 *sep++ = '\0';
216
217 ret = inet_pton(AF_INET6, buf, dst);
218 if (ret != 1)
219 return (-1);
220
221 if (sep == NULL)
222 return 128;
223
224 bits = strtonum(sep, 0, 128, &errstr);
225 if (errstr) {
226 errno = EINVAL;
227 return (-1);
228 }
229
230 return bits;
231}