Commit a646c8f6 authored by Poul-Henning Kamp's avatar Poul-Henning Kamp

Add ProxyV2 support.

parent 89ca131f
......@@ -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)
{
......
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
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