1 | /* Copyright (C) 1996-2021 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. |
3 | |
4 | The GNU C Library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Lesser General Public |
6 | License as published by the Free Software Foundation; either |
7 | version 2.1 of the License, or (at your option) any later version. |
8 | |
9 | The GNU C Library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
12 | Lesser General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public |
15 | License along with the GNU C Library; if not, see |
16 | <https://www.gnu.org/licenses/>. */ |
17 | |
18 | /* |
19 | * Copyright (c) 1996,1999 by Internet Software Consortium. |
20 | * |
21 | * Permission to use, copy, modify, and distribute this software for any |
22 | * purpose with or without fee is hereby granted, provided that the above |
23 | * copyright notice and this permission notice appear in all copies. |
24 | * |
25 | * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS |
26 | * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES |
27 | * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE |
28 | * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
29 | * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR |
30 | * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS |
31 | * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS |
32 | * SOFTWARE. |
33 | */ |
34 | |
35 | #include <arpa/inet.h> |
36 | #include <arpa/nameser.h> |
37 | #include <ctype.h> |
38 | #include <errno.h> |
39 | #include <netinet/in.h> |
40 | #include <resolv/resolv-internal.h> |
41 | #include <string.h> |
42 | #include <sys/socket.h> |
43 | #include <sys/types.h> |
44 | |
45 | static int inet_pton4 (const char *src, const char *src_end, u_char *dst); |
46 | static int inet_pton6 (const char *src, const char *src_end, u_char *dst); |
47 | |
48 | int |
49 | __inet_pton_length (int af, const char *src, size_t srclen, void *dst) |
50 | { |
51 | switch (af) |
52 | { |
53 | case AF_INET: |
54 | return inet_pton4 (src, src + srclen, dst); |
55 | case AF_INET6: |
56 | return inet_pton6 (src, src + srclen, dst); |
57 | default: |
58 | __set_errno (EAFNOSUPPORT); |
59 | return -1; |
60 | } |
61 | } |
62 | libc_hidden_def (__inet_pton_length) |
63 | |
64 | /* Like __inet_pton_length, but use strlen (SRC) as the length of |
65 | SRC. */ |
66 | int |
67 | __inet_pton (int af, const char *src, void *dst) |
68 | { |
69 | return __inet_pton_length (af, src, strlen (src), dst); |
70 | } |
71 | libc_hidden_def (__inet_pton) |
72 | weak_alias (__inet_pton, inet_pton) |
73 | libc_hidden_weak (inet_pton) |
74 | |
75 | /* Like inet_aton but without all the hexadecimal, octal and shorthand |
76 | (and trailing garbage is not ignored). Return 1 if SRC is a valid |
77 | dotted quad, else 0. This function does not touch DST unless it's |
78 | returning 1. |
79 | Author: Paul Vixie, 1996. */ |
80 | static int |
81 | inet_pton4 (const char *src, const char *end, unsigned char *dst) |
82 | { |
83 | int saw_digit, octets, ch; |
84 | unsigned char tmp[NS_INADDRSZ], *tp; |
85 | |
86 | saw_digit = 0; |
87 | octets = 0; |
88 | *(tp = tmp) = 0; |
89 | while (src < end) |
90 | { |
91 | ch = *src++; |
92 | if (ch >= '0' && ch <= '9') |
93 | { |
94 | unsigned int new = *tp * 10 + (ch - '0'); |
95 | |
96 | if (saw_digit && *tp == 0) |
97 | return 0; |
98 | if (new > 255) |
99 | return 0; |
100 | *tp = new; |
101 | if (! saw_digit) |
102 | { |
103 | if (++octets > 4) |
104 | return 0; |
105 | saw_digit = 1; |
106 | } |
107 | } |
108 | else if (ch == '.' && saw_digit) |
109 | { |
110 | if (octets == 4) |
111 | return 0; |
112 | *++tp = 0; |
113 | saw_digit = 0; |
114 | } |
115 | else |
116 | return 0; |
117 | } |
118 | if (octets < 4) |
119 | return 0; |
120 | memcpy (dst, tmp, NS_INADDRSZ); |
121 | return 1; |
122 | } |
123 | |
124 | /* Return the value of CH as a hexademical digit, or -1 if it is a |
125 | different type of character. */ |
126 | static int |
127 | hex_digit_value (char ch) |
128 | { |
129 | if ('0' <= ch && ch <= '9') |
130 | return ch - '0'; |
131 | if ('a' <= ch && ch <= 'f') |
132 | return ch - 'a' + 10; |
133 | if ('A' <= ch && ch <= 'F') |
134 | return ch - 'A' + 10; |
135 | return -1; |
136 | } |
137 | |
138 | /* Convert presentation-level IPv6 address to network order binary |
139 | form. Return 1 if SRC is a valid [RFC1884 2.2] address, else 0. |
140 | This function does not touch DST unless it's returning 1. |
141 | Author: Paul Vixie, 1996. Inspired by Mark Andrews. */ |
142 | static int |
143 | inet_pton6 (const char *src, const char *src_endp, unsigned char *dst) |
144 | { |
145 | unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; |
146 | const char *curtok; |
147 | int ch; |
148 | size_t xdigits_seen; /* Number of hex digits since colon. */ |
149 | unsigned int val; |
150 | |
151 | tp = memset (tmp, '\0', NS_IN6ADDRSZ); |
152 | endp = tp + NS_IN6ADDRSZ; |
153 | colonp = NULL; |
154 | |
155 | /* Leading :: requires some special handling. */ |
156 | if (src == src_endp) |
157 | return 0; |
158 | if (*src == ':') |
159 | { |
160 | ++src; |
161 | if (src == src_endp || *src != ':') |
162 | return 0; |
163 | } |
164 | |
165 | curtok = src; |
166 | xdigits_seen = 0; |
167 | val = 0; |
168 | while (src < src_endp) |
169 | { |
170 | ch = *src++; |
171 | int digit = hex_digit_value (ch); |
172 | if (digit >= 0) |
173 | { |
174 | if (xdigits_seen == 4) |
175 | return 0; |
176 | val <<= 4; |
177 | val |= digit; |
178 | if (val > 0xffff) |
179 | return 0; |
180 | ++xdigits_seen; |
181 | continue; |
182 | } |
183 | if (ch == ':') |
184 | { |
185 | curtok = src; |
186 | if (xdigits_seen == 0) |
187 | { |
188 | if (colonp) |
189 | return 0; |
190 | colonp = tp; |
191 | continue; |
192 | } |
193 | else if (src == src_endp) |
194 | return 0; |
195 | if (tp + NS_INT16SZ > endp) |
196 | return 0; |
197 | *tp++ = (unsigned char) (val >> 8) & 0xff; |
198 | *tp++ = (unsigned char) val & 0xff; |
199 | xdigits_seen = 0; |
200 | val = 0; |
201 | continue; |
202 | } |
203 | if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) |
204 | && inet_pton4 (curtok, src_endp, tp) > 0) |
205 | { |
206 | tp += NS_INADDRSZ; |
207 | xdigits_seen = 0; |
208 | break; /* '\0' was seen by inet_pton4. */ |
209 | } |
210 | return 0; |
211 | } |
212 | if (xdigits_seen > 0) |
213 | { |
214 | if (tp + NS_INT16SZ > endp) |
215 | return 0; |
216 | *tp++ = (unsigned char) (val >> 8) & 0xff; |
217 | *tp++ = (unsigned char) val & 0xff; |
218 | } |
219 | if (colonp != NULL) |
220 | { |
221 | /* Replace :: with zeros. */ |
222 | if (tp == endp) |
223 | /* :: would expand to a zero-width field. */ |
224 | return 0; |
225 | size_t n = tp - colonp; |
226 | memmove (endp - n, colonp, n); |
227 | memset (colonp, 0, endp - n - colonp); |
228 | tp = endp; |
229 | } |
230 | if (tp != endp) |
231 | return 0; |
232 | memcpy (dst, tmp, NS_IN6ADDRSZ); |
233 | return 1; |
234 | } |
235 | |