[master] 15a8e6c0d Add the .authority field to backend definitions.

Nils Goroll nils.goroll at uplex.de
Mon Feb 20 15:38:06 UTC 2023


commit 15a8e6c0d832005a9dd0b3fd8145d1c261cee4b9
Author: Geoff Simmons <geoff at uplex.de>
Date:   Wed Aug 21 14:33:45 2019 +0200

    Add the .authority field to backend definitions.
    
    If the .via field is also set, then the value of .authority is set
    as the authority TLV in the PROXY header. This gives the "true"
    backend (usually the ssl-onloader) the opportunity to set the SNI
    (HostName field) from the TLV value, for the TLS handshake with the
    remote backend.
    
    This mandates that PROXYv2 is always used with a via backend (since
    only version 2 supports TLVs).
    
    If the value of .authority is the empty string, then the TLV is not
    sent. If .authority is not set for the backend, then fall back to
    .host_header, which itself may have been a fallback to .host. Note
    that if neither .authority nor .host_header is set, and .host is
    set to an IP address, then the IP address is forwarded as the SNI
    value, which is not permitted for HostName (RFC4366 ch 3.1). So
    users are advised to set either .authority or .host_header, or set
    .authority="", when .via is set.
    
    Usage note with haproxy:
    
    To enable sending SNI when haproxy is used as a TLS onloader, ``sni
    fc_pp_authority`` needs to be used with the backend configuration.
    
    Full usage example with haproxy 2.2:
    
    listen sslon
            mode    tcp
            maxconn 1000
            bind    /shared/varnish_haproxy/haproxy_sslon accept-proxy mode 777
            stick-table type ip size 100
            stick   on dst
            server  s00 0.0.0.0:443 ssl ca-file /etc/ssl/certs/ca-bundle.crt alpn http/1.1 sni fc_pp_authority
            server  s01 0.0.0.0:443 ssl ca-file /etc/ssl/certs/ca-bundle.crt alpn http/1.1 sni fc_pp_authority
            # ...
    
    A higher number of servers improves TLS session caching.

diff --git a/bin/varnishd/cache/cache_backend.c b/bin/varnishd/cache/cache_backend.c
index f4722729e..ba3b54c08 100644
--- a/bin/varnishd/cache/cache_backend.c
+++ b/bin/varnishd/cache/cache_backend.c
@@ -576,8 +576,8 @@ via_resolve(VRT_CTX, const struct vrt_endpoint *vep, VCL_BACKEND via)
 {
 	const struct backend *viabe = NULL;
 
-	AN(vep);
-	AN(via);
+	CHECK_OBJ_NOTNULL(vep, VRT_ENDPOINT_MAGIC);
+	CHECK_OBJ_NOTNULL(via, DIRECTOR_MAGIC);
 
 	if (vep->uds_path) {
 		VRT_fail(ctx, "Via is only supported for IP addresses");
@@ -586,9 +586,16 @@ via_resolve(VRT_CTX, const struct vrt_endpoint *vep, VCL_BACKEND via)
 
 	via = VRT_DirectorResolve(ctx, via);
 
-	if (via != NULL &&
-	    (via->vdir->methods == vbe_methods ||
-	     via->vdir->methods == vbe_methods_noprobe))
+	if (via == NULL) {
+		VRT_fail(ctx, "Via resolution failed");
+		return (NULL);
+	}
+
+	CHECK_OBJ(via, DIRECTOR_MAGIC);
+	CHECK_OBJ_NOTNULL(via->vdir, VCLDIR_MAGIC);
+
+	if (via->vdir->methods == vbe_methods ||
+	    via->vdir->methods == vbe_methods_noprobe)
 		CAST_OBJ_NOTNULL(viabe, via->priv, BACKEND_MAGIC);
 
 	if (viabe == NULL)
@@ -601,18 +608,19 @@ via_resolve(VRT_CTX, const struct vrt_endpoint *vep, VCL_BACKEND via)
  * construct a new endpoint identical to vep with sa in a proxy header
  */
 static struct vrt_endpoint *
-via_endpoint(const struct vrt_endpoint *vep, const struct suckaddr *sa)
+via_endpoint(const struct vrt_endpoint *vep, const struct suckaddr *sa,
+    const char *auth)
 {
 	struct vsb *preamble;
 	struct vrt_blob blob[1];
 	struct vrt_endpoint *nvep, *ret;
 	const struct suckaddr *client_bogo;
 
-	AN(vep);
+	CHECK_OBJ_NOTNULL(vep, VRT_ENDPOINT_MAGIC);
 	AN(sa);
 
 	nvep = VRT_Endpoint_Clone(vep);
-	AN(nvep);
+	CHECK_OBJ_NOTNULL(nvep, VRT_ENDPOINT_MAGIC);
 
 	if (VSA_Get_Proto(sa) == AF_INET6)
 		client_bogo = bogo_ip6;
@@ -621,11 +629,12 @@ via_endpoint(const struct vrt_endpoint *vep, const struct suckaddr *sa)
 
 	preamble = VSB_new_auto();
 	AN(preamble);
-	VPX_Format_Proxy(preamble, 2, client_bogo, sa, NULL);
+	VPX_Format_Proxy(preamble, 2, client_bogo, sa, auth);
 	blob->blob = VSB_data(preamble);
 	blob->len = VSB_len(preamble);
 	nvep->preamble = blob;
 	ret = VRT_Endpoint_Clone(nvep);
+	CHECK_OBJ_NOTNULL(ret, VRT_ENDPOINT_MAGIC);
 	VSB_destroy(&preamble);
 	free(nvep);
 
@@ -658,7 +667,7 @@ VRT_new_backend_clustered(VRT_CTX, struct vsmw_cluster *vc,
 		assert(vep->ipv4== NULL && vep->ipv6== NULL);
 	}
 
-	if (via) {
+	if (via != NULL) {
 		viabe = via_resolve(ctx, vep, via);
 		if (viabe == NULL)
 			return (NULL);
@@ -701,7 +710,8 @@ VRT_new_backend_clustered(VRT_CTX, struct vsmw_cluster *vc,
 		VRT_VSC_Hide(be->vsc_seg);
 
 	if (viabe)
-		vep = be->endpoint = via_endpoint(viabe->endpoint, sa);
+		vep = be->endpoint = via_endpoint(viabe->endpoint, sa,
+		    be->authority);
 	else
 		vep = be->endpoint = VRT_Endpoint_Clone(vep);
 
diff --git a/bin/varnishtest/tests/c00042.vtc b/bin/varnishtest/tests/c00042.vtc
index 9bd29ccfd..894fc5c07 100644
--- a/bin/varnishtest/tests/c00042.vtc
+++ b/bin/varnishtest/tests/c00042.vtc
@@ -1,10 +1,10 @@
 varnishtest "Test vcl defined via backends"
 
 server s1 {
-	rxreq
-	txresp
-	rxreq
-	txresp
+	loop 5 {
+		rxreq
+		txresp
+	}
 } -start
 
 # the use case for via-proxy is to have a(n ha)proxy make a(n ssl)
@@ -16,6 +16,7 @@ server s1 {
 varnish v2 -proto PROXY -vcl {
 	import debug;
 	import std;
+	import proxy;
 
 	backend dummy { .host = "${bad_backend}"; }
 
@@ -28,14 +29,13 @@ varnish v2 -proto PROXY -vcl {
 		set req.backend_hint = s1.backend();
 		return (pass);
 	}
+
+	sub vcl_deliver {
+		set resp.http.Authority = proxy.authority();
+	}
 } -start
 
 varnish v1 -vcl {
-	import debug;
-	import vtc;
-
-	backend dummy { .host = "${bad_backend}"; }
-
 	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
 	backend s1 { .via = v2; .host = "${s1_addr}"; .port = "${s1_port}"; }
 
@@ -48,9 +48,79 @@ client c1 {
 	txreq -url /1
 	rxresp
 	expect resp.status == 200
+	expect resp.http.Authority == "127.0.0.1"
 	txreq -url /2
 	rxresp
 	expect resp.status == 200
+	expect resp.http.Authority == "127.0.0.1"
+} -run
+
+varnish v1 -vcl {
+	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
+
+	backend s1 {
+		.via = v2;
+		.host = "${s1_addr}";
+		.port = "${s1_port}";
+		.authority = "authority.com";
+	}
+
+	sub vcl_recv {
+		set req.backend_hint = s1;
+	}
+}
+
+client c1 {
+	txreq -url /3
+	rxresp
+	expect resp.status == 200
+	expect resp.http.Authority == "authority.com"
+} -run
+
+varnish v1 -vcl {
+	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
+
+	backend s1 {
+		.via = v2;
+		.host = "${s1_addr}";
+		.port = "${s1_port}";
+		.host_header = "host.com";
+	}
+
+	sub vcl_recv {
+		set req.backend_hint = s1;
+	}
+}
+
+client c1 {
+	txreq -url /4
+	rxresp
+	expect resp.status == 200
+	expect resp.http.Authority == "host.com"
+} -run
+
+# Setting .authority = "" disables sending the TLV.
+varnish v1 -vcl {
+	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
+
+	backend s1 {
+		.via = v2;
+		.host = "${s1_addr}";
+		.port = "${s1_port}";
+		.authority = "";
+	}
+
+	sub vcl_recv {
+		set req.backend_hint = s1;
+	}
+}
+
+client c1 {
+	txreq -url /5
+	rxresp
+	expect resp.status == 200
+	# vmod_proxy returns the empty string if the TLV is absent.
+	expect resp.http.Authority == ""
 } -run
 
 varnish v1 -errvcl "Cannot set both .via and .path" {
diff --git a/bin/varnishtest/tests/c00114.vtc b/bin/varnishtest/tests/c00114.vtc
new file mode 100644
index 000000000..84e9aee69
--- /dev/null
+++ b/bin/varnishtest/tests/c00114.vtc
@@ -0,0 +1,59 @@
+varnishtest "TLV authority over via backends used as SNI for haproxy backend/1"
+
+# This test is skipped unless haproxy is available. It fails unless
+# that binary implements the fc_pp_authority fetch, to return the TLV
+# Authority value sent in a PROXYv2 header.
+
+# In this version of the test, we set port 0 in the server config of
+# the "ssl-onloading" haproxy, and set the destination port in the
+# backend config for Varnish. The onloader sets its destination port
+# from the address forwarded via PROXY, which in turn is set from the
+# Varnish backend config. See c00101.vtc for another config method.
+
+feature ignore_unknown_macro
+
+feature cmd {haproxy --version 2>&1 | grep -q 'HA-*Proxy version'}
+
+server s1 {
+	rxreq
+	txresp -hdr "Foo: bar"
+} -start
+
+haproxy h1 -conf {
+    listen feh1
+	mode http
+	bind "fd@${feh1}" ssl verify none crt ${testdir}/common.pem
+	server s1 ${s1_addr}:${s1_port}
+	http-response set-header X-SNI %[ssl_fc_sni]
+} -start
+
+# Note the use of port 0 for server s0.
+haproxy h2 -conf {
+    listen clear-to-ssl
+	bind unix@"${tmpdir}/h2.sock" accept-proxy
+	server s0 0.0.0.0:0 ssl verify none sni fc_pp_authority
+} -start
+
+varnish v1 -vcl {
+	backend h2 { .path = "${tmpdir}/h2.sock"; }
+
+	# The ssl-onloader uses the port number set here.
+	backend h1 {
+		.via = h2;
+		.host = "${h1_feh1_addr}";
+		.port = "${h1_feh1_port}";
+		.authority = "authority.com";
+	}
+
+	sub vcl_recv {
+		set req.backend_hint = h1;
+	}
+} -start
+
+client c1 {
+	txreq
+	rxresp
+	expect resp.status == 200
+	expect resp.http.Foo == "bar"
+	expect resp.http.X-SNI == "authority.com"
+} -run
diff --git a/bin/varnishtest/tests/common.pem b/bin/varnishtest/tests/common.pem
new file mode 100644
index 000000000..ca8778e4f
--- /dev/null
+++ b/bin/varnishtest/tests/common.pem
@@ -0,0 +1,65 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAnb0BDF7FsqzslakNg7u/n/JQkq6nheuKwvyTqECfpc9y7uSB
+e/vrEFqBaDSLQagJxuZdL5geFeVtRbdAoB97N1/LZa6vecjjgGSP0Aag/gS/ocnM
+RIyvlVWWT9MrD46OG3qZY1ORU1ltrVL0NKttJP8xME7j3bTwIDElx/hNI0n7L+yS
+kAe2xb/7CbZRfoOhjTVAcGv4aSLVc/Hi8k6VkIzdOEtH6TcghXmuGcuqvLNH9Buo
+syngKTcQ8zg6J+e64aVvC+e7vi94uil9Qu+JHm0pkDzAZ2WluNsuXlrJToPirWyj
+6/YdN6xgSI1hbZkBmUPAebgYuxBt6huvfyQd3wIDAQABAoIBABojc8UE/2W4WgwC
+04Z82ig7Ezb7Ui9S9M+S4zUCYHItijIkE4DkIfO3y7Hk4x6iJdyb191HK9UdC5p9
+32upS9XFPgM/izx3GZvxDhO+xXbSep7ovbyuQ3pPkHTx3TTavpm3GyvmcTKKoy4R
+jP4dWhzDXPdQW1ol3ZS4EDau4rlyClY6oi1mq9aBEX3MqVjB/nO7s2AbdgclAgP2
+OZMhTzWYR1k5tYySHCXh3ggGMCikyvHU0+SsGyrstYzP1VYi/n3f0VgqW/5ZjG8x
+6SHpe04unErPF3HuSun2ZMCFdBxaTFZ8FENb8evrSXe3nQOc9W21RQdRRrNNUbjl
+JYI4veECgYEA0ATYKMS1VCUYRZoQ49b5GTg7avUYqfW4bEo4fSfBue8NrnKR3Wu8
+PPBiCTuIYq1vSF+60B7Vu+hW0A8OuQ2UuMxLpYcQ7lKfNad/+yAfoWWafIqCqNU9
+at0QMdbW6A69d6jZt7OrXtleBsphCnN58jTz4ch4PIa2Oyq46NUXCvUCgYEAwh8t
+G6BOHOs3yRNI2s9Y9EEfwoil2uIKrZhqiL3AwdIpu5uNIMuPnbaEpXvRX6jv/qtL
+321i8vZLc31aM7zfxQ6B4ReQFJfYC80FJsWvcLwT9hB9mTJpLS4sIu5tzQc87O6w
+RtjFMom+5ns5hfPB4Eccy0EtbQWVY4nCzUeO6QMCgYBSvqqRRPXwG7VU8lznlHqP
+upuABzChYrnScY+Y0TixUlL54l79Wb6N6vzEOWceAWkzu8iewrU4QspNhr/PgoR3
+IeSxWlG0yy7Dc/ZnmTabx8O06I/iwrfkizzG5nOj6UEamRLJjPGNEB/jyZriQl7u
+pnugg1K4mMliLbNSAnlhBQKBgQCmYepbv260Qrex1KGhSg9Ia3k5V74weYYFfJnz
+UhChD+1NK+ourcsOtp3C6PlwMHBjq5aAjlU9QfUxq8NgjQaO8/xGXdfUjsFSfAtq
+TA4vZkUFpuTAJgEYBHc4CXx7OzTxLzRPxQRgaMgC7KNFOMR34vu/CsJQq3R7uFwL
+bsYC2QKBgQCtEmg1uDZVdByX9zyUMuRxz5Tq/vDcp+A5lJj2mha1+bUMaKX2+lxQ
+vPxY55Vaw/ukWkJirRrpGv6IytBn0dLAFSlKZworZGBaxsm8OGTFJ5Oe9+kZTjI9
+hvjpClOA1otbmj2F2uZAbuIjxQGDNUkLoifN5yDYCC8JPujHuHmULw==
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIGeTCCBGGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADB+MQswCQYDVQQGEwJGUjEW
+MBQGA1UECBMNSWxlLWRlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoT
+B296b24uaW8xFTATBgNVBAMTDE96b24gVGVzdCBDQTEeMBwGCSqGSIb3DQEJARYP
+c3VwcG9ydEBvem9uLmlvMB4XDTE2MDExNzIzMDIzOFoXDTE4MDExNjIzMDIzOFow
+gb4xCzAJBgNVBAYTAkZSMRYwFAYDVQQIEw1JbGUtZGUtRnJhbmNlMRowGAYDVQQH
+ExFOZXVpbGx5LXN1ci1TZWluZTEYMBYGA1UEChMPVE9BRCBDb25zdWx0aW5nMRcw
+FQYDVQQLEw5lUGFyYXBoZXIgVGVhbTEWMBQGA1UEAxMNd3d3LnRlc3QxLmNvbTEw
+MC4GCSqGSIb3DQEJARYhYXJuYXVsdC5taWNoZWxAdG9hZC1jb25zdWx0aW5nLmZy
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnb0BDF7FsqzslakNg7u/
+n/JQkq6nheuKwvyTqECfpc9y7uSBe/vrEFqBaDSLQagJxuZdL5geFeVtRbdAoB97
+N1/LZa6vecjjgGSP0Aag/gS/ocnMRIyvlVWWT9MrD46OG3qZY1ORU1ltrVL0NKtt
+JP8xME7j3bTwIDElx/hNI0n7L+ySkAe2xb/7CbZRfoOhjTVAcGv4aSLVc/Hi8k6V
+kIzdOEtH6TcghXmuGcuqvLNH9BuosyngKTcQ8zg6J+e64aVvC+e7vi94uil9Qu+J
+Hm0pkDzAZ2WluNsuXlrJToPirWyj6/YdN6xgSI1hbZkBmUPAebgYuxBt6huvfyQd
+3wIDAQABo4IBvzCCAbswCwYDVR0PBAQDAgOoMBMGA1UdJQQMMAoGCCsGAQUFBwMB
+MB0GA1UdDgQWBBTIihFNVNgOseQnsWEcAQxAbIKE4TCBsgYDVR0jBIGqMIGngBRv
+G9At9gzk2MW5Z7JVey1LtPIZ8KGBg6SBgDB+MQswCQYDVQQGEwJGUjEWMBQGA1UE
+CBMNSWxlLWRlLUZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxEDAOBgNVBAoTB296b24u
+aW8xFTATBgNVBAMTDE96b24gVGVzdCBDQTEeMBwGCSqGSIb3DQEJARYPc3VwcG9y
+dEBvem9uLmlvggkA15FtIaGcrk8wDAYDVR0TAQH/BAIwADAaBgNVHREEEzARgg9j
+b21tb25OYW1lOmNvcHkwCQYDVR0SBAIwADBIBgNVHR8EQTA/MD2gO6A5hjdodHRw
+Oi8vb3BlbnNzbGNhLnRvYWQtY29uc3VsdGluZy5jb20vb3BlbnZwbi9MYXRlc3Qu
+Y3JsMBEGCWCGSAGG+EIBAQQEAwIGQDAxBglghkgBhvhCAQ0EJBYiVE9BRC1Db25z
+dWx0aW5nIHNlcnZlciBjZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAgEAewDa
+9BukGNJMex8gsXmmdaczTr8yh9Uvw4NJcZS38I+26o//2g+d6i7wxcQg8hIm62Hj
+0TblGU3+RsJo4uzcWxxA5YUYlVszbHNBRpQengEE5pjwHvoXVMNES6Bt8xP04+Vj
+0qVnA8gUaDMk9lN5anK7tF/mbHOIJwHJZYCa2t3y95dIOVEXFwOIzzbSbaprjkLN
+w0BgR5paJz7NZWNqo4sZHUUz94uH2bPEd01SqHO0dJwEVxadgxuPnD05I9gqGpGX
+Zf3Rn7EQylvUtX9mpPaulQPXc3emefewLUSSAdnZrVikZK2J/B4lSi9FpUwl4iQH
+pZoE0QLQHtB1SBKacnOAddGSTLSdFvpzjErjjWSpMukF0vutmrP86GG3xtshWVhI
+u+yLfDJVm/pXfaeDtWMXpxIT/U1i0avpk5MZtFMRC0MTaxEWBTnnJm+/yiaAXQYg
+E1ZIP0mkZkiUojIawTR7JTjHGhIraP9UVPNceVy0DLfETHEou3vhwBn7PFOz7piJ
+wjp3A47DStJD4fapaX6B1fqM+n34CMD9ZAiJFgQEIQfObAWC9hyr4m+pqkp1Qfuw
+vsAP/ZoS1CBirJfm3i+Gshh+VeH+TAmO/NBBYCfzBdgkNz4tJCkOc7CUT/NQTR/L
+N2OskR/Fkge149RJi7hHvE3gk/mtGtNmHJPuQ+s=
+-----END CERTIFICATE-----
+
diff --git a/bin/varnishtest/tests/d00007.vtc b/bin/varnishtest/tests/d00007.vtc
index 4198e3fb3..b119d9cc2 100644
--- a/bin/varnishtest/tests/d00007.vtc
+++ b/bin/varnishtest/tests/d00007.vtc
@@ -2,18 +2,30 @@ varnishtest "Test dynamic backends"
 
 server s1 {
 	rxreq
+	expect req.url == "/"
+	expect req.http.Probe == "p1"
+	expect req.http.Authority == <undef>
 	txresp
 	close
 	accept
 	rxreq
+	expect req.url == "/1"
+	expect req.http.Probe == <undef>
+	expect req.http.Authority == <undef>
 	txresp
 	close
 	accept
 	rxreq
+	expect req.url == "/"
+	expect req.http.Probe == "p2"
+	expect req.http.Authority == "127.0.0.1"
 	txresp
 	close
 	accept
 	rxreq
+	expect req.url == "/2"
+	expect req.http.Probe == <undef>
+	expect req.http.Authority == "127.0.0.1"
 	txresp
 } -start
 
@@ -26,6 +38,7 @@ server s1 {
 varnish v2 -proto PROXY -vcl {
 	import debug;
 	import std;
+	import proxy;
 
 	backend dummy { .host = "${bad_backend}"; }
 
@@ -36,8 +49,13 @@ varnish v2 -proto PROXY -vcl {
 	sub vcl_recv {
 		s1.refresh(server.ip, std.port(server.ip));
 		set req.backend_hint = s1.backend();
+		set req.http.Authority = proxy.authority();
 		return (pass);
 	}
+
+	sub vcl_deliver {
+		set resp.http.Authority = req.http.Authority;
+	}
 } -start
 
 #
@@ -53,10 +71,26 @@ varnish v1 -vcl {
 
 	backend dummy { .host = "${bad_backend}"; }
 
-	probe pr {
+	probe p1 {
+		.threshold = 8;
+		.initial = 8;
+		.interval = 1m;
+		.request =
+			"GET / HTTP/1.1"
+			"Host: ${s1_addr}"
+			"Probe: p1"
+			"Connection: close";
+	}
+
+	probe p2 {
 		.threshold = 8;
 		.initial = 8;
 		.interval = 1m;
+		.request =
+			"GET / HTTP/1.1"
+			"Host: ${s1_addr}"
+			"Probe: p2"
+			"Connection: close";
 	}
 
 	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
@@ -67,10 +101,10 @@ varnish v1 -vcl {
 
 	sub vcl_recv {
 		if (req.url == "/1") {
-			s1.refresh("${s1_addr}", "${s1_port}", pr);
+			s1.refresh("${s1_addr}", "${s1_port}", p1);
 			vtc.sleep(1s);
 		} else if (req.url == "/2") {
-			s1.refresh("${s1_addr}", "${s1_port}", pr,
+			s1.refresh("${s1_addr}", "${s1_port}", p2,
 			    via=v2);
 			vtc.sleep(1s);
 		}
@@ -84,7 +118,9 @@ client c1 {
 	txreq -url /1
 	rxresp
 	expect resp.status == 200
+	expect resp.http.Authority == <undef>
 	txreq -url /2
 	rxresp
 	expect resp.status == 200
+	expect resp.http.Authority == "127.0.0.1"
 } -run
diff --git a/include/vrt.h b/include/vrt.h
index 4f524e4a5..5d01f542d 100644
--- a/include/vrt.h
+++ b/include/vrt.h
@@ -63,6 +63,7 @@
  *	exp_close added to struct vrt_backend_probe
  *	VRT_new_backend() signature changed
  *	VRT_new_backend_clustered() signature changed
+ *	authority field added to struct vrt_backend
  * 16.0 (2022-09-15)
  *	VMOD C-prototypes moved into JSON
  *	VRT_AddVDP() deprecated
@@ -561,6 +562,7 @@ struct vrt_endpoint {
 #define VRT_BACKEND_FIELDS(rigid)				\
 	rigid char			*vcl_name;		\
 	rigid char			*hosthdr;		\
+	rigid char			*authority;		\
 	vtim_dur			connect_timeout;	\
 	vtim_dur			first_byte_timeout;	\
 	vtim_dur			between_bytes_timeout;	\
@@ -571,6 +573,7 @@ struct vrt_endpoint {
 	do {					\
 		DA(vcl_name);			\
 		DA(hosthdr);			\
+		DA(authority);			\
 		DN(connect_timeout);		\
 		DN(first_byte_timeout);		\
 		DN(between_bytes_timeout);	\
diff --git a/lib/libvcc/vcc_backend.c b/lib/libvcc/vcc_backend.c
index a062e1cb5..c86896623 100644
--- a/lib/libvcc/vcc_backend.c
+++ b/lib/libvcc/vcc_backend.c
@@ -372,6 +372,7 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
 	const struct token *t_port = NULL;
 	const struct token *t_path = NULL;
 	const struct token *t_hosthdr = NULL;
+	const struct token *t_authority = NULL;
 	const struct token *t_did = NULL;
 	const struct token *t_preamble = NULL;
 	struct symbol *pb;
@@ -420,6 +421,7 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
 	    "?proxy_header",
 	    "?preamble",
 	    "?via",
+	    "?authority",
 	    NULL);
 
 	tl->fb = VSB_new_auto();
@@ -547,6 +549,12 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
 			AN(via);
 			AN(via->rname);
 			SkipToken(tl, ';');
+		} else if (vcc_IdIs(t_field, "authority")) {
+			ExpectErr(tl, CSTR);
+			assert(tl->t->dec != NULL);
+			t_authority = tl->t;
+			vcc_NextToken(tl);
+			SkipToken(tl, ';');
 		} else {
 			ErrInternal(tl);
 			VSB_destroy(&tl->fb);
@@ -609,6 +617,28 @@ vcc_ParseHostDef(struct vcc *tl, const struct token *t_be, const char *vgcname)
 		Fb(tl, 0, "\"0.0.0.0\"");
 	Fb(tl, 0, ",\n");
 
+	/*
+	 * Emit the authority field, falling back to hosthdr, then host.
+	 *
+	 * When authority is "", sending the TLV is disabled.
+	 *
+	 * Falling back to host may result in an IP address in authority,
+	 * which is an illegal SNI HostName (RFC 4366 ch. 3.1). But we
+	 * document the potential error, rather than try to find out
+	 * whether or not Emit_Sockaddr() had to look up a name.
+	 */
+	if (via != NULL) {
+		AN(t_host);
+		Fb(tl, 0, "\t.authority = ");
+		if (t_authority != NULL)
+			EncToken(tl->fb, t_authority);
+		else if (t_hosthdr != NULL)
+			EncToken(tl->fb, t_hosthdr);
+		else
+			EncToken(tl->fb, t_host);
+		Fb(tl, 0, ",\n");
+	}
+
 	/* Close the struct */
 	Fb(tl, 0, "};\n");
 
diff --git a/vmod/vmod_debug_dyn.c b/vmod/vmod_debug_dyn.c
index 24685cc83..fa988fe4f 100644
--- a/vmod/vmod_debug_dyn.c
+++ b/vmod/vmod_debug_dyn.c
@@ -79,6 +79,7 @@ dyn_dir_init(VRT_CTX, struct xyzzy_debug_dyn *dyn,
 	vrt.endpoint = &vep;
 	vrt.vcl_name = dyn->vcl_name;
 	vrt.hosthdr = addr;
+	vrt.authority = addr;
 	vrt.probe = probe;
 
 	sa = VSS_ResolveOne(NULL, addr, port, AF_UNSPEC, SOCK_STREAM, 0);


More information about the varnish-commit mailing list