]>
Commit | Line | Data |
---|---|---|
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 | 19 | static 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 |
40 | static 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 | */ | |
56 | int | |
9dd346ff | 57 | inet_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 | */ | |
84 | static int | |
9dd346ff | 85 | inet_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 | } |