varnish-cache/bin/varnishtest/vtc_proxy.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
#include "config.h"
30
31
#include <sys/socket.h>
32
33
#include <netinet/in.h>
34
35
#include <unistd.h>
36
37
#include "vtc.h"
38
39
#include "vend.h"
40
#include "vsa.h"
41
#include "vtcp.h"
42
43
static const char vpx1_sig[] = {'P', 'R', 'O', 'X', 'Y'};
44
static const char vpx2_sig[] = {
45
        '\r', '\n', '\r', '\n', '\0', '\r', '\n',
46
        'Q', 'U', 'I', 'T', '\n',
47
};
48
49
static void
50 8
vpx_enc_addr(struct vsb *vsb, int proto, const struct suckaddr *s)
51
{
52
        const struct sockaddr_in *sin4;
53
        const struct sockaddr_in6 *sin6;
54
        socklen_t sl;
55
56 8
        if (proto == PF_INET6) {
57 4
                sin6 = VSA_Get_Sockaddr(s, &sl);        //lint !e826
58 4
                AN(sin6);
59 4
                assert(sl >= sizeof(*sin6));
60 4
                VSB_bcat(vsb, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
61
        } else {
62 4
                sin4 = VSA_Get_Sockaddr(s, &sl);        //lint !e826
63 4
                AN(sin4);
64 4
                assert(sl >= sizeof(*sin4));
65 4
                VSB_bcat(vsb, &sin4->sin_addr, sizeof(sin4->sin_addr));
66
        }
67 8
}
68
69
static void
70 8
vpx_enc_port(struct vsb *vsb, const struct suckaddr *s)
71
{
72
        uint8_t b[2];
73
74 8
        vbe16enc(b, (uint16_t)VSA_Port(s));
75 8
        VSB_bcat(vsb, b, sizeof(b));
76 8
}
77
78
int
79 20
vtc_send_proxy(int fd, int version, const struct suckaddr *sac,
80
    const struct suckaddr *sas)
81
{
82
        struct vsb *vsb;
83
        char hc[VTCP_ADDRBUFSIZE];
84
        char pc[VTCP_PORTBUFSIZE];
85
        char hs[VTCP_ADDRBUFSIZE];
86
        char ps[VTCP_PORTBUFSIZE];
87
        int i, len;
88
        int proto;
89
90 20
        AN(sac);
91 20
        AN(sas);
92
93 20
        assert(version == 1 || version == 2);
94 20
        vsb = VSB_new_auto();
95 20
        AN(vsb);
96
97 20
        proto = VSA_Get_Proto(sas);
98 20
        assert(proto == PF_INET6 || proto == PF_INET);
99
100 20
        if (version == 1) {
101 16
                VSB_bcat(vsb, vpx1_sig, sizeof(vpx1_sig));
102 16
                if (proto == PF_INET6)
103 8
                        VSB_printf(vsb, " TCP6 ");
104 8
                else if (proto == PF_INET)
105 8
                        VSB_printf(vsb, " TCP4 ");
106 16
                VTCP_name(sac, hc, sizeof(hc), pc, sizeof(pc));
107 16
                VTCP_name(sas, hs, sizeof(hs), ps, sizeof(ps));
108 16
                VSB_printf(vsb, "%s %s %s %s\r\n", hc, hs, pc, ps);
109 4
        } else if (version == 2) {
110 4
                VSB_bcat(vsb, vpx2_sig, sizeof(vpx2_sig));
111 4
                VSB_putc(vsb, 0x21);
112 4
                if (proto == PF_INET6) {
113 2
                        VSB_putc(vsb, 0x21);
114 2
                        VSB_putc(vsb, 0x00);
115 2
                        VSB_putc(vsb, 0x24);
116 2
                } else if (proto == PF_INET) {
117 2
                        VSB_putc(vsb, 0x11);
118 2
                        VSB_putc(vsb, 0x00);
119 2
                        VSB_putc(vsb, 0x0c);
120
                }
121 4
                vpx_enc_addr(vsb, proto, sac);
122 4
                vpx_enc_addr(vsb, proto, sas);
123 4
                vpx_enc_port(vsb, sac);
124 4
                vpx_enc_port(vsb, sas);
125
        } else
126 0
                WRONG("Wrong proxy version");
127
128 20
        AZ(VSB_finish(vsb));
129 20
        len = VSB_len(vsb);
130 20
        i = write(fd, VSB_data(vsb), len);
131 20
        VSB_delete(vsb);
132 20
        return (i != len);
133
}