]> err.no Git - varnish/commitdiff
Clean up the ACL generation code a bit.
authorphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 20 Nov 2008 10:03:53 +0000 (10:03 +0000)
committerphk <phk@d4fa192b-c00b-0410-8231-f00ffab90ce4>
Thu, 20 Nov 2008 10:03:53 +0000 (10:03 +0000)
git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3409 d4fa192b-c00b-0410-8231-f00ffab90ce4

varnish-cache/lib/libvcl/vcc_acl.c

index dde8a8d0d5bb023992cfdf506664ee0d4eceb592..f3155e2033689f163d855bba5af51de27567af17 100644 (file)
@@ -60,59 +60,87 @@ struct acl_e {
 
 /* Compare two acl rules for ordering */
 
+#define CMP(a, b)                                                      \
+       do {                                                            \
+               if ((a) < (b))                                          \
+                       return (-1);                                    \
+               else if ((b) < (a))                                     \
+                       return (1);                                     \
+       } while (0)
+               
 static int
-vcl_acl_cmp(struct tokenlist *tl, struct acl_e *ae1, struct acl_e *ae2)
+vcl_acl_cmp(struct acl_e *ae1, struct acl_e *ae2)
 {
        unsigned char *p1, *p2;
        unsigned m;
 
-       (void)tl;
        p1 = ae1->data;
        p2 = ae2->data;
        m = ae1->mask;
        if (ae2->mask < m)
                m = ae2->mask;
        for (; m >= 8; m -= 8) {
-               if (*p1 < *p2)
-                       return (-1);
-               if (*p1 > *p2)
-                       return (1);
+               CMP(*p1, *p2);
                p1++;
                p2++;
        }
        if (m) {
                m = 0xff00 >> m;
                m &= 0xff;
-               if ((*p1 & m) < (*p2 & m))
-                       return (-1);
-               if ((*p1 & m) > (*p2 & m))
-                       return (1);
+               CMP(*p1 & m, *p2 & m);
        }
-       if (ae1->mask > ae2->mask)
-               return (-1);
-       if (ae1->mask < ae2->mask)
-               return (1);
+       /* Long mask is less than short mask */
+       CMP(ae2->mask, ae1->mask);
 
        return (0);
 }
 
 
 static void
-vcl_acl_add_entry(struct tokenlist *tl, struct acl_e *ae)
+vcc_acl_add_entry(struct tokenlist *tl, const struct acl_e *ae, int l,
+    const unsigned char *u, int fam)
 {
-       struct acl_e *ae2;
+       struct acl_e *ae2, *aen;
        int i;
 
+       if (fam == PF_INET && ae->mask > 32) {
+               vsb_printf(tl->sb,
+                   "Too wide mask (%u) for IPv4 address", ae->mask);
+               vcc_ErrWhere(tl, ae->t_mask);
+               return;
+       }
+       if (fam == PF_INET6 && ae->mask > 128) {
+               vsb_printf(tl->sb,
+                   "Too wide mask (%u) for IPv6 address", ae->mask);
+               vcc_ErrWhere(tl, ae->t_mask);
+               return;
+       }
+
+       /* Make a copy from the template */
+       aen = TlAlloc(tl, sizeof *ae2);
+       AN(aen);
+       *aen = *ae;
+
+       /* We treat family as part of address, it saves code */
+       assert(fam <= 0xff);
+       aen->data[0] = fam & 0xff;
+       aen->mask += 8;
+
+       memcpy(aen->data + 1, u, l);
+
        VTAILQ_FOREACH(ae2, &tl->acl, list) {
-               i = vcl_acl_cmp(tl, ae, ae2);
+               i = vcl_acl_cmp(aen, ae2);
                if (i == 0) {
-                       /* If the two rules agree, silently ignore it */
-                       if (ae->not == ae2->not)
+                       /*
+                        * If the two rules agree, silently ignore it
+                        * XXX: is that counter intuitive ?
+                        */
+                       if (aen->not == ae2->not)
                                return;
                        vsb_printf(tl->sb, "Conflicting ACL entries:\n");
                        vcc_ErrWhere(tl, ae2->t_addr);
                        vsb_printf(tl->sb, "vs:\n");
-                       vcc_ErrWhere(tl, ae->t_addr);
+                       vcc_ErrWhere(tl, aen->t_addr);
                        return;
                }
                /*
@@ -126,43 +154,11 @@ vcl_acl_add_entry(struct tokenlist *tl, struct acl_e *ae)
                 * be used to gather statistics.
                 */
                if (i < 0) {
-                       VTAILQ_INSERT_BEFORE(ae2, ae, list);
+                       VTAILQ_INSERT_BEFORE(ae2, aen, list);
                        return;
                }
        }
-       VTAILQ_INSERT_TAIL(&tl->acl, ae, list);
-}
-
-static void
-vcc_acl_emit_entry(struct tokenlist *tl, const struct acl_e *ae, int l,
-    const unsigned char *u, int fam)
-{
-       struct acl_e *ae2;
-
-       if (fam == PF_INET && ae->mask > 32) {
-               vsb_printf(tl->sb,
-                   "Too wide mask (%u) for IPv4 address", ae->mask);
-               vcc_ErrWhere(tl, ae->t_mask);
-               return;
-       }
-       if (fam == PF_INET6 && ae->mask > 128) {
-               vsb_printf(tl->sb,
-                   "Too wide mask (%u) for IPv6 address", ae->mask);
-               vcc_ErrWhere(tl, ae->t_mask);
-               return;
-       }
-
-       ae2 = TlAlloc(tl, sizeof *ae2);
-       AN(ae2);
-       *ae2 = *ae;
-
-       ae2->data[0] = fam & 0xff;
-       ae2->mask += 8; /* family matching */
-
-       memcpy(ae2->data + 1, u, l);
-
-       vcl_acl_add_entry(tl, ae2);
-
+       VTAILQ_INSERT_TAIL(&tl->acl, aen, list);
 }
 
 static void
@@ -211,7 +207,7 @@ vcc_acl_try_getaddrinfo(struct tokenlist *tl, struct acl_e *ae)
                        if (ae->t_mask == NULL)
                                ae->mask = 32;
                        i4++;
-                       vcc_acl_emit_entry(tl, ae, 4, u, res->ai_family);
+                       vcc_acl_add_entry(tl, ae, 4, u, res->ai_family);
                        break;
                case PF_INET6:
                        assert(PF_INET6 < 256);
@@ -221,7 +217,7 @@ vcc_acl_try_getaddrinfo(struct tokenlist *tl, struct acl_e *ae)
                        if (ae->t_mask == NULL)
                                ae->mask = 128;
                        i6++;
-                       vcc_acl_emit_entry(tl, ae, 16, u, res->ai_family);
+                       vcc_acl_add_entry(tl, ae, 16, u, res->ai_family);
                        break;
                default:
                        vsb_printf(tl->sb,
@@ -270,7 +266,7 @@ vcc_acl_try_netnotation(struct tokenlist *tl, struct acl_e *ae)
        }
        if (ae->t_mask == NULL)
                ae->mask = 8 + 8 * i;
-       vcc_acl_emit_entry(tl, ae, 4, b, AF_INET);
+       vcc_acl_add_entry(tl, ae, 4, b, AF_INET);
        return (1);
 }
 
@@ -321,9 +317,12 @@ vcc_acl_entry(struct tokenlist *tl)
        ERRCHK(tl);
 }
 
+/*********************************************************************
+ * Emit a function to match the ACL we have collected
+ */
+
 static void
-vcc_acl_bot(const struct tokenlist *tl, const char *acln, int silent,
-    const char *pfx)
+vcc_acl_emit(const struct tokenlist *tl, const char *acln, int anon)
 {
        struct acl_e *ae;
        int depth, l, m, i;
@@ -333,7 +332,7 @@ vcc_acl_bot(const struct tokenlist *tl, const char *acln, int silent,
 
        Fh(tl, 0, "\nstatic int\n");
        Fh(tl, 0, "match_acl_%s_%s(const struct sess *sp, const void *p)\n",
-           pfx, acln);
+           anon ? "anon" : "named", acln);
        Fh(tl, 0, "{\n");
        Fh(tl, 0, "\tconst unsigned char *a;\n");
        assert(sizeof (unsigned char) == 1);
@@ -375,30 +374,31 @@ vcc_acl_bot(const struct tokenlist *tl, const char *acln, int silent,
                /* Back down, if necessary */
                oc = "";
                while (l <= depth) {
-                       Fh(tl, 0, "\t%*s}\n",
-                           -depth, "");
+                       Fh(tl, 0, "\t%*s}\n", -depth, "");
                        depth--;
                        oc = "else ";
                }
+
                m = ae->mask;
                m -= l * 8;
+
+               /* Do whole byte compares */
                for (i = l; m >= 8; m -= 8, i++) {
-                       if (i == 0) {
+                       if (i == 0)
                                Fh(tl, 0, "\t%*s%sif (fam == %d) {\n",
                                    -i, "", oc, ae->data[i]);
-                       } else {
+                       else
                                Fh(tl, 0, "\t%*s%sif (a[%d] == %d) {\n",
                                    -i, "", oc, i - 1, ae->data[i]);
-                       }
                        at[i] = ae->data[i];
                        depth = i;
                        oc = "";
                }
+
                if (m > 0) {
+                       /* Do fractional byte compares */
                        Fh(tl, 0, "\t%*s%sif ((a[%d] & 0x%x) == %d) {\n",
-                           -i, "",
-                           oc,
-                           i - 1, (0xff00 >> m) & 0xff,
+                           -i, "", oc, i - 1, (0xff00 >> m) & 0xff,
                            ae->data[i] & ((0xff00 >> m) & 0xff));
                        at[i] = 256;
                        depth = i;
@@ -407,11 +407,9 @@ vcc_acl_bot(const struct tokenlist *tl, const char *acln, int silent,
 
                i = (ae->mask + 7) / 8;
 
-               if (!silent) {
+               if (!anon) {
                        Fh(tl, 0, "\t%*sVRT_acl_log(sp, \"%sMATCH %s \" ",
-                           -i, "",
-                           ae->not ? "NEG_" : "",
-                           acln,
+                           -i, "", ae->not ? "NEG_" : "", acln,
                            PF(ae->t_addr));
                        EncToken(tl->fh, ae->t_addr);
                        if (ae->t_mask != NULL)
@@ -422,9 +420,12 @@ vcc_acl_bot(const struct tokenlist *tl, const char *acln, int silent,
                Fh(tl, 0, "\t%*sreturn (%d);\n", -i, "", ae->not ? 0 : 1);
        }
 
+       /* Unwind */
        for (; 0 <= depth; depth--)
                Fh(tl, 0, "\t%*.*s}\n", depth, depth, "");
-       if (!silent)
+
+       /* Deny by default */
+       if (!anon)
                Fh(tl, 0, "\tVRT_acl_log(sp, \"NO_MATCH %s\");\n", acln);
        Fh(tl, 0, "\treturn (0);\n}\n");
 }
@@ -453,7 +454,7 @@ vcc_Cond_Ip(const struct var *vp, struct tokenlist *tl)
                asprintf(&acln, "%u", tl->cnt);
                assert(acln != NULL);
                vcc_acl_entry(tl);
-               vcc_acl_bot(tl, acln, 1, "anon");
+               vcc_acl_emit(tl, acln, 1);
                Fb(tl, 1, "%smatch_acl_anon_%s(sp, %s)\n",
                    (tcond == T_NEQ ? "!" : ""), acln, vp->rname);
                free(acln);
@@ -497,7 +498,7 @@ vcc_Acl(struct tokenlist *tl)
        ExpectErr(tl, '}');
        vcc_NextToken(tl);
 
-       vcc_acl_bot(tl, acln, 0, "named");
+       vcc_acl_emit(tl, acln, 0);
 
        free(acln);
 }