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 267165
vss_parse(char *str, char **addr, char **port)
65
{
66
        char *p;
67
68 267165
        *addr = *port = NULL;
69
70 267165
        if (str[0] == '[') {
71
                /* IPv6 address of the form [::1]:80 */
72 756
                *addr = str + 1;
73 756
                p = strchr(str, ']');
74 756
                if (p == NULL)
75 27
                        return ("IPv6 address lacks ']'");
76 729
                *p++ = '\0';
77 729
                if (*p == '\0')
78 216
                        return (NULL);
79 513
                if (*p != ' ' && *p != ':')
80 27
                        return ("IPv6 address has wrong port separator");
81 486
        } else {
82
                /*
83
                 * IPv4 address of the form 127.0.0.1:80, IPv6 address
84
                 * without port or non-numeric.
85
                 */
86 266409
                *addr = str;
87 266409
                p = strchr(str, ' ');
88 266409
                if (p == NULL)
89 216189
                        p = strchr(str, ':');
90 266409
                if (p == NULL)
91 31806
                        return (NULL);
92 234603
                if (p[0] == ':' && strchr(&p[1], ':'))
93 945
                        return (NULL);
94 233658
                if (p == str)
95 26217
                        *addr = NULL;
96
        }
97 234144
        *p++ = '\0';
98 234144
        *port = p;
99 234144
        return (NULL);
100 267165
}
101
102
static int
103 267164
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 267164
        AN(addr);
111 267164
        AN(res);
112 267164
        AZ(*res);
113 267164
        AN(errp);
114 267164
        *errp = NULL;
115
116 267164
        memset(&hints, 0, sizeof hints);
117 267164
        hints.ai_family = family;
118 267164
        hints.ai_socktype = socktype;
119 267164
        hints.ai_flags = flags;
120
121 267164
        p = strdup(addr);
122 267164
        AN(p);
123 267164
        *errp = vss_parse(p, &hp, &pp);
124 267164
        if (*errp != NULL) {
125 54
                free(p);
126 54
                return (-1);
127
        }
128 267110
        if (pp != NULL)
129 234144
                def_port = pp;
130 267110
        ret = getaddrinfo(hp, def_port, &hints, res);
131 267110
        free(p);
132
133 267110
        if (ret == EAI_SYSTEM)
134 0
                *errp = VAS_errtxt(errno);
135 267110
        else if (ret != 0)
136 675
                *errp = gai_strerror(ret);
137
138 267110
        return (ret);
139 267164
}
140
141
static const struct suckaddr *
142 28620
vss_alloc_suckaddr(void *dst, const struct addrinfo *ai)
143
{
144
145 28620
        AN(ai);
146 28620
        if (dst == NULL)
147 26190
                return (VSA_Malloc(ai->ai_addr, ai->ai_addrlen));
148
149 2430
        return (VSA_Build(dst, ai->ai_addr, ai->ai_addrlen));
150 28620
}
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 237865
VSS_resolver_socktype(const char *addr, const char *def_port,
161
    vss_resolved_f *func, void *priv, const char **errp, int socktype)
162
{
163 237865
        struct addrinfo *res0 = NULL, *res;
164
        const struct suckaddr *vsa;
165
        int ret;
166
167 237865
        AN(addr);
168 237865
        AN(func);
169 237865
        AN(errp);
170
171 475730
        ret = vss_resolve(addr, def_port, AF_UNSPEC, socktype, AI_PASSIVE,
172 237865
            &res0, errp);
173 237865
        if (ret != 0)
174 108
                return (-1);
175
176 367438
        for (res = res0; res != NULL; res = res->ai_next) {
177 262084
                vsa = VSA_Malloc(res->ai_addr, res->ai_addrlen);
178 262084
                if (vsa != NULL) {
179 262084
                        ret = func(priv, vsa);
180 262084
                        VSA_free(&vsa);
181 262084
                        if (ret)
182 132403
                                break;
183 129681
                }
184 129681
        }
185 237757
        freeaddrinfo(res0);
186 237757
        return (ret);
187 237865
}
188
189
int
190 237896
VSS_resolver(const char *addr, const char *def_port, vss_resolved_f *func,
191
    void *priv, const char **errp)
192
{
193 237896
        return (VSS_resolver_socktype(
194 237896
            addr, def_port, func, priv, errp, SOCK_STREAM));
195
}
196
197
const struct suckaddr *
198 27756
VSS_ResolveOne(void *dst, const char *addr, const char *def_port,
199
    int family, int socktype, int flags)
200
{
201 27756
        struct addrinfo *res = NULL;
202 27756
        const struct suckaddr *retval = NULL;
203
        const char *err;
204
        int ret;
205
206 27756
        AN(addr);
207 27756
        ret = vss_resolve(addr, def_port, family, socktype, flags, &res, &err);
208 27756
        if (ret == 0 && res != NULL && res->ai_next == NULL) {
209 27459
                AZ(err);
210 27459
                retval = vss_alloc_suckaddr(dst, res);
211 27459
        }
212 27756
        if (res != NULL)
213 27459
                freeaddrinfo(res);
214 27756
        return (retval);
215
}
216
217
const struct suckaddr *
218 1485
VSS_ResolveFirst(void *dst, const char *addr, const char *def_port,
219
    int family, int socktype, int flags)
220
{
221 1485
        struct addrinfo *res0 = NULL, *res;
222 1485
        const struct suckaddr *retval = NULL;
223
        const char *err;
224
        int ret;
225
226 1485
        AN(addr);
227 1485
        ret = vss_resolve(addr, def_port, family, socktype, flags, &res0, &err);
228 1485
        if (ret == 0)
229 1161
                AZ(err);
230
231 1512
        for (res = res0; res != NULL; res = res->ai_next) {
232 1161
                retval = vss_alloc_suckaddr(dst, res);
233 1161
                if (retval != NULL)
234 1134
                        break;
235 27
        }
236 1485
        if (res0 != NULL)
237 1161
                freeaddrinfo(res0);
238 1485
        return (retval);
239
}