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
}