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