[master] b8366fe25 vcc_backend: Forbid ip addresses as .authority with .via

Nils Goroll nils.goroll at uplex.de
Mon Feb 10 15:02:05 UTC 2025


commit b8366fe25c284884f4e8c2f62c8babe5a8a384f8
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Fri Feb 7 11:38:25 2025 +0100

    vcc_backend: Forbid ip addresses as .authority with .via
    
    One half of the fix for #3963

diff --git a/bin/varnishtest/tests/c00042.vtc b/bin/varnishtest/tests/c00042.vtc
index ed69de824..60fd5c994 100644
--- a/bin/varnishtest/tests/c00042.vtc
+++ b/bin/varnishtest/tests/c00042.vtc
@@ -47,8 +47,8 @@ varnish v2 -cliok "param.set debug +syncvsl"
 
 varnish v1 -vcl {
 	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
-	backend s1 { .via = v2; .host = "${s1_addr}"; .port = "${s1_port}"; }
-	backend s2 { .via = v2; .host = "${s2_addr}"; .port = "${s2_port}"; }
+	backend s1 { .via = v2; .authority = "1.2.3.4.example.com"; .host = "${s1_addr}"; .port = "${s1_port}"; }
+	backend s2 { .via = v2; .authority = "s2"; .host = "${s2_addr}"; .port = "${s2_port}"; }
 
 	sub vcl_recv {
 		if (req.url ~ "^/s1/") {
@@ -65,19 +65,19 @@ client c1 {
 	txreq -url /s1/1
 	rxresp
 	expect resp.status == 200
-	expect resp.http.Authority == "${s1_addr}"
+	expect resp.http.Authority == "1.2.3.4.example.com"
 	expect resp.http.Server == "s1"
 
 	txreq -url /s2/1
 	rxresp
 	expect resp.status == 200
-	expect resp.http.Authority == "${s2_addr}"
+	expect resp.http.Authority == "s2"
 	expect resp.http.Server == "s2"
 
 	txreq -url /s1/2
 	rxresp
 	expect resp.status == 200
-	expect resp.http.Authority == "${s1_addr}"
+	expect resp.http.Authority == "1.2.3.4.example.com"
 	expect resp.http.Server == "s1"
 } -run
 
@@ -150,6 +150,27 @@ client c1 {
 	expect resp.http.Authority == ""
 } -run
 
+varnish v1 -errvcl ".host used as authority can not be an ip address with .via" {
+	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
+
+	backend s1 {
+		.via = v2;
+		.host = "${s1_addr}";
+		.port = "${s1_port}";
+	}
+}
+
+varnish v1 -errvcl ".host_header used as authority can not be an ip address with .via" {
+	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
+
+	backend s1 {
+		.via = v2;
+		.host = "${s1_addr}";
+		.host_header = "${s1_addr}";
+		.port = "${s1_port}";
+	}
+}
+
 varnish v1 -errvcl "Cannot set both .via and .path" {
 	backend v2 { .host = "${v2_addr}"; .port = "${v2_port}"; }
 
@@ -164,11 +185,13 @@ varnish v1 -errvcl "Cannot stack .via backends" {
 
 	backend b {
 		.via = a;
+		.host_header = "b";
 		.host = "127.0.0.1";
 	}
 
 	backend c {
 		.via = b;
+		.authority = "c";
 		.host = "127.0.0.2";
 	}
 
@@ -180,5 +203,5 @@ varnish v1 -errvcl "Cannot stack .via backends" {
 # issue #4177: backend named default with .via property
 varnish v1 -vcl {
 	backend via { .host = "${localhost}"; }
-	backend default { .via = via; .host = "${localhost}"; }
+	backend default { .via = via; .authority = "localhost"; .host = "${localhost}"; }
 }
diff --git a/doc/sphinx/reference/vcl-backend.rst b/doc/sphinx/reference/vcl-backend.rst
index 00904acbf..24ffc28fc 100644
--- a/doc/sphinx/reference/vcl-backend.rst
+++ b/doc/sphinx/reference/vcl-backend.rst
@@ -219,6 +219,8 @@ The HTTP authority to use when connecting to this backend. If unset,
 
 ``.authority = ""`` disables sending an authority.
 
+``.authority`` can not be an IP address.
+
 As of this release, the attribute is only used by ``.via`` connections
 as a ``PP2_TYPE_AUTHORITY`` Type-Length-Value (TLV) in the `PROXY2`_
 preamble.
diff --git a/lib/libvcc/vcc_backend.c b/lib/libvcc/vcc_backend.c
index 7e6bf64c6..7b61703f5 100644
--- a/lib/libvcc/vcc_backend.c
+++ b/lib/libvcc/vcc_backend.c
@@ -36,8 +36,14 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+
 
 #include "vcc_compile.h"
+#include "vsa.h"
+#include "vss.h"
 #include "vus.h"
 
 /*--------------------------------------------------------------------
@@ -75,6 +81,18 @@ Emit_Sockaddr(struct vcc *tl, struct vsb *vsb1, const struct token *t_host,
 	VSB_cat(vsb1, "\t.uds_path = (void *) 0,\n");
 }
 
+/*
+ * a string represents an IP address if getaddrinfo(AI_NUMERICHOST) succeeds
+ */
+static int
+isip(const char *addr)
+{
+	char buf[vsa_suckaddr_len];
+
+	return (VSS_ResolveOne(buf, addr, "80", AF_UNSPEC, SOCK_STREAM,
+	    AI_NUMERICHOST | AI_NUMERICSERV) != NULL);
+}
+
 /*
  * For UDS, we do not create a VSA. We run the VUS_resolver() checks and, if
  * it's a path, can be accessed, and is a socket. If so, just emit the path
@@ -660,10 +678,12 @@ vcc_ParseHostDef(struct vcc *tl, struct symbol *sym,
 	 *
 	 * 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.
+	 * authority must be a valid SNI HostName (RFC 4366 ch. 3.1), but the
+	 * RFC does not define what that is and defers to "DNS hostname".
+	 *
+	 * So instead of trying to attempt a solution to that pandora's box, we
+	 * just implement >>Literal IPv4 and IPv6 addresses are not permitted in
+	 * "HostName".<<
 	 */
 	if (via != NULL) {
 		AN(t_host);
@@ -675,6 +695,17 @@ vcc_ParseHostDef(struct vcc *tl, struct symbol *sym,
 			t_val = t_host;
 		p = t_val->dec;
 
+		if (isip(p)) {
+			if (t_val == t_authority)
+				VSB_cat(tl->sb, ".authority can not be an ip address with .via.\n");
+			else {
+				VSB_printf(tl->sb, ".%s used as authority can not be an ip address with .via.\n",
+					t_val == t_hosthdr ? "host_header" : "host");
+				VSB_cat(tl->sb, "Hint: configure .authority explicitly\n");
+			}
+			vcc_ErrWhere(tl, t_val);
+		}
+
 		Fb(tl, 0, "\t.authority = ");
 		VSB_quote(tl->fb, p, -1, VSB_QUOTE_CSTR);
 		Fb(tl, 0, ",\n");


More information about the varnish-commit mailing list