varnish-cache/bin/varnishd/proxy/cache_proxy_proto.c
1
/*-
2
 * Copyright (c) 2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * Redistribution and use in source and binary forms, with or without
8
 * modification, are permitted provided that the following conditions
9
 * are met:
10
 * 1. Redistributions of source code must retain the above copyright
11
 *    notice, this list of conditions and the following disclaimer.
12
 * 2. Redistributions in binary form must reproduce the above copyright
13
 *    notice, this list of conditions and the following disclaimer in the
14
 *    documentation and/or other materials provided with the distribution.
15
 *
16
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
20
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26
 * SUCH DAMAGE.
27
 *
28
 */
29
30
#include "config.h"
31
32
#include <netinet/in.h>
33
#include <netdb.h>
34
35
#include "cache/cache_varnishd.h"
36
#include "cache/cache_transport.h"
37
38
#include "vend.h"
39
#include "vsa.h"
40
#include "vtcp.h"
41
42
/**********************************************************************
43
 * PROXY 1 protocol
44
 */
45
46
static const char vpx1_sig[] = {'P', 'R', 'O', 'X', 'Y'};
47
48
static int
49 64
vpx_proto1(const struct worker *wrk, struct req *req)
50
{
51
        const char *fld[5];
52
        int i;
53
        char *p, *q;
54
        struct addrinfo hints, *res;
55
        struct suckaddr *sa;
56 64
        int pfam = -1;
57
58 64
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
59 64
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
60 64
        CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC);
61
62 64
        q = strchr(req->htc->rxbuf_b, '\r');
63 64
        if (q == NULL)
64 2
                return (-1);
65
66 62
        *q++ = '\0';
67
        /* Nuke the CRLF */
68 62
        if (*q != '\n')
69 0
                return (-1);
70 62
        *q++ = '\0';
71
72
        /* Split the fields */
73 62
        p = req->htc->rxbuf_b;
74 370
        for (i = 0; i < 5; i++) {
75 310
                p = strchr(p, ' ');
76 310
                if (p == NULL) {
77 2
                        VSL(SLT_ProxyGarbage, req->sp->vxid,
78
                            "PROXY1: Too few fields");
79 2
                        return (-1);
80
                }
81 308
                *p++ = '\0';
82 308
                fld[i] = p;
83
        }
84
85 60
        if (strchr(p, ' ')) {
86 6
                VSL(SLT_ProxyGarbage, req->sp->vxid,
87
                    "PROXY1: Too many fields");
88 6
                return (-1);
89
        }
90
91 54
        if (!strcmp(fld[0], "TCP4"))
92 32
                pfam = AF_INET;
93 22
        else if (!strcmp(fld[0], "TCP6"))
94 20
                pfam = AF_INET6;
95
        else {
96 2
                VSL(SLT_ProxyGarbage, req->sp->vxid,
97
                    "PROXY1: Wrong TCP[46] field");
98 2
                return (-1);
99
        }
100
101 52
        memset(&hints, 0, sizeof hints);
102 52
        hints.ai_socktype = SOCK_STREAM;
103 52
        hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
104
105 52
        i = getaddrinfo(fld[1], fld[3], &hints, &res);
106 52
        if (i != 0) {
107 10
                VSL(SLT_ProxyGarbage, req->sp->vxid,
108
                    "PROXY1: Cannot resolve source address (%s)",
109
                    gai_strerror(i));
110 10
                return (-1);
111
        }
112 42
        AZ(res->ai_next);
113 42
        if (res->ai_family != pfam) {
114 4
                VSL(SLT_ProxyGarbage, req->sp->vxid,
115
                    "PROXY1: %s got wrong protocol (%d)",
116 4
                    fld[0], res->ai_family);
117 4
                freeaddrinfo(res);
118 4
                return (-1);
119
        }
120 38
        SES_Reserve_client_addr(req->sp, &sa);
121 38
        AN(VSA_Build(sa, res->ai_addr, res->ai_addrlen));
122 38
        SES_Set_String_Attr(req->sp, SA_CLIENT_IP, fld[1]);
123 38
        SES_Set_String_Attr(req->sp, SA_CLIENT_PORT, fld[3]);
124 38
        freeaddrinfo(res);
125
126 38
        i = getaddrinfo(fld[2], fld[4], &hints, &res);
127 38
        if (i != 0) {
128 6
                VSL(SLT_ProxyGarbage, req->sp->vxid,
129
                    "PROXY1: Cannot resolve destination address (%s)",
130
                    gai_strerror(i));
131 6
                return (-1);
132
        }
133 32
        AZ(res->ai_next);
134 32
        if (res->ai_family != pfam) {
135 0
                VSL(SLT_ProxyGarbage, req->sp->vxid,
136
                    "PROXY1: %s got wrong protocol (%d)",
137 0
                    fld[0], res->ai_family);
138 0
                freeaddrinfo(res);
139 0
                return (-1);
140
        }
141 32
        SES_Reserve_server_addr(req->sp, &sa);
142 32
        AN(VSA_Build(sa, res->ai_addr, res->ai_addrlen));
143 32
        freeaddrinfo(res);
144
145 32
        VSL(SLT_Proxy, req->sp->vxid, "1 %s %s %s %s",
146
            fld[1], fld[3], fld[2], fld[4]);
147 32
        HTC_RxPipeline(req->htc, q);
148 32
        WS_Reset(req->htc->ws, 0);
149 32
        return (0);
150
}
151
152
/**********************************************************************
153
 * PROXY 2 protocol
154
 */
155
156
static const char vpx2_sig[] = {
157
        '\r', '\n', '\r', '\n', '\0', '\r', '\n',
158
        'Q', 'U', 'I', 'T', '\n',
159
};
160
161
static int
162 32
vpx_proto2(const struct worker *wrk, struct req *req)
163
{
164
        int l;
165
        const uint8_t *p;
166 32
        sa_family_t pfam = 0xff;
167
        struct sockaddr_in sin4;
168
        struct sockaddr_in6 sin6;
169 32
        struct suckaddr *sa = NULL;
170
        char ha[VTCP_ADDRBUFSIZE];
171
        char pa[VTCP_PORTBUFSIZE];
172
        char hb[VTCP_ADDRBUFSIZE];
173
        char pb[VTCP_PORTBUFSIZE];
174
175 32
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
176 32
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
177 32
        CHECK_OBJ_NOTNULL(req->sp, SESS_MAGIC);
178
179 32
        assert(req->htc->rxbuf_e - req->htc->rxbuf_b >= 16L);
180 32
        l = vbe16dec(req->htc->rxbuf_b + 14);
181 32
        assert(req->htc->rxbuf_e - req->htc->rxbuf_b >= 16L + l);
182 32
        HTC_RxPipeline(req->htc, req->htc->rxbuf_b + 16L + l);
183 32
        WS_Reset(req->ws, 0);
184 32
        p = (const void *)req->htc->rxbuf_b;
185
186
        /* Version @12 top half */
187 32
        if ((p[12] >> 4) != 2) {
188 0
                VSL(SLT_ProxyGarbage, req->sp->vxid,
189 0
                    "PROXY2: bad version (%d)", p[12] >> 4);
190 0
                return (-1);
191
        }
192
193
        /* Command @12 bottom half */
194 32
        switch (p[12] & 0x0f) {
195
        case 0x0:
196
                /* Local connection from proxy, ignore addresses */
197 10
                return (0);
198
        case 0x1:
199
                /* Proxied connection */
200 20
                break;
201
        default:
202 2
                VSL(SLT_ProxyGarbage, req->sp->vxid,
203 2
                    "PROXY2: bad command (%d)", p[12] & 0x0f);
204 2
                return (-1);
205
        }
206
207
        /* Address family & protocol @13 */
208 20
        switch (p[13]) {
209
        case 0x00:
210
                /* UNSPEC|UNSPEC, ignore proxy header */
211 4
                VSL(SLT_ProxyGarbage, req->sp->vxid,
212
                    "PROXY2: Ignoring UNSPEC|UNSPEC addresses");
213 4
                return (0);
214
        case 0x11:
215
                /* IPv4|TCP */
216 8
                pfam = AF_INET;
217 8
                if (l < 12) {
218 2
                        VSL(SLT_ProxyGarbage, req->sp->vxid,
219
                            "PROXY2: Ignoring short IPv4 addresses (%d)", l);
220 2
                        return (0);
221
                }
222 6
                break;
223
        case 0x21:
224
                /* IPv6|TCP */
225 6
                pfam = AF_INET6;
226 6
                if (l < 36) {
227 2
                        VSL(SLT_ProxyGarbage, req->sp->vxid,
228
                            "PROXY2: Ignoring short IPv6 addresses (%d)", l);
229 2
                        return (0);
230
                }
231 4
                break;
232
        default:
233
                /* Ignore proxy header */
234 2
                VSL(SLT_ProxyGarbage, req->sp->vxid,
235 2
                    "PROXY2: Ignoring unsupported protocol (0x%02x)", p[13]);
236 2
                return (0);
237
        }
238
239 10
        switch (pfam) {
240
        case AF_INET:
241 6
                memset(&sin4, 0, sizeof sin4);
242 6
                sin4.sin_family = pfam;
243
244
                /* dst/server */
245 6
                memcpy(&sin4.sin_addr, p + 20, 4);
246 6
                memcpy(&sin4.sin_port, p + 26, 2);
247 6
                SES_Reserve_server_addr(req->sp, &sa);
248 6
                AN(VSA_Build(sa, &sin4, sizeof sin4));
249 6
                VTCP_name(sa, ha, sizeof ha, pa, sizeof pa);
250
251
                /* src/client */
252 6
                memcpy(&sin4.sin_addr, p + 16, 4);
253 6
                memcpy(&sin4.sin_port, p + 24, 2);
254 6
                SES_Reserve_client_addr(req->sp, &sa);
255 6
                AN(VSA_Build(sa, &sin4, sizeof sin4));
256 6
                break;
257
        case AF_INET6:
258 4
                memset(&sin6, 0, sizeof sin6);
259 4
                sin6.sin6_family = pfam;
260
261
                /* dst/server */
262 4
                memcpy(&sin6.sin6_addr, p + 32, 16);
263 4
                memcpy(&sin6.sin6_port, p + 50, 2);
264 4
                SES_Reserve_server_addr(req->sp, &sa);
265 4
                AN(VSA_Build(sa, &sin6, sizeof sin6));
266 4
                VTCP_name(sa, ha, sizeof ha, pa, sizeof pa);
267
268
                /* src/client */
269 4
                memcpy(&sin6.sin6_addr, p + 16, 16);
270 4
                memcpy(&sin6.sin6_port, p + 48, 2);
271 4
                SES_Reserve_client_addr(req->sp, &sa);
272 4
                AN(VSA_Build(sa, &sin6, sizeof sin6));
273 4
                break;
274
        default:
275 0
                WRONG("Wrong pfam");
276
        }
277
278 10
        AN(sa);
279 10
        VTCP_name(sa, hb, sizeof hb, pb, sizeof pb);
280 10
        SES_Set_String_Attr(req->sp, SA_CLIENT_IP, hb);
281 10
        SES_Set_String_Attr(req->sp, SA_CLIENT_PORT, pb);
282
283 10
        VSL(SLT_Proxy, req->sp->vxid, "2 %s %s %s %s", hb, pb, ha, pa);
284 10
        return (0);
285
}
286
287
/**********************************************************************
288
 * HTC_Rx completion detector
289
 */
290
291
static enum htc_status_e v_matchproto_(htc_complete_f)
292 214
vpx_complete(struct http_conn *htc)
293
{
294
        int i, l, j;
295
        char *p, *q;
296
297 214
        CHECK_OBJ_NOTNULL(htc, HTTP_CONN_MAGIC);
298
299 214
        assert(htc->rxbuf_e >= htc->rxbuf_b);
300 214
        assert(htc->rxbuf_e <= htc->ws->r);
301
302 214
        l = htc->rxbuf_e - htc->rxbuf_b;
303 214
        p = htc->rxbuf_b;
304 214
        j = 0x3;
305 1044
        for (i = 0; i < l; i++) {
306 941
                if (i < sizeof vpx1_sig && p[i] != vpx1_sig[i])
307 202
                        j &= ~1;
308 941
                if (i < sizeof vpx2_sig && p[i] != vpx2_sig[i])
309 422
                        j &= ~2;
310 941
                if (j == 0)
311 2
                        return (HTC_S_JUNK);
312 939
                if (j == 1 && i == sizeof vpx1_sig) {
313 70
                        assert (htc->rxbuf_e < htc->ws->r);
314 70
                        *htc->rxbuf_e = '\0';
315 70
                        q = strchr(p + i, '\n');
316 70
                        if (q != NULL && (q - htc->rxbuf_b) > 107)
317 2
                                return (HTC_S_OVERFLOW);
318 68
                        if (q == NULL)
319 4
                                return (HTC_S_MORE);
320 64
                        return (HTC_S_COMPLETE);
321
                }
322 869
                if (j == 2 && i == sizeof vpx2_sig) {
323 39
                        if (l < 16)
324 0
                                return (HTC_S_MORE);
325 39
                        j = vbe16dec(p + 14);
326 39
                        if (l < 16 + j)
327 7
                                return (HTC_S_MORE);
328 32
                        return (HTC_S_COMPLETE);
329
                }
330
        }
331 103
        return (HTC_S_MORE);
332
}
333
334
static void v_matchproto_(task_func_t)
335 102
vpx_new_session(struct worker *wrk, void *arg)
336
{
337
        struct req *req;
338
        struct sess *sp;
339
        enum htc_status_e hs;
340
        char *p;
341
        int i;
342
343 102
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
344 102
        CAST_OBJ_NOTNULL(req, arg, REQ_MAGIC);
345 102
        sp = req->sp;
346 102
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
347
348
        /* Per specification */
349
        assert(sizeof vpx1_sig == 5);
350
        assert(sizeof vpx2_sig == 12);
351
352 102
        HTC_RxInit(req->htc, req->ws);
353 102
        hs = HTC_RxStuff(req->htc, vpx_complete,
354 102
            NULL, NULL, NAN, sp->t_idle + cache_param->timeout_idle,
355
            1024);                      // XXX ?
356 102
        if (hs != HTC_S_COMPLETE) {
357 6
                Req_Release(req);
358 6
                SES_Delete(sp, SC_RX_JUNK, NAN);
359 6
                return;
360
        }
361 96
        p = req->htc->rxbuf_b;
362 96
        if (p[0] == vpx1_sig[0])
363 64
                i = vpx_proto1(wrk, req);
364 32
        else if (p[0] == vpx2_sig[0])
365 32
                i = vpx_proto2(wrk, req);
366
        else
367 0
                WRONG("proxy sig mismatch");
368
369 96
        if (i) {
370 34
                Req_Release(req);
371 34
                SES_Delete(sp, SC_RX_JUNK, NAN);
372 34
                return;
373
        }
374
375 62
        SES_SetTransport(wrk, sp, req, &HTTP1_transport);
376
}
377
378
struct transport PROXY_transport = {
379
        .name =                 "PROXY",
380
        .proto_ident =          "PROXY",
381
        .magic =                TRANSPORT_MAGIC,
382
        .new_session =          vpx_new_session,
383
};
384
385
static void
386 8
vpx_enc_addr(struct vsb *vsb, int proto, const struct suckaddr *s)
387
{
388
        const struct sockaddr_in *sin4;
389
        const struct sockaddr_in6 *sin6;
390
        socklen_t sl;
391
392 8
        if (proto == PF_INET6) {
393 4
                sin6 = VSA_Get_Sockaddr(s, &sl);        //lint !e826
394 4
                AN(sin6);
395 4
                assert(sl >= sizeof *sin6);
396 4
                VSB_bcat(vsb, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
397
        } else {
398 4
                sin4 = VSA_Get_Sockaddr(s, &sl);        //lint !e826
399 4
                AN(sin4);
400 4
                assert(sl >= sizeof *sin4);
401 4
                VSB_bcat(vsb, &sin4->sin_addr, sizeof(sin4->sin_addr));
402
        }
403 8
}
404
405
static void
406 8
vpx_enc_port(struct vsb *vsb, const struct suckaddr *s)
407
{
408
        uint8_t b[2];
409
410 8
        vbe16enc(b, (uint16_t)VSA_Port(s));
411 8
        VSB_bcat(vsb, b, sizeof(b));
412 8
}
413
414
void
415 8
VPX_Send_Proxy(int fd, int version, const struct sess *sp)
416
{
417
        struct vsb *vsb, *vsb2;
418
        const char *p1, *p2;
419
        struct suckaddr *sac, *sas;
420
        char ha[VTCP_ADDRBUFSIZE];
421
        char pa[VTCP_PORTBUFSIZE];
422
        int proto;
423
424 8
        CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
425 8
        assert(version == 1 || version == 2);
426 8
        vsb = VSB_new_auto();
427 8
        AN(vsb);
428
429 8
        AZ(SES_Get_server_addr(sp, &sas));
430 8
        AN(sas);
431 8
        proto = VSA_Get_Proto(sas);
432 8
        assert(proto == PF_INET6 || proto == PF_INET);
433
434 8
        if (version == 1) {
435 4
                VSB_bcat(vsb, vpx1_sig, sizeof(vpx1_sig));
436 4
                p1 = SES_Get_String_Attr(sp, SA_CLIENT_IP);
437 4
                AN(p1);
438 4
                p2 = SES_Get_String_Attr(sp, SA_CLIENT_PORT);
439 4
                AN(p2);
440 4
                VTCP_name(sas, ha, sizeof ha, pa, sizeof pa);
441 4
                if (proto == PF_INET6)
442 2
                        VSB_printf(vsb, " TCP6 ");
443 2
                else if (proto == PF_INET)
444 2
                        VSB_printf(vsb, " TCP4 ");
445 4
                VSB_printf(vsb, "%s %s %s %s\r\n", p1, ha, p2, pa);
446 4
        } else if (version == 2) {
447 4
                AZ(SES_Get_client_addr(sp, &sac));
448 4
                AN(sac);
449
450 4
                VSB_bcat(vsb, vpx2_sig, sizeof(vpx2_sig));
451 4
                VSB_putc(vsb, 0x21);
452 4
                if (proto == PF_INET6) {
453 2
                        VSB_putc(vsb, 0x21);
454 2
                        VSB_putc(vsb, 0x00);
455 2
                        VSB_putc(vsb, 0x24);
456 2
                } else if (proto == PF_INET) {
457 2
                        VSB_putc(vsb, 0x11);
458 2
                        VSB_putc(vsb, 0x00);
459 2
                        VSB_putc(vsb, 0x0c);
460
                }
461 4
                vpx_enc_addr(vsb, proto, sac);
462 4
                vpx_enc_addr(vsb, proto, sas);
463 4
                vpx_enc_port(vsb, sac);
464 4
                vpx_enc_port(vsb, sas);
465
        } else
466 0
                WRONG("Wrong proxy version");
467
468 8
        AZ(VSB_finish(vsb));
469 8
        (void)write(fd, VSB_data(vsb), VSB_len(vsb));
470 8
        if (!DO_DEBUG(DBG_PROTOCOL)) {
471 8
                VSB_delete(vsb);
472 16
                return;
473
        }
474
475 0
        vsb2 = VSB_new_auto();
476 0
        AN(vsb2);
477 0
        VSB_quote(vsb2, VSB_data(vsb), VSB_len(vsb),
478
            version == 2 ? VSB_QUOTE_HEX : 0);
479 0
        AZ(VSB_finish(vsb2));
480 0
        VSL(SLT_Debug, 999, "PROXY_HDR %s", VSB_data(vsb2));
481 0
        VSB_delete(vsb);
482 0
        VSB_delete(vsb2);
483
}