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