[master] b9756475f Warn about ACL entries with non-zero host bits

Nils Goroll nils.goroll at uplex.de
Wed Apr 1 18:48:08 UTC 2020


commit b9756475fa0ca69e0a3a31b919a6f26141c30f79
Author: Nils Goroll <nils.goroll at uplex.de>
Date:   Thu Dec 12 20:32:53 2019 +0100

    Warn about ACL entries with non-zero host bits
    
    Summary:
    
    ACL entries with netmasks shorter than the maximum for the respective
    protocol represent network addresses and as such, by convention,
    should be written with all zero bits in the host part to avoid
    confusion.
    
    This patch adds VCL compile warnings and improved logging if they are
    not.
    
    Discussion:
    
    For example, while 1.2.3.0/24 and 1.2.3.255/24, in CIDR notation, both
    specify all addresses with the first three octets matching 1, 2 and 3,
    using the latter can be a source of subtle confusion.
    
    This becomes particularly apparent with netmasks outside byte
    boundaries: 1.2.6.0/22 specifies addresses 1.2.4.0 - 1.2.7.255, but
    not so experienced administrators might be tempted to think that it
    specified 1.2.6.0 - 1.2.9.255.
    
    To summarize, denoting network addresses in non-canonical form is
    confusing, a possible source of error and additionally complicates
    analyses.
    
    This patch makes sure that such mishaps do not remain unnoticed by
    
    - issuing warnings during VCL compilation about non-canonical network
      addresses
    
    - Logging ACL matches together with the canonical address
    
    The actual matching code is not touched, but a minor simplification
    can be applied later.

diff --git a/bin/varnishtest/tests/c00005.vtc b/bin/varnishtest/tests/c00005.vtc
index 92ef9f9f2..0eed7ef55 100644
--- a/bin/varnishtest/tests/c00005.vtc
+++ b/bin/varnishtest/tests/c00005.vtc
@@ -115,11 +115,11 @@ varnish v1 -vcl {
 
 logexpect l1 -v v1 -g raw {
 	expect * 1007	ReqHeader	{^\Qip: 1.2.3.0\E$}
-	expect 0 =	VCL_acl	{^\QMATCH acl1 "1.2.3.4"/24\E$}
+	expect 0 =	VCL_acl	{^\QMATCH acl1 "1.2.3.4"/24 fixed: 1.2.3.0/24\E$}
 	expect 1 =	ReqHeader	{^\Qip: 1.2.3.63\E$}
-	expect 0 =	VCL_acl	{^\QMATCH acl1 "1.2.3.4"/24\E$}
+	expect 0 =	VCL_acl	{^\QMATCH acl1 "1.2.3.4"/24 fixed: 1.2.3.0/24\E$}
 	expect 1 =	ReqHeader	{^\Qip: 1.2.3.64\E$}
-	expect 0 =	VCL_acl	{^\QMATCH acl1 "1.2.3.66"/26\E$}
+	expect 0 =	VCL_acl	{^\QMATCH acl1 "1.2.3.66"/26 fixed: 1.2.3.64/26\E$}
 
 	expect 1 =	ReqHeader	{^\Qip: 1.3.4.255\E$}
 	expect 0 =	VCL_acl	{^\QMATCH acl1 "1.3.4.0"/23\E$}
diff --git a/lib/libvcc/vcc_acl.c b/lib/libvcc/vcc_acl.c
index cf18107d7..443d9189e 100644
--- a/lib/libvcc/vcc_acl.c
+++ b/lib/libvcc/vcc_acl.c
@@ -40,6 +40,8 @@
 #include <string.h>
 
 #include "vcc_compile.h"
+#include <vtcp.h>
+#include <vsa.h>
 
 #define ACL_MAXADDR	(sizeof(struct in6_addr) + 1)
 
@@ -50,6 +52,7 @@ struct acl_e {
 	unsigned		not;
 	unsigned		para;
 	char			*addr;
+	char			*fixed;
 	struct token		*t_addr;
 	struct token		*t_mask;
 };
@@ -91,10 +94,60 @@ vcl_acl_cmp(struct acl_e *ae1, struct acl_e *ae2)
 	return (0);
 }
 
+static char *
+vcc_acl_chk(struct vcc *tl, const struct acl_e *ae, const int l,
+    unsigned char *p, int fam)
+{
+	const unsigned char *u;
+	char h[VTCP_ADDRBUFSIZE];
+	char t[VTCP_ADDRBUFSIZE + 10];
+	char s[vsa_suckaddr_len];
+	struct suckaddr *sa;
+	unsigned m;
+	int ll, ret = 0;
+
+	u = p;
+	ll = l;
+	m = ae->mask;
+
+	p += m / 8;
+	ll -= m / 8;
+	assert (ll >= 0);
+	m %= 8;
+
+	if (m && (*p << m & 0xff) != 0) {
+		ret = 1;
+		m = 0xff00 >> m;
+		*p &= m;
+	}
+	if (m) {
+		p++;
+		ll--;
+	}
+
+	for ( ; ll > 0; p++, ll--) {
+		if (*p == 0)
+			continue;
+		ret = 1;
+		*p = 0;
+	}
+	if (ret == 0)
+		return (NULL);
+
+	sa = VSA_BuildFAP(s, fam, u, l, NULL, 0);
+	AN(sa);
+	VTCP_name(sa, h, sizeof h, NULL, 0);
+	bprintf(t, "%s/%d", h, ae->mask);
+	VSB_printf(tl->sb, "Address/Netmask mismatch, changed to %s\n", t);
+	vcc_ErrWhere(tl, ae->t_addr);
+	vcc_Warn(tl);
+	return (strdup(t));
+}
+
 
 static void
 vcc_acl_add_entry(struct vcc *tl, const struct acl_e *ae, int l,
-    const unsigned char *u, int fam)
+    unsigned char *u, int fam)
 {
 	struct acl_e *ae2, *aen;
 	int i;
@@ -120,6 +173,8 @@ vcc_acl_add_entry(struct vcc *tl, const struct acl_e *ae, int l,
 	AN(aen);
 	*aen = *ae;
 
+	aen->fixed = vcc_acl_chk(tl, ae, l, u, fam);
+
 	/* We treat family as part of address, it saves code */
 	assert(fam <= 0xff);
 	aen->data[0] = fam & 0xff;
@@ -410,6 +465,7 @@ vcc_acl_emit(struct vcc *tl, const char *name, const char *rname, int anon)
 		}
 
 		if (m > 0) {
+			// XXX can remove masking due to fixup
 			/* Do fractional byte compares */
 			Fh(tl, 0, "\t%*s%sif ((a[%d] & 0x%x) == %d) {\n",
 			    -i, "", "", i - 1, (0xff00 >> m) & 0xff,
@@ -436,6 +492,9 @@ vcc_acl_emit(struct vcc *tl, const char *name, const char *rname, int anon)
 				t = VTAILQ_NEXT(t, list);
 				AN(t);
 			} while (ae->t_mask != NULL);
+			if (ae->fixed)
+				Fh(tl, 0, "\" fixed: %s\"",
+				   ae->fixed);
 			Fh(tl, 0, ");\n");
 		}
 


More information about the varnish-commit mailing list