[master] a646c8f Add ProxyV2 support.
Poul-Henning Kamp
phk at FreeBSD.org
Wed Apr 8 10:45:41 CEST 2015
commit a646c8f6cd66f638d5398da4f1a90c8e5b2f67c3
Author: Poul-Henning Kamp <phk at FreeBSD.org>
Date: Wed Apr 8 08:45:18 2015 +0000
Add ProxyV2 support.
diff --git a/bin/varnishd/proxy/cache_proxy_proto.c b/bin/varnishd/proxy/cache_proxy_proto.c
index 8c8eb07..c7ae516 100644
--- a/bin/varnishd/proxy/cache_proxy_proto.c
+++ b/bin/varnishd/proxy/cache_proxy_proto.c
@@ -32,6 +32,8 @@
#include <sys/types.h>
#include <sys/socket.h>
+#include <netinet/in.h>
+
#include <netdb.h>
#include <stdlib.h>
#include <string.h>
@@ -40,11 +42,7 @@
#include "vend.h"
#include "vsa.h"
-
-static const char vpx2_sig[] = {
- '\r', '\n', '\r', '\n', '\0', '\r', '\n',
- 'Q', 'U', 'I', 'T', '\n',
-};
+#include "vtcp.h"
/**********************************************************************
* PROXY 1 protocol
@@ -60,7 +58,7 @@ vpx_proto1(const struct worker *wrk, struct req *req)
char *p, *q;
struct addrinfo hints, *res;
struct suckaddr *sa;
- int pfam = 0;
+ int pfam = -1;
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
@@ -156,21 +154,139 @@ vpx_proto1(const struct worker *wrk, struct req *req)
return (0);
}
+/**********************************************************************
+ * PROXY 2 protocol
+ */
+
+static const char vpx2_sig[] = {
+ '\r', '\n', '\r', '\n', '\0', '\r', '\n',
+ 'Q', 'U', 'I', 'T', '\n',
+};
+
static int
vpx_proto2(const struct worker *wrk, struct req *req)
{
int l;
+ const uint8_t *p;
+ sa_family_t pfam = 0xff;
+ struct sockaddr_in sin4;
+ struct sockaddr_in6 sin6;
+ struct suckaddr *sa = NULL;
+ char hb[VTCP_ADDRBUFSIZE];
+ char pb[VTCP_PORTBUFSIZE];
CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
- VSL(SLT_Debug, req->sp->fd, "PROXY2");
- assert(req->htc->rxbuf_e - req->htc->rxbuf_b >= 16);
+ assert(req->htc->rxbuf_e - req->htc->rxbuf_b >= 16L);
l = vbe16dec(req->htc->rxbuf_b + 14);
- req->htc->pipeline_b = req->htc->rxbuf_b + 16 + l;
+ assert(req->htc->rxbuf_e - req->htc->rxbuf_b >= 16L + l);
+ req->htc->pipeline_b = req->htc->rxbuf_b + 16L + l;
+ p = (const void *)req->htc->rxbuf_b;
+
+ /* Version @12 top half */
+ if ((p[12] >> 4) != 2) {
+ VSLb(req->vsl, SLT_ProxyGarbage,
+ "PROXY2: bad version (%d)", p[12] >> 4);
+ return (-1);
+ }
+
+ /* Command @12 bottom half */
+ switch(p[12] & 0x0f) {
+ case 0x0:
+ /* Local connection from proxy, ignore addresses */
+ return (0);
+ case 0x1:
+ /* Proxied connection */
+ break;
+ default:
+ VSLb(req->vsl, SLT_ProxyGarbage,
+ "PROXY2: bad command (%d)", p[12] & 0x0f);
+ return (-1);
+ }
+
+ /* Address family & protocol @13 */
+ switch(p[13]) {
+ case 0x00:
+ /* UNSPEC|UNSPEC, ignore proxy header */
+ VSLb(req->vsl, SLT_ProxyGarbage,
+ "PROXY2: Ignoring UNSPEC|UNSPEC addresses");
+ return (0);
+ case 0x11:
+ /* IPv4|TCP */
+ pfam = AF_INET;
+ if (l < 12) {
+ VSLb(req->vsl, SLT_ProxyGarbage,
+ "PROXY2: Ignoring short IPv4 addresses (%d)", l);
+ return (0);
+ }
+ break;
+ case 0x21:
+ /* IPv6|TCP */
+ pfam = AF_INET6;
+ if (l < 36) {
+ VSLb(req->vsl, SLT_ProxyGarbage,
+ "PROXY2: Ignoring short IPv6 addresses (%d)", l);
+ return (0);
+ }
+ break;
+ default:
+ /* Ignore proxy header */
+ VSLb(req->vsl, SLT_ProxyGarbage,
+ "PROXY2: Ignoring unsupported protocol (0x%02x)", p[13]);
+ return (0);
+ }
+
+ switch (pfam) {
+ case AF_INET:
+ memset(&sin4, 0, sizeof sin4);
+ sin4.sin_family = pfam;
+
+ /* dst/server */
+ memcpy(&sin4.sin_addr, p + 20, 4);
+ memcpy(&sin4.sin_port, p + 26, 2);
+ SES_Reserve_server_addr(req->sp, &sa);
+ AN(VSA_Build(sa, &sin4, sizeof sin4));
+
+ /* src/client */
+ memcpy(&sin4.sin_addr, p + 16, 4);
+ memcpy(&sin4.sin_port, p + 24, 2);
+ SES_Reserve_client_addr(req->sp, &sa);
+ AN(VSA_Build(sa, &sin4, sizeof sin4));
+ break;
+ case AF_INET6:
+ memset(&sin6, 0, sizeof sin6);
+ sin6.sin6_family = pfam;
+
+ /* dst/server */
+ memcpy(&sin6.sin6_addr, p + 32, 16);
+ memcpy(&sin6.sin6_port, p + 50, 2);
+ SES_Reserve_server_addr(req->sp, &sa);
+ AN(VSA_Build(sa, &sin6, sizeof sin6));
+
+ /* src/client */
+ memcpy(&sin6.sin6_addr, p + 16, 16);
+ memcpy(&sin6.sin6_port, p + 48, 2);
+ SES_Reserve_client_addr(req->sp, &sa);
+ AN(VSA_Build(sa, &sin6, sizeof sin6));
+ break;
+ default:
+ WRONG("Wrong pfam");
+ }
+
+ AN(sa);
+ VTCP_name(sa, hb, sizeof hb, pb, sizeof pb);
+ SES_Set_String_Attr(req->sp, SA_CLIENT_IP, hb);
+ SES_Set_String_Attr(req->sp, SA_CLIENT_PORT, pb);
+ VSLb(req->vsl, SLT_Debug, "PROXY2 %s %s", hb, pb);
+
return (0);
}
+/**********************************************************************
+ * HTC_Rx completion detector
+ */
+
static enum htc_status_e __match_proto__(htc_complete_f)
vpx_complete(struct http_conn *htc)
{
@@ -192,6 +308,8 @@ vpx_complete(struct http_conn *htc)
if (j == 0)
return (HTC_S_JUNK);
if (j == 1 && i == sizeof vpx1_sig) {
+ if (l > 107)
+ return (HTC_S_OVERFLOW);
if (strchr(p + i, '\n') == NULL)
return (HTC_S_MORE);
return (HTC_S_COMPLETE);
@@ -208,7 +326,6 @@ vpx_complete(struct http_conn *htc)
return (HTC_S_MORE);
}
-
void __match_proto__(task_func_t)
VPX_Proto_Sess(struct worker *wrk, void *priv)
{
diff --git a/bin/varnishtest/tests/o00001.vtc b/bin/varnishtest/tests/o00001.vtc
new file mode 100644
index 0000000..3d4e2f6
--- /dev/null
+++ b/bin/varnishtest/tests/o00001.vtc
@@ -0,0 +1,169 @@
+varnishtest "PROXY v2 test"
+
+server s1 {
+ # The server address is part of the hash-key
+ # so we need three responses
+ rxreq
+ expect req.http.x-forwarded-for == "127.0.0.1"
+ txresp -hdr "Obj: 1"
+ rxreq
+ expect req.http.x-forwarded-for == "1.2.3.4"
+ txresp -hdr "Obj: 2"
+ rxreq
+ expect req.http.x-forwarded-for == "102:304:506::d0e:f10"
+ txresp -hdr "Obj: 3"
+} -start
+
+varnish v1 -proto "PROXY" -vcl+backend {
+ import ${vmod_std};
+
+ acl fwd_client {
+ "1.2.3.4";
+ "102:304:506::d0e:f10";
+ }
+ acl fwd_server {
+ "5.6.7.8";
+ "8182:8384:8586::8d8e:8f80";
+ }
+
+ sub vcl_deliver {
+ set resp.http.li = local.ip;
+ set resp.http.lp = std.port(local.ip);
+ set resp.http.ri = remote.ip;
+ set resp.http.rp = std.port(remote.ip);
+ set resp.http.ci = client.ip;
+ set resp.http.cp = std.port(client.ip);
+ set resp.http.si = server.ip;
+ set resp.http.sp = std.port(server.ip);
+ set resp.http.fc = (client.ip ~ fwd_client);
+ set resp.http.fs = (server.ip ~ fwd_server);
+ }
+} -start
+
+client c1 {
+ # LOCAL command
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ sendhex "20 00 00 00"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.si == "${v1_addr}"
+ expect resp.http.sp == "${v1_port}"
+ expect resp.http.ci == "127.0.0.1"
+} -run
+delay .1
+
+client c1 {
+ # unknown command
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ sendhex "22 00 00 00"
+ timeout 8
+ expect_close
+} -run
+delay .1
+
+client c1 {
+ # UNSPEC proto
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ sendhex "21 00 00 00"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.si == "${v1_addr}"
+ expect resp.http.sp == "${v1_port}"
+ expect resp.http.ci == "127.0.0.1"
+} -run
+delay .1
+
+client c1 {
+ # unknown proto
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ sendhex "21 99 00 00"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.si == "${v1_addr}"
+ expect resp.http.sp == "${v1_port}"
+ expect resp.http.ci == "127.0.0.1"
+} -run
+delay .1
+
+client c1 {
+ # short IPv4
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ sendhex "21 11 00 0b"
+ sendhex "01 02 03 04 05 06 07 08 09 0a 0b"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.si == "${v1_addr}"
+ expect resp.http.sp == "${v1_port}"
+ expect resp.http.ci == "127.0.0.1"
+} -run
+delay .1
+
+client c1 {
+ # short IPv6
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ sendhex "21 21 00 23"
+ sendhex "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f"
+ sendhex "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f"
+ sendhex "01 02 03"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.fs == false
+ expect resp.http.fc == false
+ expect resp.http.si == "${v1_addr}"
+ expect resp.http.sp == "${v1_port}"
+ expect resp.http.ci == "127.0.0.1"
+} -run
+delay .1
+
+client c1 {
+ # good IPv4
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ sendhex "21 11 00 0c"
+ sendhex "01 02 03 04"
+ sendhex "05 06 07 08"
+ sendhex "09 0a"
+ sendhex "0b 0c"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.obj == 2
+ expect resp.http.fs == true
+ expect resp.http.fc == true
+ expect resp.http.ci == "1.2.3.4"
+ expect resp.http.cp == "2314"
+ expect resp.http.si == "5.6.7.8"
+ expect resp.http.sp == "2828"
+ expect resp.http.li == "${v1_addr}"
+ expect resp.http.lp == "${v1_port}"
+ expect resp.http.ri != "1.2.3.4"
+} -run
+delay .1
+
+client c1 {
+ # good IPv6
+ sendhex "0d 0a 0d 0a 00 0d 0a 51 55 49 54 0a"
+ sendhex "21 21 00 24"
+ sendhex "01 02 03 04 05 06 00 00 00 00 00 00 0d 0e 0f 10"
+ sendhex "81 82 83 84 85 86 00 00 00 00 00 00 8d 8e 8f 80"
+ sendhex "09 0a"
+ sendhex "0b 0c"
+ txreq
+ rxresp
+ expect resp.status == 200
+ expect resp.http.obj == 3
+ expect resp.http.fs == true
+ expect resp.http.fc == true
+ expect resp.http.ci == "102:304:506::d0e:f10"
+ expect resp.http.cp == "2314"
+ expect resp.http.si == "8182:8384:8586::8d8e:8f80"
+ expect resp.http.sp == "2828"
+ expect resp.http.li == "${v1_addr}"
+ expect resp.http.lp == "${v1_port}"
+ expect resp.http.ri != "102:304:506::d0e:f10"
+} -run
+delay .1
More information about the varnish-commit
mailing list