varnish-cache/lib/libvarnish/vss.c
1
/*-
2
 * Copyright (c) 2006 Verdens Gang AS
3
 * Copyright (c) 2006-2010 Varnish Software AS
4
 * All rights reserved.
5
 *
6
 * Author: Dag-Erling Smørgrav <des@des.no>
7
 * Author: Cecilie Fritzvold <cecilihf@linpro.no>
8
 *
9
 * SPDX-License-Identifier: BSD-2-Clause
10
 *
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 * 1. Redistributions of source code must retain the above copyright
15
 *    notice, this list of conditions and the following disclaimer.
16
 * 2. Redistributions in binary form must reproduce the above copyright
17
 *    notice, this list of conditions and the following disclaimer in the
18
 *    documentation and/or other materials provided with the distribution.
19
 *
20
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
24
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30
 * SUCH DAMAGE.
31
 */
32
33
#include "config.h"
34
35
#include <sys/socket.h>
36
37
#include <netdb.h>
38
#include <stdlib.h>
39
#include <string.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 370638
vss_parse(char *str, char **addr, char **port)
66
{
67
        char *p;
68
69 370638
        *addr = *port = NULL;
70
71 370638
        if (str[0] == '[') {
72
                /* IPv6 address of the form [::1]:80 */
73 920
                *addr = str + 1;
74 920
                p = strchr(str, ']');
75 920
                if (p == NULL)
76 40
                        return ("IPv6 address lacks ']'");
77 880
                *p++ = '\0';
78 880
                if (*p == '\0')
79 280
                        return (NULL);
80 600
                if (*p != ' ' && *p != ':')
81 40
                        return ("IPv6 address has wrong port separator");
82 560
        } else {
83
                /*
84
                 * IPv4 address of the form 127.0.0.1:80, IPv6 address
85
                 * without port or non-numeric.
86
                 */
87 369718
                *addr = str;
88 369718
                p = strchr(str, ' ');
89 369718
                if (p == NULL)
90 300120
                        p = strchr(str, ':');
91 369720
                if (p == NULL)
92 45162
                        return (NULL);
93 324558
                if (p[0] == ':' && strchr(&p[1], ':'))
94 1400
                        return (NULL);
95 323158
                if (p == str)
96 36480
                        *addr = NULL;
97
        }
98 323718
        *p++ = '\0';
99 323718
        *port = p;
100 323718
        return (NULL);
101 370640
}
102
103
static int
104 370636
vss_resolve(const char *addr, const char *def_port, int family, int socktype,
105
    int flags, struct addrinfo **res, const char **errp)
106
{
107
        struct addrinfo hints;
108
        char *p, *hp, *pp;
109
        int ret;
110
111 370636
        AN(addr);
112 370636
        AN(res);
113 370635
        AZ(*res);
114 370636
        AN(errp);
115 370635
        *errp = NULL;
116
117 370635
        memset(&hints, 0, sizeof hints);
118 370635
        hints.ai_family = family;
119 370635
        hints.ai_socktype = socktype;
120 370635
        hints.ai_flags = flags;
121
122 370635
        p = strdup(addr);
123 370635
        AN(p);
124 370638
        *errp = vss_parse(p, &hp, &pp);
125 370638
        if (*errp != NULL) {
126 80
                free(p);
127 80
                return (-1);
128
        }
129 370559
        if (pp != NULL)
130 323717
                def_port = pp;
131 370560
        ret = getaddrinfo(hp, def_port, &hints, res);
132 370560
        free(p);
133
134 370560
        if (ret == EAI_SYSTEM)
135 0
                *errp = VAS_errtxt(errno);
136 370557
        else if (ret != 0)
137 1000
                *errp = gai_strerror(ret);
138
139 370557
        return (ret);
140 370638
}
141
142
static struct suckaddr *
143 39922
vss_alloc_suckaddr(void *dst, const struct addrinfo *ai)
144
{
145
146 39922
        AN(ai);
147 39922
        if (dst == NULL)
148 36480
                return (VSA_Malloc(ai->ai_addr, ai->ai_addrlen));
149
150 3442
        return (VSA_Build(dst, ai->ai_addr, ai->ai_addrlen));
151 39922
}
152
153
/*
154
 * Look up an address, using a default port if provided, and call
155
 * the callback function with the suckaddrs we find.
156
 * If the callback function returns anything but zero, we terminate
157
 * and pass that value.
158
 */
159
160
int
161 329798
VSS_resolver_socktype(const char *addr, const char *def_port,
162
    vss_resolved_f *func, void *priv, const char **errp, int socktype)
163
{
164 329798
        struct addrinfo *res0 = NULL, *res;
165
        struct suckaddr *vsa;
166
        int ret;
167
168 329798
        AN(addr);
169 329798
        AN(func);
170 329799
        AN(errp);
171
172 659596
        ret = vss_resolve(addr, def_port, AF_UNSPEC, socktype, AI_PASSIVE,
173 329798
            &res0, errp);
174 329798
        if (ret != 0)
175 160
                return (-1);
176
177 510635
        for (res = res0; res != NULL; res = res->ai_next) {
178 363155
                vsa = VSA_Malloc(res->ai_addr, res->ai_addrlen);
179 363155
                if (vsa != NULL) {
180 363158
                        ret = func(priv, vsa);
181 363158
                        free(vsa);
182 363158
                        if (ret)
183 182079
                                break;
184 181000
                }
185 181000
        }
186 329559
        freeaddrinfo(res0);
187 329559
        return (ret);
188 329719
}
189
190
int
191 329791
VSS_resolver(const char *addr, const char *def_port, vss_resolved_f *func,
192
    void *priv, const char **errp)
193
{
194 329791
        return (VSS_resolver_socktype(
195 329791
            addr, def_port, func, priv, errp, SOCK_STREAM));
196
}
197
198
struct suckaddr *
199 38799
VSS_ResolveOne(void *dst, const char *addr, const char *def_port,
200
    int family, int socktype, int flags)
201
{
202 38799
        struct addrinfo *res = NULL;
203 38799
        struct suckaddr *retval = NULL;
204
        const char *err;
205
        int ret;
206
207 38799
        AN(addr);
208 38799
        ret = vss_resolve(addr, def_port, family, socktype, flags, &res, &err);
209 38799
        if (ret == 0 && res != NULL && res->ai_next == NULL) {
210 38362
                AZ(err);
211 38362
                retval = vss_alloc_suckaddr(dst, res);
212 38362
        }
213 38802
        if (res != NULL)
214 38362
                freeaddrinfo(res);
215 38802
        return (retval);
216
}
217
218
struct suckaddr *
219 2040
VSS_ResolveFirst(void *dst, const char *addr, const char *def_port,
220
    int family, int socktype, int flags)
221
{
222 2040
        struct addrinfo *res0 = NULL, *res;
223 2040
        struct suckaddr *retval = NULL;
224
        const char *err;
225
        int ret;
226
227 2040
        AN(addr);
228 2040
        ret = vss_resolve(addr, def_port, family, socktype, flags, &res0, &err);
229 2040
        if (ret == 0)
230 1560
                AZ(err);
231
232 2080
        for (res = res0; res != NULL; res = res->ai_next) {
233 1560
                retval = vss_alloc_suckaddr(dst, res);
234 1560
                if (retval != NULL)
235 1520
                        break;
236 40
        }
237 2040
        if (res0 != NULL)
238 1560
                freeaddrinfo(res0);
239 2040
        return (retval);
240
}