[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