]> git.ipfire.org Git - thirdparty/glibc.git/blame - resolv/inet_net_pton.c
Fix race in tst-mqueue5
[thirdparty/glibc.git] / resolv / inet_net_pton.c
CommitLineData
df21c858 1/*
e685e07d 2 * Copyright (c) 1996,1999 by Internet Software Consortium.
df21c858
UD
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#if defined(LIBC_SCCS) && !defined(lint)
e685e07d 19static const char rcsid[] = "$BINDId: inet_net_pton.c,v 1.11 1999/01/08 19:23:44 vixie Exp $";
df21c858
UD
20#endif
21
22#include <sys/types.h>
23#include <sys/socket.h>
24#include <netinet/in.h>
25#include <arpa/inet.h>
26
27#include <assert.h>
28#include <ctype.h>
29#include <errno.h>
30#include <stdio.h>
31#include <string.h>
32#include <stdlib.h>
33
34#ifdef SPRINTF_CHAR
35# define SPRINTF(x) strlen(sprintf/**/x)
36#else
37# define SPRINTF(x) ((size_t)sprintf x)
38#endif
39
79937577
UD
40static int inet_net_pton_ipv4 (const char *src, u_char *dst,
41 size_t size) __THROW;
df21c858
UD
42
43/*
44 * static int
45 * inet_net_pton(af, src, dst, size)
46 * convert 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 a valid network specification.
53 * author:
54 * Paul Vixie (ISC), June 1996
55 */
56int
9dd346ff 57inet_net_pton (int af, const char *src, void *dst, size_t size)
df21c858
UD
58{
59 switch (af) {
60 case AF_INET:
61 return (inet_net_pton_ipv4(src, dst, size));
62 default:
c4029823 63 __set_errno (EAFNOSUPPORT);
df21c858
UD
64 return (-1);
65 }
66}
67
68/*
69 * static int
70 * inet_net_pton_ipv4(src, dst, size)
71 * convert IPv4 network number from presentation to network format.
72 * accepts hex octets, hex strings, decimal octets, and /CIDR.
73 * "size" is in bytes and describes "dst".
74 * return:
75 * number of bits, either imputed classfully or specified with /CIDR,
76 * or -1 if some failure occurred (check errno). ENOENT means it was
77 * not an IPv4 network specification.
78 * note:
79 * network byte order assumed. this means 192.5.5.240/28 has
e685e07d 80 * 0b11110000 in its fourth octet.
df21c858
UD
81 * author:
82 * Paul Vixie (ISC), June 1996
83 */
84static int
9dd346ff 85inet_net_pton_ipv4 (const char *src, u_char *dst, size_t size)
df21c858 86{
c4563d2d 87 static const char xdigits[] = "0123456789abcdef";
df21c858
UD
88 int n, ch, tmp, dirty, bits;
89 const u_char *odst = dst;
90
df21c858 91 ch = *src++;
df21c858
UD
92 if (ch == '0' && (src[0] == 'x' || src[0] == 'X')
93 && isascii(src[1]) && isxdigit(src[1])) {
94 /* Hexadecimal: Eat nybble string. */
95 if (size <= 0)
96 goto emsgsize;
e685e07d 97 dirty = 0;
0c03cb9b 98 tmp = 0; /* To calm down gcc. */
df21c858 99 src++; /* skip x or X. */
0c03cb9b 100 while (isxdigit((ch = *src++))) {
4caef86c 101 ch = _tolower(ch);
0c03cb9b 102 n = (const char *) __rawmemchr(xdigits, ch) - xdigits;
df21c858 103 assert(n >= 0 && n <= 15);
0c03cb9b 104 if (dirty == 0)
e685e07d 105 tmp = n;
df21c858 106 else
e685e07d 107 tmp = (tmp << 4) | n;
0c03cb9b
UD
108 if (++dirty == 2) {
109 if (size-- <= 0)
110 goto emsgsize;
111 *dst++ = (u_char) tmp;
112 dirty = 0;
113 }
114 }
e685e07d 115 if (dirty) { /* Odd trailing nybble? */
0c03cb9b 116 if (size-- <= 0)
df21c858 117 goto emsgsize;
e685e07d 118 *dst++ = (u_char) (tmp << 4);
df21c858 119 }
df21c858
UD
120 } else if (isascii(ch) && isdigit(ch)) {
121 /* Decimal: eat dotted digit string. */
122 for (;;) {
123 tmp = 0;
124 do {
0c03cb9b
UD
125 n = ((const char *) __rawmemchr(xdigits, ch)
126 - xdigits);
df21c858
UD
127 assert(n >= 0 && n <= 9);
128 tmp *= 10;
129 tmp += n;
130 if (tmp > 255)
131 goto enoent;
0c03cb9b 132 } while (isascii((ch = *src++)) && isdigit(ch));
df21c858
UD
133 if (size-- <= 0)
134 goto emsgsize;
135 *dst++ = (u_char) tmp;
136 if (ch == '\0' || ch == '/')
137 break;
138 if (ch != '.')
139 goto enoent;
140 ch = *src++;
141 if (!isascii(ch) || !isdigit(ch))
142 goto enoent;
143 }
144 } else
145 goto enoent;
146
26761c28 147 bits = -1;
df21c858
UD
148 if (ch == '/' && isascii(src[0]) && isdigit(src[0]) && dst > odst) {
149 /* CIDR width specifier. Nothing can follow it. */
150 ch = *src++; /* Skip over the /. */
151 bits = 0;
152 do {
0c03cb9b 153 n = (const char *) __rawmemchr(xdigits, ch) - xdigits;
df21c858
UD
154 assert(n >= 0 && n <= 9);
155 bits *= 10;
156 bits += n;
0c03cb9b 157 } while (isascii((ch = *src++)) && isdigit(ch));
df21c858
UD
158 if (ch != '\0')
159 goto enoent;
26761c28
UD
160 if (bits > 32)
161 goto emsgsize;
df21c858
UD
162 }
163
76b87c03 164 /* Firey death and destruction unless we prefetched EOS. */
df21c858
UD
165 if (ch != '\0')
166 goto enoent;
167
168 /* If nothing was written to the destination, we found no address. */
169 if (dst == odst)
170 goto enoent;
171 /* If no CIDR spec was given, infer width from net class. */
172 if (bits == -1) {
26761c28
UD
173 if (*odst >= 240) /* Class E */
174 bits = 32;
175 else if (*odst >= 224) /* Class D */
df21c858 176 bits = 4;
26761c28 177 else if (*odst >= 192) /* Class C */
df21c858 178 bits = 24;
26761c28 179 else if (*odst >= 128) /* Class B */
df21c858 180 bits = 16;
26761c28 181 else /* Class A */
df21c858 182 bits = 8;
26761c28
UD
183 /* If imputed mask is narrower than specified octets, widen. */
184 if (bits >= 8 && bits < ((dst - odst) * 8))
185 bits = (dst - odst) * 8;
df21c858
UD
186 }
187 /* Extend network to cover the actual mask. */
188 while (bits > ((dst - odst) * 8)) {
189 if (size-- <= 0)
190 goto emsgsize;
191 *dst++ = '\0';
192 }
193 return (bits);
194
195 enoent:
c4029823 196 __set_errno (ENOENT);
df21c858
UD
197 return (-1);
198
199 emsgsize:
c4029823 200 __set_errno (EMSGSIZE);
df21c858
UD
201 return (-1);
202}