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
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 */
30
31
#include "config.h"
32
33
#include <sys/socket.h>
34
35
#include <netdb.h>
36
#include <stdlib.h>
37
#include <string.h>
38
39
#include "vdef.h"
40
41
#include "vas.h"
42
#include "vsa.h"
43
#include "vss.h"
44
45
/*lint -esym(754, _storage) not ref */
46
47
/*
48
 * Take a string provided by the user and break it up into address and
49
 * port parts.  Examples of acceptable input include:
50
 *
51
 * "localhost" - "localhost:80"
52
 * "127.0.0.1" - "127.0.0.1:80"
53
 * "0.0.0.0" - "0.0.0.0:80"
54
 * "[::1]" - "[::1]:80"
55
 * "[::]" - "[::]:80"
56
 * "::1" - "[::1]:80"
57
 *
58
 * See also RFC5952
59
 */
60
61
static const char *
62 14832
vss_parse(char *str, char **addr, char **port)
63
{
64
        char *p;
65
66 14832
        *addr = *port = NULL;
67
68 14832
        if (str[0] == '[') {
69
                /* IPv6 address of the form [::1]:80 */
70 34
                *addr = str + 1;
71 34
                p = strchr(str, ']');
72 34
                if (p == NULL)
73 2
                        return ("IPv6 address lacks ']'");
74 32
                *p++ = '\0';
75 32
                if (*p == '\0')
76 10
                        return (NULL);
77 22
                if (*p != ' ' && *p != ':')
78 2
                        return ("IPv6 address has wrong port separator");
79
        } else {
80
                /*
81
                 * IPv4 address of the form 127.0.0.1:80, IPv6 address
82
                 * without port or non-numeric.
83
                 */
84 14798
                *addr = str;
85 14798
                p = strchr(str, ' ');
86 14798
                if (p == NULL)
87 8248
                        p = strchr(str, ':');
88 14798
                if (p == NULL)
89 2950
                        return (NULL);
90 11848
                if (p[0] == ':' && strchr(&p[1], ':'))
91 8
                        return (NULL);
92 11840
                if (p == str)
93 1438
                        *addr = NULL;
94
        }
95 11860
        *p++ = '\0';
96 11860
        *port = p;
97 11860
        return (NULL);
98
}
99
100
/*
101
 * Look up an address, using a default port if provided, and call
102
 * the callback function with the suckaddrs we find.
103
 * If the callback function returns anything but zero, we terminate
104
 * and pass that value.
105
 */
106
107
int
108 14832
VSS_resolver(const char *addr, const char *def_port, vss_resolved_f *func,
109
    void *priv, const char **err)
110
{
111
        struct addrinfo hints, *res0, *res;
112
        struct suckaddr *vsa;
113
        char *h;
114
        char *adp, *hop;
115
        int ret;
116
117 14832
        *err = NULL;
118 14832
        h = strdup(addr);
119 14832
        AN(h);
120 14832
        *err = vss_parse(h, &hop, &adp);
121 14832
        if (*err != NULL) {
122 4
                free(h);
123 4
                return (-1);
124
        }
125 14828
        if (adp != NULL)
126 11860
                def_port = adp;
127
128 14828
        memset(&hints, 0, sizeof hints);
129 14828
        hints.ai_socktype = SOCK_STREAM;
130 14828
        hints.ai_flags = AI_PASSIVE;
131 14828
        ret = getaddrinfo(hop, def_port, &hints, &res0);
132 14828
        free(h);
133 14828
        if (ret != 0) {
134 4
                *err = gai_strerror(ret);
135 4
                return (-1);
136
        }
137 23062
        for (res = res0; res != NULL; res = res->ai_next) {
138 16108
                vsa = VSA_Malloc(res->ai_addr, res->ai_addrlen);
139 16108
                if (vsa != NULL) {
140 16108
                        ret = func(priv, vsa);
141 16104
                        free(vsa);
142 16104
                        if (ret)
143 7866
                                break;
144
                }
145
        }
146 14820
        freeaddrinfo(res0);
147 14820
        return (ret);
148
}