From: phk Date: Thu, 20 Nov 2008 10:03:53 +0000 (+0000) Subject: Clean up the ACL generation code a bit. X-Git-Url: https://err.no/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=a0e9c778f4c90edb1ed9a11ec8fd10049b14ac36;p=varnish Clean up the ACL generation code a bit. git-svn-id: svn+ssh://projects.linpro.no/svn/varnish/trunk@3409 d4fa192b-c00b-0410-8231-f00ffab90ce4 --- diff --git a/varnish-cache/lib/libvcl/vcc_acl.c b/varnish-cache/lib/libvcl/vcc_acl.c index dde8a8d0..f3155e20 100644 --- a/varnish-cache/lib/libvcl/vcc_acl.c +++ b/varnish-cache/lib/libvcl/vcc_acl.c @@ -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); }