vinyl-cache/lib/libvinyl/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 40326
vss_parse(char *str, char **addr, char **port)
66
{
67
        char *p;
68
69 40326
        *addr = *port = NULL;
70
71 40326
        if (str[0] == '[') {
72
                /* IPv6 address of the form [::1]:80 */
73 144
                *addr = str + 1;
74 144
                p = strchr(str, ']');
75 144
                if (p == NULL)
76 3
                        return ("IPv6 address lacks ']'");
77 141
                *p++ = '\0';
78 141
                if (*p == '\0')
79 33
                        return (NULL);
80 108
                if (*p != ' ' && *p != ':')
81 3
                        return ("IPv6 address has wrong port separator");
82 105
        } else {
83
                /*
84
                 * IPv4 address of the form 127.0.0.1:80, IPv6 address
85
                 * without port or non-numeric.
86
                 */
87 40182
                *addr = str;
88 40182
                p = strchr(str, ' ');
89 40182
                if (p == NULL)
90 33747
                        p = strchr(str, ':');
91 40182
                if (p == NULL)
92 7332
                        return (NULL);
93 32850
                if (p[0] == ':' && strchr(&p[1], ':'))
94 126
                        return (NULL);
95 32724
                if (p == str)
96 3555
                        *addr = NULL;
97
        }
98 32829
        *p++ = '\0';
99 32829
        *port = p;
100 32829
        return (NULL);
101 40326
}
102
103
static const char *
104 3114
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 3114
        errp = vss_parse(str, addr, port);
112 3114
        if (errp != NULL)
113 0
                return (errp);
114 3114
        if (*port == NULL || **port == '-')
115 39
                return (NULL);
116
117 3075
        l = strtoul(*port, &end, 10);
118 3075
        if (end[0] != '-' || end[1] == '\0')
119 3006
                return (NULL);
120 69
        if (strchr(end + 1, '-') != NULL)
121 6
                return (NULL);
122 63
        h = strtoul(end + 1, &end, 10);
123 63
        if (end[0] != '\0')
124 9
                return (NULL);
125
126
        /* Port range of the form 80-81 */
127 54
        if (l == 0)
128 3
                return ("Range start cannot be 0");
129 51
        if (h < l)
130 3
                return ("Range start higher than range end");
131 48
        if (h > 65535)
132 3
                return ("Range end higher than 65535");
133
134 45
        *lo = l;
135 45
        *hi = h;
136 45
        return (NULL);
137 3114
}
138
139
static int
140 37212
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 37212
        AN(addr);
148 37212
        AN(res);
149 37212
        AZ(*res);
150 37212
        AN(errp);
151 37212
        *errp = NULL;
152
153 37212
        memset(&hints, 0, sizeof hints);
154 37212
        hints.ai_family = family;
155 37212
        hints.ai_socktype = socktype;
156 37212
        hints.ai_flags = flags;
157
158 37212
        p = strdup(addr);
159 37212
        AN(p);
160 37212
        *errp = vss_parse(p, &hp, &pp);
161 37212
        if (*errp != NULL) {
162 6
                free(p);
163 6
                return (-1);
164
        }
165 37206
        if (pp != NULL)
166 29730
                def_port = pp;
167 37206
        ret = getaddrinfo(hp, def_port, &hints, res);
168 37206
        free(p);
169
170 37206
        if (ret == EAI_SYSTEM)
171 0
                *errp = VAS_errtxt(errno);
172 37206
        else if (ret != 0)
173 156
                *errp = gai_strerror(ret);
174
175 37206
        return (ret);
176 37212
}
177
178
static const struct suckaddr *
179 6918
vss_alloc_suckaddr(void *dst, const struct addrinfo *ai)
180
{
181
182 6918
        AN(ai);
183 6918
        if (dst == NULL)
184 6561
                return (VSA_Malloc(ai->ai_addr, ai->ai_addrlen));
185
186 357
        return (VSA_Build(dst, ai->ai_addr, ai->ai_addrlen));
187 6918
}
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 30193
VSS_resolver_socktype(const char *addr, const char *def_port,
198
    vss_resolved_f *func, void *priv, const char **errp, int socktype)
199
{
200 30193
        struct addrinfo *res0 = NULL, *res;
201
        const struct suckaddr *vsa;
202
        int ret;
203
204 30193
        AN(addr);
205 30193
        AN(func);
206 30193
        AN(errp);
207
208 60386
        ret = vss_resolve(addr, def_port, AF_UNSPEC, socktype, AI_PASSIVE,
209 30193
            &res0, errp);
210 30193
        if (ret != 0)
211 69
                return (-1);
212
213 46636
        for (res = res0; res != NULL; res = res->ai_next) {
214 33259
                vsa = VSA_Malloc(res->ai_addr, res->ai_addrlen);
215 33259
                if (vsa != NULL) {
216 33259
                        ret = func(priv, vsa);
217 33259
                        VSA_free(&vsa);
218 33259
                        if (ret)
219 16747
                                break;
220 16512
                }
221 16512
        }
222 30124
        freeaddrinfo(res0);
223 30124
        return (ret);
224 30193
}
225
226
int
227 30198
VSS_resolver(const char *addr, const char *def_port, vss_resolved_f *func,
228
    void *priv, const char **errp)
229
{
230 30198
        return (VSS_resolver_socktype(
231 30198
            addr, def_port, func, priv, errp, SOCK_STREAM));
232
}
233
234
int
235 3114
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 3114
        unsigned long lo = 0, hi = 0, i;
240 3114
        int error = 0;
241
242 3114
        AN(addr);
243 3114
        AN(func);
244 3114
        AN(errp);
245
246 3114
        p = strdup(addr);
247 3114
        AN(p);
248 3114
        *errp = vss_parse_range(p, &hp, &pp, &lo, &hi);
249 3114
        if (*errp != NULL) {
250 9
                free(p);
251 9
                return (-1);
252
        }
253
254 3105
        if (lo == 0) {
255
                /* No port range (0 not allowed in range) */
256 3060
                free(p);
257 3060
                return (VSS_resolver(addr, def_port, func, priv, errp));
258
        }
259
260
        /* Undo vss_parse() string modifications */
261 45
        memcpy(p, addr, pp - p);
262
263 132
        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 87
                sprintf(pp, "%lu", i);
269 87
                error = VSS_resolver(p, def_port, func, priv, errp);
270 87
        }
271 45
        free(p);
272 45
        return (error);
273 3114
}
274
275
const struct suckaddr *
276 6741
VSS_ResolveOne(void *dst, const char *addr, const char *def_port,
277
    int family, int socktype, int flags)
278
{
279 6741
        struct addrinfo *res = NULL;
280 6741
        const struct suckaddr *retval = NULL;
281
        const char *err;
282
        int ret;
283
284 6741
        AN(addr);
285 6741
        ret = vss_resolve(addr, def_port, family, socktype, flags, &res, &err);
286 6741
        if (ret == 0 && res != NULL && res->ai_next == NULL) {
287 6684
                AZ(err);
288 6684
                retval = vss_alloc_suckaddr(dst, res);
289 6684
        }
290 6741
        if (res != NULL)
291 6684
                freeaddrinfo(res);
292 6741
        return (retval);
293
}
294
295
const struct suckaddr *
296 270
VSS_ResolveFirst(void *dst, const char *addr, const char *def_port,
297
    int family, int socktype, int flags)
298
{
299 270
        struct addrinfo *res0 = NULL, *res;
300 270
        const struct suckaddr *retval = NULL;
301
        const char *err;
302
        int ret;
303
304 270
        AN(addr);
305 270
        ret = vss_resolve(addr, def_port, family, socktype, flags, &res0, &err);
306 270
        if (ret == 0)
307 234
                AZ(err);
308
309 273
        for (res = res0; res != NULL; res = res->ai_next) {
310 234
                retval = vss_alloc_suckaddr(dst, res);
311 234
                if (retval != NULL)
312 231
                        break;
313 3
        }
314 270
        if (res0 != NULL)
315 234
                freeaddrinfo(res0);
316 270
        return (retval);
317
}