[master] 7b9a3a3 Add support for sending PROXY headers to backends.

Poul-Henning Kamp phk at FreeBSD.org
Thu Apr 7 10:51:04 CEST 2016


commit 7b9a3a30086ee5d3638d65597c316a278ef42991
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date:   Thu Apr 7 08:50:11 2016 +0000

    Add support for sending PROXY headers to backends.
    
    Connections to backends so configured are never reused.

diff --git a/bin/varnishd/cache/cache_backend.c b/bin/varnishd/cache/cache_backend.c
index 2fff7c2..14e5c04 100644
--- a/bin/varnishd/cache/cache_backend.c
+++ b/bin/varnishd/cache/cache_backend.c
@@ -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);
diff --git a/bin/varnishd/cache/cache_transport.h b/bin/varnishd/cache/cache_transport.h
index 40847a5..2b22519 100644
--- a/bin/varnishd/cache/cache_transport.h
+++ b/bin/varnishd/cache/cache_transport.h
@@ -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 *);
diff --git a/bin/varnishd/proxy/cache_proxy_proto.c b/bin/varnishd/proxy/cache_proxy_proto.c
index ee6fef5..fafbd0a 100644
--- a/bin/varnishd/proxy/cache_proxy_proto.c
+++ b/bin/varnishd/proxy/cache_proxy_proto.c
@@ -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);
+}
diff --git a/bin/varnishtest/tests/o00002.vtc b/bin/varnishtest/tests/o00002.vtc
new file mode 100644
index 0000000..5c6fee0
--- /dev/null
+++ b/bin/varnishtest/tests/o00002.vtc
@@ -0,0 +1,103 @@
+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



More information about the varnish-commit mailing list