[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