| | varnish-cache/lib/libvarnish/vss.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2010 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Dag-Erling Smørgrav <des@des.no> |
6 |
|
* Author: Cecilie Fritzvold <cecilihf@linpro.no> |
7 |
|
* |
8 |
|
* SPDX-License-Identifier: BSD-2-Clause |
9 |
|
* |
10 |
|
* Redistribution and use in source and binary forms, with or without |
11 |
|
* modification, are permitted provided that the following conditions |
12 |
|
* are met: |
13 |
|
* 1. Redistributions of source code must retain the above copyright |
14 |
|
* notice, this list of conditions and the following disclaimer. |
15 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
16 |
|
* notice, this list of conditions and the following disclaimer in the |
17 |
|
* documentation and/or other materials provided with the distribution. |
18 |
|
* |
19 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
20 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
23 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 |
|
* SUCH DAMAGE. |
30 |
|
*/ |
31 |
|
|
32 |
|
#include "config.h" |
33 |
|
|
34 |
|
#include <sys/socket.h> |
35 |
|
|
36 |
|
#include <netdb.h> |
37 |
|
#include <stdlib.h> |
38 |
|
#include <string.h> |
39 |
|
#include <stdio.h> |
40 |
|
|
41 |
|
#include "vdef.h" |
42 |
|
|
43 |
|
#include "vas.h" |
44 |
|
#include "vsa.h" |
45 |
|
#include "vss.h" |
46 |
|
|
47 |
|
/*lint -esym(754, _storage) not ref */ |
48 |
|
|
49 |
|
/* |
50 |
|
* Take a string provided by the user and break it up into address and |
51 |
|
* port parts. The address and port separator may be either a colon or |
52 |
|
* a whitespace. Examples of acceptable input include: |
53 |
|
* |
54 |
|
* "localhost" - "localhost:80" - "localhost 80" |
55 |
|
* "127.0.0.1" - "127.0.0.1:80" - "127.0.0.1 80" |
56 |
|
* "0.0.0.0" - "0.0.0.0:80" - "0.0.0.0 80" |
57 |
|
* "[::1]" - "[::1]:80" - "[::1] 80" |
58 |
|
* "[::]" - "[::]:80" - "[::] 80" |
59 |
|
* "::1" - "[::1]:80" - "[::1] 80" |
60 |
|
* |
61 |
|
* See also RFC5952 |
62 |
|
*/ |
63 |
|
|
64 |
|
static const char * |
65 |
502448 |
vss_parse(char *str, char **addr, char **port) |
66 |
|
{ |
67 |
|
char *p; |
68 |
|
|
69 |
502448 |
*addr = *port = NULL; |
70 |
|
|
71 |
502448 |
if (str[0] == '[') { |
72 |
|
/* IPv6 address of the form [::1]:80 */ |
73 |
1800 |
*addr = str + 1; |
74 |
1800 |
p = strchr(str, ']'); |
75 |
1800 |
if (p == NULL) |
76 |
40 |
return ("IPv6 address lacks ']'"); |
77 |
1760 |
*p++ = '\0'; |
78 |
1760 |
if (*p == '\0') |
79 |
400 |
return (NULL); |
80 |
1360 |
if (*p != ' ' && *p != ':') |
81 |
40 |
return ("IPv6 address has wrong port separator"); |
82 |
1320 |
} else { |
83 |
|
/* |
84 |
|
* IPv4 address of the form 127.0.0.1:80, IPv6 address |
85 |
|
* without port or non-numeric. |
86 |
|
*/ |
87 |
500648 |
*addr = str; |
88 |
500648 |
p = strchr(str, ' '); |
89 |
500648 |
if (p == NULL) |
90 |
420249 |
p = strchr(str, ':'); |
91 |
500648 |
if (p == NULL) |
92 |
91050 |
return (NULL); |
93 |
409598 |
if (p[0] == ':' && strchr(&p[1], ':')) |
94 |
1680 |
return (NULL); |
95 |
407918 |
if (p == str) |
96 |
44520 |
*addr = NULL; |
97 |
|
} |
98 |
409238 |
*p++ = '\0'; |
99 |
409238 |
*port = p; |
100 |
409238 |
return (NULL); |
101 |
502448 |
} |
102 |
|
|
103 |
|
static const char * |
104 |
39280 |
vss_parse_range(char *str, char **addr, char **port, unsigned long *lo, |
105 |
|
unsigned long *hi) |
106 |
|
{ |
107 |
|
const char *errp; |
108 |
|
char *end; |
109 |
|
unsigned long l, h; |
110 |
|
|
111 |
39280 |
errp = vss_parse(str, addr, port); |
112 |
39280 |
if (errp != NULL) |
113 |
0 |
return (errp); |
114 |
39280 |
if (*port == NULL || **port == '-') |
115 |
520 |
return (NULL); |
116 |
|
|
117 |
38760 |
l = strtoul(*port, &end, 10); |
118 |
38760 |
if (end[0] != '-' || end[1] == '\0') |
119 |
37840 |
return (NULL); |
120 |
920 |
if (strchr(end + 1, '-') != NULL) |
121 |
80 |
return (NULL); |
122 |
840 |
h = strtoul(end + 1, &end, 10); |
123 |
840 |
if (end[0] != '\0') |
124 |
120 |
return (NULL); |
125 |
|
|
126 |
|
/* Port range of the form 80-81 */ |
127 |
720 |
if (l == 0) |
128 |
40 |
return ("Range start cannot be 0"); |
129 |
680 |
if (h < l) |
130 |
40 |
return ("Range start higher than range end"); |
131 |
640 |
if (h > 65535) |
132 |
40 |
return ("Range end higher than 65535"); |
133 |
|
|
134 |
600 |
*lo = l; |
135 |
600 |
*hi = h; |
136 |
600 |
return (NULL); |
137 |
39280 |
} |
138 |
|
|
139 |
|
static int |
140 |
463168 |
vss_resolve(const char *addr, const char *def_port, int family, int socktype, |
141 |
|
int flags, struct addrinfo **res, const char **errp) |
142 |
|
{ |
143 |
|
struct addrinfo hints; |
144 |
|
char *p, *hp, *pp; |
145 |
|
int ret; |
146 |
|
|
147 |
463168 |
AN(addr); |
148 |
463168 |
AN(res); |
149 |
463168 |
AZ(*res); |
150 |
463168 |
AN(errp); |
151 |
463168 |
*errp = NULL; |
152 |
|
|
153 |
463168 |
memset(&hints, 0, sizeof hints); |
154 |
463168 |
hints.ai_family = family; |
155 |
463168 |
hints.ai_socktype = socktype; |
156 |
463168 |
hints.ai_flags = flags; |
157 |
|
|
158 |
463168 |
p = strdup(addr); |
159 |
463168 |
AN(p); |
160 |
463168 |
*errp = vss_parse(p, &hp, &pp); |
161 |
463168 |
if (*errp != NULL) { |
162 |
80 |
free(p); |
163 |
80 |
return (-1); |
164 |
|
} |
165 |
463088 |
if (pp != NULL) |
166 |
370154 |
def_port = pp; |
167 |
463088 |
ret = getaddrinfo(hp, def_port, &hints, res); |
168 |
463088 |
free(p); |
169 |
|
|
170 |
463088 |
if (ret == EAI_SYSTEM) |
171 |
0 |
*errp = VAS_errtxt(errno); |
172 |
463088 |
else if (ret != 0) |
173 |
1760 |
*errp = gai_strerror(ret); |
174 |
|
|
175 |
463088 |
return (ret); |
176 |
463168 |
} |
177 |
|
|
178 |
|
static const struct suckaddr * |
179 |
85570 |
vss_alloc_suckaddr(void *dst, const struct addrinfo *ai) |
180 |
|
{ |
181 |
|
|
182 |
85570 |
AN(ai); |
183 |
85570 |
if (dst == NULL) |
184 |
81040 |
return (VSA_Malloc(ai->ai_addr, ai->ai_addrlen)); |
185 |
|
|
186 |
4530 |
return (VSA_Build(dst, ai->ai_addr, ai->ai_addrlen)); |
187 |
85570 |
} |
188 |
|
|
189 |
|
/* |
190 |
|
* Look up an address, using a default port if provided, and call |
191 |
|
* the callback function with the suckaddrs we find. |
192 |
|
* If the callback function returns anything but zero, we terminate |
193 |
|
* and pass that value. |
194 |
|
*/ |
195 |
|
|
196 |
|
int |
197 |
376586 |
VSS_resolver_socktype(const char *addr, const char *def_port, |
198 |
|
vss_resolved_f *func, void *priv, const char **errp, int socktype) |
199 |
|
{ |
200 |
376586 |
struct addrinfo *res0 = NULL, *res; |
201 |
|
const struct suckaddr *vsa; |
202 |
|
int ret; |
203 |
|
|
204 |
376586 |
AN(addr); |
205 |
376586 |
AN(func); |
206 |
376586 |
AN(errp); |
207 |
|
|
208 |
753172 |
ret = vss_resolve(addr, def_port, AF_UNSPEC, socktype, AI_PASSIVE, |
209 |
376586 |
&res0, errp); |
210 |
376586 |
if (ret != 0) |
211 |
920 |
return (-1); |
212 |
|
|
213 |
582746 |
for (res = res0; res != NULL; res = res->ai_next) { |
214 |
414786 |
vsa = VSA_Malloc(res->ai_addr, res->ai_addrlen); |
215 |
414786 |
if (vsa != NULL) { |
216 |
414786 |
ret = func(priv, vsa); |
217 |
414786 |
VSA_free(&vsa); |
218 |
414786 |
if (ret) |
219 |
207706 |
break; |
220 |
207080 |
} |
221 |
207080 |
} |
222 |
375666 |
freeaddrinfo(res0); |
223 |
375666 |
return (ret); |
224 |
376586 |
} |
225 |
|
|
226 |
|
int |
227 |
376640 |
VSS_resolver(const char *addr, const char *def_port, vss_resolved_f *func, |
228 |
|
void *priv, const char **errp) |
229 |
|
{ |
230 |
376640 |
return (VSS_resolver_socktype( |
231 |
376640 |
addr, def_port, func, priv, errp, SOCK_STREAM)); |
232 |
|
} |
233 |
|
|
234 |
|
int |
235 |
39280 |
VSS_resolver_range(const char *addr, const char *def_port, vss_resolved_f *func, |
236 |
|
void *priv, const char **errp) |
237 |
|
{ |
238 |
|
char *p, *hp, *pp; |
239 |
39280 |
unsigned long lo = 0, hi = 0, i; |
240 |
39280 |
int error = 0; |
241 |
|
|
242 |
39280 |
AN(addr); |
243 |
39280 |
AN(func); |
244 |
39280 |
AN(errp); |
245 |
|
|
246 |
39280 |
p = strdup(addr); |
247 |
39280 |
AN(p); |
248 |
39280 |
*errp = vss_parse_range(p, &hp, &pp, &lo, &hi); |
249 |
39280 |
if (*errp != NULL) { |
250 |
120 |
free(p); |
251 |
120 |
return (-1); |
252 |
|
} |
253 |
|
|
254 |
39160 |
if (lo == 0) { |
255 |
|
/* No port range (0 not allowed in range) */ |
256 |
38560 |
free(p); |
257 |
38560 |
return (VSS_resolver(addr, def_port, func, priv, errp)); |
258 |
|
} |
259 |
|
|
260 |
|
/* Undo vss_parse() string modifications */ |
261 |
600 |
memcpy(p, addr, pp - p); |
262 |
|
|
263 |
1760 |
for (i = lo; i <= hi && !error; i++) { |
264 |
|
/* pp points to the first character of the range definition. |
265 |
|
* The range definition includes the biggest port number, so the |
266 |
|
* buffer must be big enough to fit each number individually. |
267 |
|
*/ |
268 |
1160 |
sprintf(pp, "%lu", i); |
269 |
1160 |
error = VSS_resolver(p, def_port, func, priv, errp); |
270 |
1160 |
} |
271 |
600 |
free(p); |
272 |
600 |
return (error); |
273 |
39280 |
} |
274 |
|
|
275 |
|
const struct suckaddr * |
276 |
82970 |
VSS_ResolveOne(void *dst, const char *addr, const char *def_port, |
277 |
|
int family, int socktype, int flags) |
278 |
|
{ |
279 |
82970 |
struct addrinfo *res = NULL; |
280 |
82970 |
const struct suckaddr *retval = NULL; |
281 |
|
const char *err; |
282 |
|
int ret; |
283 |
|
|
284 |
82970 |
AN(addr); |
285 |
82970 |
ret = vss_resolve(addr, def_port, family, socktype, flags, &res, &err); |
286 |
82970 |
if (ret == 0 && res != NULL && res->ai_next == NULL) { |
287 |
82530 |
AZ(err); |
288 |
82530 |
retval = vss_alloc_suckaddr(dst, res); |
289 |
82530 |
} |
290 |
82970 |
if (res != NULL) |
291 |
82530 |
freeaddrinfo(res); |
292 |
82970 |
return (retval); |
293 |
|
} |
294 |
|
|
295 |
|
const struct suckaddr * |
296 |
3520 |
VSS_ResolveFirst(void *dst, const char *addr, const char *def_port, |
297 |
|
int family, int socktype, int flags) |
298 |
|
{ |
299 |
3520 |
struct addrinfo *res0 = NULL, *res; |
300 |
3520 |
const struct suckaddr *retval = NULL; |
301 |
|
const char *err; |
302 |
|
int ret; |
303 |
|
|
304 |
3520 |
AN(addr); |
305 |
3520 |
ret = vss_resolve(addr, def_port, family, socktype, flags, &res0, &err); |
306 |
3520 |
if (ret == 0) |
307 |
3040 |
AZ(err); |
308 |
|
|
309 |
3560 |
for (res = res0; res != NULL; res = res->ai_next) { |
310 |
3040 |
retval = vss_alloc_suckaddr(dst, res); |
311 |
3040 |
if (retval != NULL) |
312 |
3000 |
break; |
313 |
40 |
} |
314 |
3520 |
if (res0 != NULL) |
315 |
3040 |
freeaddrinfo(res0); |
316 |
3520 |
return (retval); |
317 |
|
} |