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.c191
1 files changed, 191 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..9bb35478ca
--- /dev/null
+++ b/src/lib/libc/net/inet_net_pton.c
@@ -0,0 +1,191 @@
1/* $OpenBSD: inet_net_pton.c,v 1.5 2005/08/06 20:30:03 espie Exp $ */
2
3/*
4 * Copyright (c) 1996 by Internet Software Consortium.
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
11 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
12 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
13 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
16 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
17 * SOFTWARE.
18 */
19
20#include <sys/types.h>
21#include <sys/socket.h>
22#include <netinet/in.h>
23#include <arpa/inet.h>
24
25#include <assert.h>
26#include <ctype.h>
27#include <errno.h>
28#include <stdio.h>
29#include <string.h>
30#include <stdlib.h>
31
32static int inet_net_pton_ipv4(const char *, u_char *, size_t);
33
34/*
35 * static int
36 * inet_net_pton(af, src, dst, size)
37 * convert network number from presentation to network format.
38 * accepts hex octets, hex strings, decimal octets, and /CIDR.
39 * "size" is in bytes and describes "dst".
40 * return:
41 * number of bits, either imputed classfully or specified with /CIDR,
42 * or -1 if some failure occurred (check errno). ENOENT means it was
43 * not a valid network specification.
44 * author:
45 * Paul Vixie (ISC), June 1996
46 */
47int
48inet_net_pton(int af, const char *src, void *dst, size_t size)
49{
50 switch (af) {
51 case AF_INET:
52 return (inet_net_pton_ipv4(src, dst, size));
53 default:
54 errno = EAFNOSUPPORT;
55 return (-1);
56 }
57}
58
59/*
60 * static int
61 * inet_net_pton_ipv4(src, dst, size)
62 * convert IPv4 network number from presentation to network format.
63 * accepts hex octets, hex strings, decimal octets, and /CIDR.
64 * "size" is in bytes and describes "dst".
65 * return:
66 * number of bits, either imputed classfully or specified with /CIDR,
67 * or -1 if some failure occurred (check errno). ENOENT means it was
68 * not an IPv4 network specification.
69 * note:
70 * network byte order assumed. this means 192.5.5.240/28 has
71 * 0x11110000 in its fourth octet.
72 * author:
73 * Paul Vixie (ISC), June 1996
74 */
75static int
76inet_net_pton_ipv4(const char *src, u_char *dst, size_t size)
77{
78 static const char
79 xdigits[] = "0123456789abcdef",
80 digits[] = "0123456789";
81 int n, ch, tmp, dirty, bits;
82 const u_char *odst = dst;
83
84 ch = *src++;
85 if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
86 && isascii(src[1]) && isxdigit(src[1])) {
87 /* Hexadecimal: Eat nybble string. */
88 if (size <= 0)
89 goto emsgsize;
90 *dst = 0, dirty = 0;
91 src++; /* skip x or X. */
92 while ((ch = *src++) != '\0' &&
93 isascii(ch) && isxdigit(ch)) {
94 if (isupper(ch))
95 ch = tolower(ch);
96 n = strchr(xdigits, ch) - xdigits;
97 assert(n >= 0 && n <= 15);
98 *dst |= n;
99 if (!dirty++)
100 *dst <<= 4;
101 else if (size-- > 0)
102 *++dst = 0, dirty = 0;
103 else
104 goto emsgsize;
105 }
106 if (dirty)
107 size--;
108 } else if (isascii(ch) && isdigit(ch)) {
109 /* Decimal: eat dotted digit string. */
110 for (;;) {
111 tmp = 0;
112 do {
113 n = strchr(digits, ch) - digits;
114 assert(n >= 0 && n <= 9);
115 tmp *= 10;
116 tmp += n;
117 if (tmp > 255)
118 goto enoent;
119 } while ((ch = *src++) != '\0' &&
120 isascii(ch) && isdigit(ch));
121 if (size-- <= 0)
122 goto emsgsize;
123 *dst++ = (u_char) tmp;
124 if (ch == '\0' || ch == '/')
125 break;
126 if (ch != '.')
127 goto enoent;
128 ch = *src++;
129 if (!isascii(ch) || !isdigit(ch))
130 goto enoent;
131 }
132 } else
133 goto enoent;
134
135 bits = -1;
136 if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
137 /* CIDR width specifier. Nothing can follow it. */
138 ch = *src++; /* Skip over the /. */
139 bits = 0;
140 do {
141 n = strchr(digits, ch) - digits;
142 assert(n >= 0 && n <= 9);
143 bits *= 10;
144 bits += n;
145 } while ((ch = *src++) != '\0' &&
146 isascii(ch) && isdigit(ch));
147 if (ch != '\0')
148 goto enoent;
149 if (bits > 32)
150 goto emsgsize;
151 }
152
153 /* Firey death and destruction unless we prefetched EOS. */
154 if (ch != '\0')
155 goto enoent;
156
157 /* If nothing was written to the destination, we found no address. */
158 if (dst == odst)
159 goto enoent;
160 /* If no CIDR spec was given, infer width from net class. */
161 if (bits == -1) {
162 if (*odst >= 240) /* Class E */
163 bits = 32;
164 else if (*odst >= 224) /* Class D */
165 bits = 4;
166 else if (*odst >= 192) /* Class C */
167 bits = 24;
168 else if (*odst >= 128) /* Class B */
169 bits = 16;
170 else /* Class A */
171 bits = 8;
172 /* If imputed mask is narrower than specified octets, widen. */
173 if (bits < ((dst - odst) * 8))
174 bits = (dst - odst) * 8;
175 }
176 /* Extend network to cover the actual mask. */
177 while (bits > ((dst - odst) * 8)) {
178 if (size-- <= 0)
179 goto emsgsize;
180 *dst++ = '\0';
181 }
182 return (bits);
183
184 enoent:
185 errno = ENOENT;
186 return (-1);
187
188 emsgsize:
189 errno = EMSGSIZE;
190 return (-1);
191}