Commit 7b9a3a30 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Add support for sending PROXY headers to backends.

Connections to backends so configured are never reused.
parent e1d1b66e
......@@ -42,6 +42,7 @@
#include "cache_director.h"
#include "cache_backend.h"
#include "cache_transport.h"
#include "http1/cache_http1.h"
#define FIND_TMO(tmx, dst, bo, be) \
......@@ -108,6 +109,9 @@ vbe_dir_getfd(struct worker *wrk, struct backend *bp, struct busyobj *bo)
bp->vsc->req++;
Lck_Unlock(&bp->mtx);
if (bp->proxy_header != 0)
VPX_Send_Proxy(vc->fd, bp->proxy_header, bo->sp);
VTCP_myname(vc->fd, abuf1, sizeof abuf1, pbuf1, sizeof pbuf1);
VTCP_hisname(vc->fd, abuf2, sizeof abuf2, pbuf2, sizeof pbuf2);
VSLb(bo->vsl, SLT_BackendOpen, "%d %s %s %s %s %s",
......@@ -152,7 +156,7 @@ vbe_dir_finish(const struct director *d, struct worker *wrk,
bo->htc->priv = NULL;
if (vbc->state != VBC_STATE_USED)
VBT_Wait(wrk, vbc);
if (bo->htc->doclose != SC_NULL) {
if (bo->htc->doclose != SC_NULL || bp->proxy_header != 0) {
VSLb(bo->vsl, SLT_BackendClose, "%d %s", vbc->fd,
bp->display_name);
VBT_Close(bp->tcp_pool, &vbc);
......
......@@ -66,4 +66,4 @@ extern struct transport PROXY_transport;
extern struct transport HTTP1_transport;
const struct transport *XPORT_ByNumber(uint16_t no);
void VPX_Send_Proxy(int fd, int version, const struct sess *);
......@@ -43,6 +43,7 @@
#include "vend.h"
#include "vsa.h"
#include "vsb.h"
#include "vtcp.h"
/**********************************************************************
......@@ -379,3 +380,98 @@ struct transport PROXY_transport = {
.magic = TRANSPORT_MAGIC,
.new_session = vpx_new_session,
};
static void
vpx_enc_addr(struct vsb *vsb, int proto, const struct suckaddr *s)
{
const struct sockaddr_in *sin4;
const struct sockaddr_in6 *sin6;
socklen_t sl;
if (proto == PF_INET6) {
sin6 = VSA_Get_Sockaddr(s, &sl); //lint !e826
AN(sin6);
assert(sl >= sizeof *sin6);
VSB_bcat(vsb, &sin6->sin6_addr, sizeof(sin6->sin6_addr));
} else {
sin4 = VSA_Get_Sockaddr(s, &sl); //lint !e826
AN(sin4);
assert(sl >= sizeof *sin4);
VSB_bcat(vsb, &sin4->sin_addr, sizeof(sin4->sin_addr));
}
}
static void
vpx_enc_port(struct vsb *vsb, const struct suckaddr *s)
{
uint8_t b[2];
vbe16enc(b, (uint16_t)VSA_Port(s));
VSB_bcat(vsb, b, sizeof(b));
}
void
VPX_Send_Proxy(int fd, int version, const struct sess *sp)
{
struct vsb *vsb, *vsb2;
const char *p1, *p2;
struct suckaddr *sac, *sas;
char ha[VTCP_ADDRBUFSIZE];
char pa[VTCP_PORTBUFSIZE];
int proto;
CHECK_OBJ_NOTNULL(sp, SESS_MAGIC);
assert(version == 1 || version == 2);
vsb = VSB_new_auto();
AN(vsb);
AZ(SES_Get_server_addr(sp, &sas));
AN(sas);
proto = VSA_Get_Proto(sas);
assert(proto == PF_INET6 || proto == PF_INET);
if (version == 1) {
VSB_bcat(vsb, vpx1_sig, sizeof(vpx1_sig));
p1 = SES_Get_String_Attr(sp, SA_CLIENT_IP);
AN(p1);
p2 = SES_Get_String_Attr(sp, SA_CLIENT_PORT);
AN(p2);
VTCP_name(sas, ha, sizeof ha, pa, sizeof pa);
if (proto == PF_INET6)
VSB_printf(vsb, " TCP6 ");
else if (proto == PF_INET)
VSB_printf(vsb, " TCP4 ");
VSB_printf(vsb, "%s %s %s %s\r\n", p1, ha, p2, pa);
} else if (version == 2) {
AZ(SES_Get_client_addr(sp, &sac));
AN(sac);
VSB_bcat(vsb, vpx2_sig, sizeof(vpx2_sig));
VSB_putc(vsb, 0x21);
if (proto == PF_INET6) {
VSB_putc(vsb, 0x21);
VSB_putc(vsb, 0x00);
VSB_putc(vsb, 0x24);
} else if (proto == PF_INET) {
VSB_putc(vsb, 0x11);
VSB_putc(vsb, 0x00);
VSB_putc(vsb, 0x0c);
}
vpx_enc_addr(vsb, proto, sac);
vpx_enc_addr(vsb, proto, sas);
vpx_enc_port(vsb, sac);
vpx_enc_port(vsb, sas);
} else
WRONG("Wrong proxy version");
AZ(VSB_finish(vsb));
(void)write(fd, VSB_data(vsb), VSB_len(vsb));
vsb2 = VSB_new_auto();
AN(vsb2);
VSB_quote(vsb2, VSB_data(vsb), VSB_len(vsb),
version == 2 ? VSB_QUOTE_HEX : 0);
AZ(VSB_finish(vsb2));
VSL(SLT_Debug, 999, "PROXY_HDR %s", VSB_data(vsb2));
VSB_delete(vsb);
VSB_delete(vsb2);
}
varnishtest "Sending proxy headers to backend"
# This test is kind of hairy.
# We don't have code in server to validate PROXY headers
# so use a pipe of: c1 [proxy] v2 [proxy] v1 [http] s1
# Using proxy also between c1 and v2 allows us to test
# IPv6 processing over a IPv4 connection.
server s1 {
rxreq
expect req.url == "/1"
expect req.http.xyzzy1 == req.http.xyzzy2
expect req.http.xyzzy1 == 1111
expect req.http.x-forwarded-for == "1.2.3.4, 1.2.3.4"
txresp -body "proxy1"
rxreq
expect req.url == "/2"
expect req.http.xyzzy1 == req.http.xyzzy2
expect req.http.xyzzy1 == 2222
expect req.http.x-forwarded-for == "1.2.3.4, 1.2.3.4"
txresp -body "proxy2"
rxreq
expect req.url == "/3"
expect req.http.xyzzy1 == req.http.xyzzy2
expect req.http.xyzzy1 == 3333
expect req.http.x-forwarded-for == "1:f::2, 1:f::2"
txresp -body "proxy3"
rxreq
expect req.url == "/4"
expect req.http.xyzzy1 == req.http.xyzzy2
expect req.http.xyzzy1 == 4444
expect req.http.x-forwarded-for == "1:f::2, 1:f::2"
txresp -body "proxy4"
} -start
varnish v1 -proto PROXY -vcl+backend {
import std;
sub vcl_recv {
set req.http.xyzzy1 = std.port(client.ip);
}
} -start
varnish v2 -proto PROXY -vcl {
import std;
backend bp1 {
.host = "${v1_addr}";
.port = "${v1_port}";
.proxy_header = 1;
}
backend bp2 {
.host = "${v1_addr}";
.port = "${v1_port}";
.proxy_header = 2;
}
sub vcl_recv {
set req.http.xyzzy2 = std.port(client.ip);
if (req.url == "/1" || req.url == "/3") {
set req.backend_hint = bp1;
} else {
set req.backend_hint = bp2;
}
}
sub vcl_deliver {
set resp.http.connection = "close";
}
} -start
client c1 -connect ${v2_sock} {
send "PROXY TCP4 1.2.3.4 5.6.7.8 1111 5678\r\n"
txreq -url /1
rxresp
expect resp.body == "proxy1"
} -run
delay .2
client c1 -connect ${v2_sock} {
send "PROXY TCP4 1.2.3.4 5.6.7.8 2222 5678\r\n"
txreq -url /2
rxresp
expect resp.body == "proxy2"
} -run
delay .2
client c1 -connect ${v2_sock} {
send "PROXY TCP6 1:f::2 5:a::8 3333 5678\r\n"
txreq -url /3
rxresp
expect resp.body == "proxy3"
} -run
delay .2
client c1 -connect ${v2_sock} {
send "PROXY TCP6 1:f::2 5:a::8 4444 5678\r\n"
txreq -url /4
rxresp
expect resp.body == "proxy4"
} -run
delay .2
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment