[master] 40ca3c291 Support ACL as a vmod return type

Nils Goroll nils.goroll at uplex.de
Fri Jun 4 13:25:06 UTC 2021


commit 40ca3c2911c7c85d8025d5527c0739eea95b08b1
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Wed Jun 2 16:14:33 2021 +0200

    Support ACL as a vmod return type
    
    to the extent that the match operator ~ will actually accept vmod
    function/method calls returning it.
    
    Because VMODs also need an invalid ACL value to signal error, we stop
    panicking for a NULL ACL and trigger a VCL failure instead.
    
    The use case is not (yet) to generate dynamic ACLs, but rather to store
    and recall global ACL symbols.
    
    This implementation was particularly simple thanks to Dridis work
    on #3555 and VCL_REGEX.

diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c
index 1289c1ac2..d38587d36 100644
--- a/bin/varnishd/cache/cache_vrt.c
+++ b/bin/varnishd/cache/cache_vrt.c
@@ -134,11 +134,12 @@ VRT_acl_match(VRT_CTX, VCL_ACL acl, VCL_IP ip)
 {
 
 	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
-	CHECK_OBJ_NOTNULL(acl, VRT_ACL_MAGIC);
-	if (ip == NULL) {
-		VRT_fail(ctx, "Cannot match a null IP address");
+	if (acl == NULL || ip == NULL) {
+		VRT_fail(ctx, "Cannot match a null %s",
+			 acl == NULL ? "ACL" : "IP address");
 		return (0);
 	}
+	CHECK_OBJ(acl, VRT_ACL_MAGIC);
 	assert(VSA_Sane(ip));
 	return (acl->match(ctx, ip));
 }
diff --git a/bin/varnishtest/tests/m00023.vtc b/bin/varnishtest/tests/m00023.vtc
index 3ecfbde70..6abe3b569 100644
--- a/bin/varnishtest/tests/m00023.vtc
+++ b/bin/varnishtest/tests/m00023.vtc
@@ -21,13 +21,31 @@ varnish v1 -vcl+backend {
 		if (!debug.match_acl(loopback, "127.0.0.127")) {
 			debug.fail();
 		}
+		new o_locals = debug.aclobj(locals);
+		new o_null = debug.aclobj(debug.null_acl());
 	}
 
 	sub vcl_recv {
-		if (debug.match_acl(ip=client.ip, acl=locals)) {
-			return (hash);
+		if (req.url == "/null") {
+			if (client.ip ~ debug.null_acl()) {
+				return (synth(200));
+			}
 		}
-		return (synth(500));
+		if (req.url == "/nullo") {
+			if (client.ip ~ o_null.get()) {
+				return (synth(200));
+			}
+		}
+		if (! debug.match_acl(ip=client.ip, acl=locals)) {
+			return (synth(500, "match_acl"));
+		}
+		if (client.ip !~ debug.acl(locals)) {
+			return (synth(500, "~"));
+		}
+		if (client.ip !~ o_locals.get()) {
+			return (synth(500, "~"));
+		}
+		return (hash);
 	}
 } -start
 
@@ -35,4 +53,16 @@ client c1 {
 	txreq
 	rxresp
 	expect resp.status == 200
-} -run
+	txreq -url /null
+	rxresp
+	expect resp.status == 503
+} -start
+
+client c2 {
+	txreq -url /nullo
+	rxresp
+	expect resp.status == 503
+} -start
+
+client c1 -wait
+client c2 -wait
diff --git a/bin/varnishtest/tests/v00016.vtc b/bin/varnishtest/tests/v00016.vtc
index d26295fdc..f4421a166 100644
--- a/bin/varnishtest/tests/v00016.vtc
+++ b/bin/varnishtest/tests/v00016.vtc
@@ -89,7 +89,7 @@ varnish v1 -errvcl {resolves to too many addresses} {
 	}
 }
 
-varnish v1 -errvcl {Symbol 'foo' has wrong type (instance)} {
+varnish v1 -errvcl {Expression has type directors.shard, expected ACL} {
 	import directors;
 	backend b { .host = "${localhost}"; }
 
@@ -103,7 +103,7 @@ varnish v1 -errvcl {Symbol 'foo' has wrong type (instance)} {
 	}
 }
 
-varnish v1 -syntax 4.0 -errvcl {Undefined acl foo} {
+varnish v1 -syntax 4.0 -errvcl {Expression has type directors.shard, expected ACL} {
 	import directors;
 	backend b { .host = "${localhost}"; }
 
diff --git a/bin/varnishtest/tests/v00020.vtc b/bin/varnishtest/tests/v00020.vtc
index a12f3295e..603f3a251 100644
--- a/bin/varnishtest/tests/v00020.vtc
+++ b/bin/varnishtest/tests/v00020.vtc
@@ -423,7 +423,7 @@ varnish v1 -errvcl {'||' must be preceeded by BOOL, found REAL.} {
 	sub vcl_recv { if (std.random(0,1) || 0) { } }
 }
 
-varnish v1 -errvcl {Symbol 'acl' has wrong type (reserved), expected acl:} {
+varnish v1 -errvcl {Symbol 'acl' type (reserved) can not be used in expression.} {
 	import std;
 	sub vcl_recv { if (client.ip ~ acl) {} }
 }
diff --git a/bin/varnishtest/tests/v00021.vtc b/bin/varnishtest/tests/v00021.vtc
index 74bb36509..b8c2c4b40 100644
--- a/bin/varnishtest/tests/v00021.vtc
+++ b/bin/varnishtest/tests/v00021.vtc
@@ -151,13 +151,13 @@ varnish v1 -errvcl {Symbols named 'vcl_*' are reserved.} {
 	}
 }
 
-varnish v1 -errvcl {Symbol 'true' has wrong type (func), expected acl:} {
+varnish v1 -errvcl {Expression has type BOOL, expected ACL} {
 	sub vcl_recv {
 		if (client.ip ~ true) { }
 	}
 }
 
-varnish v1 -errvcl {Symbol 'default' has wrong type} {
+varnish v1 -errvcl {Symbol 'default' is a reserved word.} {
 	sub vcl_recv {
 		if (client.ip ~ default) { }
 	}
diff --git a/lib/libvcc/vcc_expr.c b/lib/libvcc/vcc_expr.c
index fb5220e4e..4118d861b 100644
--- a/lib/libvcc/vcc_expr.c
+++ b/lib/libvcc/vcc_expr.c
@@ -1121,17 +1121,14 @@ cmp_regexp(struct vcc *tl, struct expr **e, const struct cmps *cp)
 static void v_matchproto_(cmp_f)
 cmp_acl(struct vcc *tl, struct expr **e, const struct cmps *cp)
 {
-	struct symbol *sym;
+	struct expr *e2;
 	char buf[256];
 
 	vcc_NextToken(tl);
-	vcc_ExpectVid(tl, "ACL");
-	sym = VCC_SymbolGet(tl, SYM_MAIN, SYM_ACL, SYMTAB_CREATE, XREF_REF);
+	vcc_expr0(tl, &e2, ACL);
 	ERRCHK(tl);
-	AN(sym);
-	VCC_GlobalSymbol(sym, ACL);
-	bprintf(buf, "%sVRT_acl_match(ctx, %s, \v1)", cp->emit, sym->rname);
-	*e = vcc_expr_edit(tl, BOOL, buf, *e, NULL);
+	bprintf(buf, "%sVRT_acl_match(ctx, \v1, \v2)", cp->emit);
+	*e = vcc_expr_edit(tl, BOOL, buf, e2, *e);
 }
 
 static void v_matchproto_(cmp_f)
diff --git a/vmod/vmod_debug.vcc b/vmod/vmod_debug.vcc
index cdafcc4d3..b3ff9ac4d 100644
--- a/vmod/vmod_debug.vcc
+++ b/vmod/vmod_debug.vcc
@@ -174,6 +174,14 @@ $Function VOID vcl_discard_delay(PRIV_VCL, DURATION)
 Hold a reference to the VCL when it goes cold preventing
 discard for the given delay.
 
+$Function ACL null_acl()
+
+Return no acl.
+
+$Function ACL acl(ACL acl)
+
+Return the argument.
+
 $Function BOOL match_acl(ACL acl, IP ip)
 
 Perform an IP match against a named ACL.
@@ -194,6 +202,10 @@ Time `rounds` sweeps from `ip0` to `ip1` through `acl`.
 
 Consider: `-p vsl_mask=-VCL_acl`
 
+$Object aclobj(ACL)
+
+$Method ACL .get()
+
 $Function VOID test_probe(PROBE probe, PROBE same = 0)
 
 Only here to make sure probe definitions are passed properly.
diff --git a/vmod/vmod_debug_acl.c b/vmod/vmod_debug_acl.c
index 7d708f00d..385565891 100644
--- a/vmod/vmod_debug_acl.c
+++ b/vmod/vmod_debug_acl.c
@@ -47,12 +47,27 @@
 #include "vtim.h"
 #include "vcc_debug_if.h"
 
+VCL_ACL v_matchproto_(td_debug_null_acl)
+xyzzy_null_acl(VRT_CTX)
+{
+
+	CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
+	return (NULL);
+}
+
+VCL_ACL v_matchproto_(td_debug_acl)
+xyzzy_acl(VRT_CTX, VCL_ACL acl)
+{
+
+	CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
+	return (acl);
+}
+
 VCL_BOOL v_matchproto_(td_debug_match_acl)
 xyzzy_match_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip)
 {
 
 	CHECK_OBJ_ORNULL(ctx, VRT_CTX_MAGIC);
-	AN(acl);
 	assert(VSA_Sane(ip));
 
 	return (VRT_acl_match(ctx, acl, ip));
@@ -254,3 +269,44 @@ xyzzy_time_acl(VRT_CTX, VCL_ACL acl, VCL_IP ip0, VCL_IP ip1,
 	cleanup_sweep(asw);
 	return (d);
 }
+
+struct xyzzy_debug_aclobj {
+	unsigned			magic;
+#define VMOD_DEBUG_ACLOBJ_MAGIC	0xac10ac10
+	char *				vcl_name;
+	VCL_ACL			acl;
+};
+
+VCL_VOID v_matchproto_(td_xyzzy_debug_aclobj__init)
+xyzzy_aclobj__init(VRT_CTX, struct VPFX(debug_aclobj) **op,
+    const char *vcl_name, VCL_ACL acl)
+{
+	struct VPFX(debug_aclobj) *o;
+
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	AN(op);
+	AZ(*op);
+	ALLOC_OBJ(o, VMOD_DEBUG_ACLOBJ_MAGIC);
+	AN(o);
+	REPLACE(o->vcl_name, vcl_name);
+	o->acl = acl;
+	*op = o;
+}
+
+VCL_VOID v_matchproto_(td_xyzzy_debug_aclobj__fini)
+xyzzy_aclobj__fini(struct VPFX(debug_aclobj) **op)
+{
+	struct VPFX(debug_aclobj) *o;
+
+	TAKE_OBJ_NOTNULL(o, op, VMOD_DEBUG_ACLOBJ_MAGIC);
+	REPLACE(o->vcl_name, NULL);
+	FREE_OBJ(o);
+}
+
+VCL_ACL v_matchproto_(td_xyzzy_debug_aclobj_get)
+xyzzy_aclobj_get(VRT_CTX, struct VPFX(debug_aclobj) *o)
+{
+	CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
+	CHECK_OBJ_NOTNULL(o, VMOD_DEBUG_ACLOBJ_MAGIC);
+	return (o->acl);
+}


More information about the varnish-commit mailing list