| | 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 |
|
|
40 |
|
#include "vdef.h" |
41 |
|
|
42 |
|
#include "vas.h" |
43 |
|
#include "vsa.h" |
44 |
|
#include "vss.h" |
45 |
|
|
46 |
|
/*lint -esym(754, _storage) not ref */ |
47 |
|
|
48 |
|
/* |
49 |
|
* Take a string provided by the user and break it up into address and |
50 |
|
* port parts. The address and port separator may be either a colon or |
51 |
|
* a whitespace. Examples of acceptable input include: |
52 |
|
* |
53 |
|
* "localhost" - "localhost:80" - "localhost 80" |
54 |
|
* "127.0.0.1" - "127.0.0.1:80" - "127.0.0.1 80" |
55 |
|
* "0.0.0.0" - "0.0.0.0:80" - "0.0.0.0 80" |
56 |
|
* "[::1]" - "[::1]:80" - "[::1] 80" |
57 |
|
* "[::]" - "[::]:80" - "[::] 80" |
58 |
|
* "::1" - "[::1]:80" - "[::1] 80" |
59 |
|
* |
60 |
|
* See also RFC5952 |
61 |
|
*/ |
62 |
|
|
63 |
|
static const char * |
64 |
254682 |
vss_parse(char *str, char **addr, char **port) |
65 |
|
{ |
66 |
|
char *p; |
67 |
|
|
68 |
254682 |
*addr = *port = NULL; |
69 |
|
|
70 |
254682 |
if (str[0] == '[') { |
71 |
|
/* IPv6 address of the form [::1]:80 */ |
72 |
700 |
*addr = str + 1; |
73 |
700 |
p = strchr(str, ']'); |
74 |
700 |
if (p == NULL) |
75 |
25 |
return ("IPv6 address lacks ']'"); |
76 |
675 |
*p++ = '\0'; |
77 |
675 |
if (*p == '\0') |
78 |
200 |
return (NULL); |
79 |
475 |
if (*p != ' ' && *p != ':') |
80 |
25 |
return ("IPv6 address has wrong port separator"); |
81 |
450 |
} else { |
82 |
|
/* |
83 |
|
* IPv4 address of the form 127.0.0.1:80, IPv6 address |
84 |
|
* without port or non-numeric. |
85 |
|
*/ |
86 |
253982 |
*addr = str; |
87 |
253982 |
p = strchr(str, ' '); |
88 |
253982 |
if (p == NULL) |
89 |
205433 |
p = strchr(str, ':'); |
90 |
253982 |
if (p == NULL) |
91 |
30883 |
return (NULL); |
92 |
223099 |
if (p[0] == ':' && strchr(&p[1], ':')) |
93 |
1000 |
return (NULL); |
94 |
222099 |
if (p == str) |
95 |
25400 |
*addr = NULL; |
96 |
|
} |
97 |
222549 |
*p++ = '\0'; |
98 |
222549 |
*port = p; |
99 |
222549 |
return (NULL); |
100 |
254682 |
} |
101 |
|
|
102 |
|
static int |
103 |
254683 |
vss_resolve(const char *addr, const char *def_port, int family, int socktype, |
104 |
|
int flags, struct addrinfo **res, const char **errp) |
105 |
|
{ |
106 |
|
struct addrinfo hints; |
107 |
|
char *p, *hp, *pp; |
108 |
|
int ret; |
109 |
|
|
110 |
254683 |
AN(addr); |
111 |
254683 |
AN(res); |
112 |
254683 |
AZ(*res); |
113 |
254683 |
AN(errp); |
114 |
254683 |
*errp = NULL; |
115 |
|
|
116 |
254683 |
memset(&hints, 0, sizeof hints); |
117 |
254683 |
hints.ai_family = family; |
118 |
254683 |
hints.ai_socktype = socktype; |
119 |
254683 |
hints.ai_flags = flags; |
120 |
|
|
121 |
254683 |
p = strdup(addr); |
122 |
254683 |
AN(p); |
123 |
254683 |
*errp = vss_parse(p, &hp, &pp); |
124 |
254683 |
if (*errp != NULL) { |
125 |
50 |
free(p); |
126 |
50 |
return (-1); |
127 |
|
} |
128 |
254633 |
if (pp != NULL) |
129 |
222549 |
def_port = pp; |
130 |
254633 |
ret = getaddrinfo(hp, def_port, &hints, res); |
131 |
254633 |
free(p); |
132 |
|
|
133 |
254633 |
if (ret == EAI_SYSTEM) |
134 |
0 |
*errp = VAS_errtxt(errno); |
135 |
254633 |
else if (ret != 0) |
136 |
625 |
*errp = gai_strerror(ret); |
137 |
|
|
138 |
254633 |
return (ret); |
139 |
254683 |
} |
140 |
|
|
141 |
|
static const struct suckaddr * |
142 |
27658 |
vss_alloc_suckaddr(void *dst, const struct addrinfo *ai) |
143 |
|
{ |
144 |
|
|
145 |
27658 |
AN(ai); |
146 |
27658 |
if (dst == NULL) |
147 |
24825 |
return (VSA_Malloc(ai->ai_addr, ai->ai_addrlen)); |
148 |
|
|
149 |
2833 |
return (VSA_Build(dst, ai->ai_addr, ai->ai_addrlen)); |
150 |
27658 |
} |
151 |
|
|
152 |
|
/* |
153 |
|
* Look up an address, using a default port if provided, and call |
154 |
|
* the callback function with the suckaddrs we find. |
155 |
|
* If the callback function returns anything but zero, we terminate |
156 |
|
* and pass that value. |
157 |
|
*/ |
158 |
|
|
159 |
|
int |
160 |
226395 |
VSS_resolver_socktype(const char *addr, const char *def_port, |
161 |
|
vss_resolved_f *func, void *priv, const char **errp, int socktype) |
162 |
|
{ |
163 |
226395 |
struct addrinfo *res0 = NULL, *res; |
164 |
|
const struct suckaddr *vsa; |
165 |
|
int ret; |
166 |
|
|
167 |
226395 |
AN(addr); |
168 |
226395 |
AN(func); |
169 |
226395 |
AN(errp); |
170 |
|
|
171 |
452790 |
ret = vss_resolve(addr, def_port, AF_UNSPEC, socktype, AI_PASSIVE, |
172 |
226395 |
&res0, errp); |
173 |
226395 |
if (ret != 0) |
174 |
100 |
return (-1); |
175 |
|
|
176 |
351570 |
for (res = res0; res != NULL; res = res->ai_next) { |
177 |
250020 |
vsa = VSA_Malloc(res->ai_addr, res->ai_addrlen); |
178 |
250020 |
if (vsa != NULL) { |
179 |
250020 |
ret = func(priv, vsa); |
180 |
250020 |
VSA_free(&vsa); |
181 |
250020 |
if (ret) |
182 |
124745 |
break; |
183 |
125275 |
} |
184 |
125275 |
} |
185 |
226295 |
freeaddrinfo(res0); |
186 |
226295 |
return (ret); |
187 |
226395 |
} |
188 |
|
|
189 |
|
int |
190 |
226423 |
VSS_resolver(const char *addr, const char *def_port, vss_resolved_f *func, |
191 |
|
void *priv, const char **errp) |
192 |
|
{ |
193 |
226423 |
return (VSS_resolver_socktype( |
194 |
226423 |
addr, def_port, func, priv, errp, SOCK_STREAM)); |
195 |
|
} |
196 |
|
|
197 |
|
const struct suckaddr * |
198 |
26033 |
VSS_ResolveOne(void *dst, const char *addr, const char *def_port, |
199 |
|
int family, int socktype, int flags) |
200 |
|
{ |
201 |
26033 |
struct addrinfo *res = NULL; |
202 |
26033 |
const struct suckaddr *retval = NULL; |
203 |
|
const char *err; |
204 |
|
int ret; |
205 |
|
|
206 |
26033 |
AN(addr); |
207 |
26033 |
ret = vss_resolve(addr, def_port, family, socktype, flags, &res, &err); |
208 |
26033 |
if (ret == 0 && res != NULL && res->ai_next == NULL) { |
209 |
25758 |
AZ(err); |
210 |
25758 |
retval = vss_alloc_suckaddr(dst, res); |
211 |
25758 |
} |
212 |
26033 |
if (res != NULL) |
213 |
25758 |
freeaddrinfo(res); |
214 |
26033 |
return (retval); |
215 |
|
} |
216 |
|
|
217 |
|
const struct suckaddr * |
218 |
2200 |
VSS_ResolveFirst(void *dst, const char *addr, const char *def_port, |
219 |
|
int family, int socktype, int flags) |
220 |
|
{ |
221 |
2200 |
struct addrinfo *res0 = NULL, *res; |
222 |
2200 |
const struct suckaddr *retval = NULL; |
223 |
|
const char *err; |
224 |
|
int ret; |
225 |
|
|
226 |
2200 |
AN(addr); |
227 |
2200 |
ret = vss_resolve(addr, def_port, family, socktype, flags, &res0, &err); |
228 |
2200 |
if (ret == 0) |
229 |
1900 |
AZ(err); |
230 |
|
|
231 |
2225 |
for (res = res0; res != NULL; res = res->ai_next) { |
232 |
1900 |
retval = vss_alloc_suckaddr(dst, res); |
233 |
1900 |
if (retval != NULL) |
234 |
1875 |
break; |
235 |
25 |
} |
236 |
2200 |
if (res0 != NULL) |
237 |
1900 |
freeaddrinfo(res0); |
238 |
2200 |
return (retval); |
239 |
|
} |