Commit 99ec7796 authored by Geoff Simmons's avatar Geoff Simmons Committed by Nils Goroll

Add capability to send the authority TLV in the PROXY header

This gives the receiver of the PROXY header (usually the ssl-onloader)
the opportunity to set the SNI (HostName field) from the TLV value, for
the TLS handshake with the remote backend.

From
https://github.com/nigoroll/varnish-cache/commit/e0eb7d0a9c65cdc3c58978656b4c71f4ab8aabca
edited by @nigoroll to split out the proxy header functionality.

Add vmod_debug access to the proxy header formatting and test it
parent a74315bc
......@@ -989,7 +989,8 @@ VRT_VSA_GetPtr(VRT_CTX, const struct suckaddr *sua, const unsigned char ** dst)
}
void
VRT_Format_Proxy(struct vsb *vsb, VCL_INT version, VCL_IP sac, VCL_IP sas)
VRT_Format_Proxy(struct vsb *vsb, VCL_INT version, VCL_IP sac, VCL_IP sas,
VCL_STRING auth)
{
VPX_Format_Proxy(vsb, (int)version, sac, sas);
VPX_Format_Proxy(vsb, (int)version, sac, sas, auth);
}
......@@ -40,4 +40,4 @@
int VPX_tlv(const struct req *req, int tlv, void **dst, int *len);
void VPX_Format_Proxy(struct vsb *, int, const struct suckaddr *,
const struct suckaddr *);
const struct suckaddr *, const char *);
......@@ -606,6 +606,24 @@ vpx_enc_port(struct vsb *vsb, const struct suckaddr *s)
VSB_bcat(vsb, b, sizeof(b));
}
static void
vpx_enc_authority(struct vsb *vsb, const char *authority, size_t l_authority)
{
uint16_t l;
AN(vsb);
if (l_authority == 0)
return;
AN(authority);
AN(*authority);
VSB_putc(vsb, PP2_TYPE_AUTHORITY);
vbe16enc(&l, l_authority);
VSB_bcat(vsb, &l, sizeof(l));
VSB_cat(vsb, authority);
}
/* short path for stringified addresses from session attributes */
static void
vpx_format_proxy_v1(struct vsb *vsb, int proto,
......@@ -634,22 +652,33 @@ vpx_format_proxy_v1(struct vsb *vsb, int proto,
static void
vpx_format_proxy_v2(struct vsb *vsb, int proto,
const struct suckaddr *sac, const struct suckaddr *sas)
const struct suckaddr *sac, const struct suckaddr *sas,
const char *authority)
{
size_t l_authority = 0;
uint16_t l_tlv = 0, l;
AN(vsb);
AN(sac);
AN(sas);
if (authority != NULL && *authority != '\0') {
l_authority = strlen(authority);
/* 3 bytes in the TLV before the authority string */
assert(3 + l_authority <= UINT16_MAX);
l_tlv = 3 + l_authority;
}
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);
vbe16enc(&l, 0x24 + l_tlv);
VSB_bcat(vsb, &l, sizeof(l));
} else if (proto == PF_INET) {
VSB_putc(vsb, 0x11);
VSB_putc(vsb, 0x00);
VSB_putc(vsb, 0x0c);
vbe16enc(&l, 0x0c + l_tlv);
VSB_bcat(vsb, &l, sizeof(l));
} else {
WRONG("Wrong proxy v2 proto");
}
......@@ -657,12 +686,14 @@ vpx_format_proxy_v2(struct vsb *vsb, int proto,
vpx_enc_addr(vsb, proto, sas);
vpx_enc_port(vsb, sac);
vpx_enc_port(vsb, sas);
vpx_enc_authority(vsb, authority, l_authority);
AZ(VSB_finish(vsb));
}
void
VPX_Format_Proxy(struct vsb *vsb, int version,
const struct suckaddr *sac, const struct suckaddr *sas)
const struct suckaddr *sac, const struct suckaddr *sas,
const char *authority)
{
int proto;
char hac[VTCP_ADDRBUFSIZE];
......@@ -684,7 +715,7 @@ VPX_Format_Proxy(struct vsb *vsb, int version,
VTCP_name(sas, has, sizeof has, pas, sizeof pas);
vpx_format_proxy_v1(vsb, proto, hac, pac, has, pas);
} else if (version == 2) {
vpx_format_proxy_v2(vsb, proto, sac, sas);
vpx_format_proxy_v2(vsb, proto, sac, sas, authority);
} else
WRONG("Wrong proxy version");
}
......@@ -721,7 +752,7 @@ VPX_Send_Proxy(int fd, int version, const struct sess *sp)
} else if (version == 2) {
AZ(SES_Get_client_addr(sp, &sac));
AN(sac);
vpx_format_proxy_v2(vsb, proto, sac, sas);
vpx_format_proxy_v2(vsb, proto, sac, sas, NULL);
} else
WRONG("Wrong proxy version");
......
varnishtest "VCL backend side access to IP#s"
varnishtest "VCL backend side access to IP#s and debug.proxy_header"
server s1 {
rxreq
......@@ -6,11 +6,20 @@ server s1 {
} -start
varnish v1 -proto PROXY -vcl+backend {
import vtc;
import blob;
sub vcl_backend_response {
set beresp.http.li = local.ip;
set beresp.http.ri = remote.ip;
set beresp.http.ci = client.ip;
set beresp.http.si = server.ip;
set beresp.http.proxy1 = blob.encode(blob=blob.sub(
vtc.proxy_header(v1, client.ip, server.ip), 36B));
set beresp.http.proxy2 = blob.encode(encoding=HEX,
blob=vtc.proxy_header(v2, client.ip, server.ip,
"vtc.varnish-cache.org"));
}
} -start
......@@ -20,4 +29,6 @@ client c1 -proxy1 "1.2.3.4:1111 5.6.7.8:5678" {
expect resp.http.li == ${v1_addr}
expect resp.http.ci == 1.2.3.4
expect resp.http.si == 5.6.7.8
expect resp.http.proxy1 == "PROXY TCP4 1.2.3.4 5.6.7.8 1111 5678"
expect resp.http.proxy2 == "0d0a0d0a000d0a515549540a2111002401020304050607080457162e0200157674632e7661726e6973682d63616368652e6f7267"
} -run
......@@ -57,6 +57,7 @@
* VRT_HashStrands32() added
* VRT_l_resp_body() changed
* VRT_l_beresp_body() changed
* VRT_Format_Proxy() added // transitional interface
* 10.0 (2019-09-15)
* VRT_UpperLowerStrands added.
* VRT_synth_page now takes STRANDS argument
......@@ -76,7 +77,6 @@
* VRT_Stv_*() functions renamed to VRT_stevedore_*()
* [cache.h] WS_ReserveAll() added
* [cache.h] WS_Reserve(ws, 0) deprecated
* VRT_Fortmat_Proxy() added
* 9.0 (2019-03-15)
* Make 'len' in vmod_priv 'long'
* HTTP_Copy() removed
......@@ -550,7 +550,8 @@ void VRT_DelDirector(VCL_BACKEND *);
/* Suckaddr related */
int VRT_VSA_GetPtr(VRT_CTX, VCL_IP sua, const unsigned char ** dst);
void VRT_Format_Proxy(struct vsb *, VCL_INT, VCL_IP, VCL_IP);
/* transitional interface */
void VRT_Format_Proxy(struct vsb *, VCL_INT, VCL_IP, VCL_IP, VCL_STRING);
typedef int vmod_event_f(VRT_CTX, struct vmod_priv *, enum vcl_event_e);
......
......@@ -155,6 +155,18 @@ Returns the size in bytes of a collection of C-datatypes:
This can be useful for VMOD authors in conjunction with workspace operations.
$Function BLOB proxy_header(ENUM {v1,v2} version,
IP client, IP server, STRING authority=0)
Format a proxy header of the given version ``v1`` or ``v2`` and
addresses (The VCL IP type also conatins the port number).
Optionally also send an authority TLV with version ``v2`` (ignored for
version ``v1``).
Candidate for moving into vmod_proxy, but there were concerns about
the interface design
SEE ALSO
========
......
......@@ -35,6 +35,7 @@
#include "cache/cache.h"
#include "vsb.h"
#include "vtcp.h"
#include "vtim.h"
......@@ -331,3 +332,41 @@ vmod_typesize(VRT_CTX, VCL_STRING s)
i += (p - a); /* pad */
return ((VCL_INT)i);
}
/*--------------------------------------------------------------------*/
#define BLOB_VMOD_PROXY_HEADER_TYPE 0xc8f34f78
VCL_BLOB v_matchproto_(td_vtc_proxy_header)
vmod_proxy_header(VRT_CTX, VCL_ENUM venum, VCL_IP client, VCL_IP server,
VCL_STRING authority)
{
struct vsb *vsb;
const void *h;
int version;
size_t l;
CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
if (venum == VENUM(v1))
version = 1;
else if (venum == VENUM(v2))
version = 2;
else
WRONG(venum);
vsb = VSB_new_auto();
AN(vsb);
VRT_Format_Proxy(vsb, version, client, server, authority);
l = VSB_len(vsb);
h = WS_Copy(ctx->ws, VSB_data(vsb), l);
VSB_delete(vsb);
if (h == NULL) {
VRT_fail(ctx, "proxy_header: out of workspace");
return (NULL);
}
return (VRT_blob(ctx, "proxy_header", h, l,
BLOB_VMOD_PROXY_HEADER_TYPE));
}
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