Soft bans are like normal bans, but they are subject to grace per usual rules. --- bin/varnishd/cache/cache.h | 1 + bin/varnishd/cache/cache_ban.c | 58 +++++++++++++++++++++++++++++++++---- bin/varnishd/cache/cache_vrt.c | 6 ++-- bin/varnishtest/tests/s00004.vtc | 47 ++++++++++++++++++++++++++++++ bin/varnishtest/tests/s00005.vtc | 59 ++++++++++++++++++++++++++++++++++++++ include/vcli.h | 7 +++++ include/vrt.h | 4 +-- lib/libvcl/vcc_action.c | 25 ++++++++++++++-- 8 files changed, 195 insertions(+), 12 deletions(-) create mode 100644 bin/varnishtest/tests/s00004.vtc create mode 100644 bin/varnishtest/tests/s00005.vtc
diff --git a/bin/varnishd/cache/cache.h b/bin/varnishd/cache/cache.h index 6d4fe86..66ee459 100644 --- a/bin/varnishd/cache/cache.h +++ b/bin/varnishd/cache/cache.h @@ -757,6 +757,7 @@ void BAN_Compile(void); struct ban *BAN_RefBan(struct objcore *oc, double t0, const struct ban *tail); void BAN_TailDeref(struct ban **ban); double BAN_Time(const struct ban *ban); +void BAN_Set_Soft(struct ban *b, int soft); /* cache_busyobj.c */ void VBO_Init(void); diff --git a/bin/varnishd/cache/cache_ban.c b/bin/varnishd/cache/cache_ban.c index aa8bca9..6270a4a 100644 --- a/bin/varnishd/cache/cache_ban.c +++ b/bin/varnishd/cache/cache_ban.c @@ -42,6 +42,7 @@ * 8 bytes - double: timestamp XXX: Byteorder ? * 4 bytes - be32: length * 1 byte - flags: 0x01: BAN_F_REQ + * 0x02: BAN_F_SOFT * N tests * A test have this form: * 1 byte - arg (see ban_vars.h col 3 "BAN_ARG_XXX") @@ -82,6 +83,7 @@ struct ban { unsigned flags; #define BAN_F_GONE (1 << 0) #define BAN_F_REQ (1 << 2) +#define BAN_F_SOFT (1 << 3) /* soft ban, aka grace */ #define BAN_F_LURK (3 << 6) /* ban-lurker-color */ VTAILQ_HEAD(,objcore) objcore; struct vsb *vsb; @@ -392,7 +394,11 @@ BAN_Insert(struct ban *b) t0 = VTIM_real(); memcpy(b->spec, &t0, sizeof t0); - b->spec[12] = (b->flags & BAN_F_REQ) ? 1 : 0; + b->spec[12] = 0; + if (b->flags & BAN_F_REQ) + b->spec[12] |= 0x1; + if (b->flags & BAN_F_SOFT) + b->spec[12] |= 0x2; memcpy(b->spec + 13, VSB_data(b->vsb), ln); ln += 13; vbe32enc(b->spec + 8, ln); @@ -551,8 +557,10 @@ BAN_Reload(const uint8_t *ban, unsigned len) AN(b2->spec); memcpy(b2->spec, ban, len); b2->flags |= gone; - if (ban[12]) + if (ban[12] & 0x01) b2->flags |= BAN_F_REQ; + if (ban[12] & 0x02) + b2->flags |= BAN_F_SOFT; if (b == NULL) VTAILQ_INSERT_TAIL(&ban_head, b2, list); else @@ -587,6 +595,21 @@ BAN_Time(const struct ban *b) } /*-------------------------------------------------------------------- + * Set/unset the soft flag on a ban + */ + +void +BAN_Set_Soft(struct ban *b, int soft) +{ + + CHECK_OBJ_NOTNULL(b, BAN_MAGIC); + if (soft) + b->flags |= BAN_F_SOFT; + else + b->flags &= ~BAN_F_SOFT; +} + +/*-------------------------------------------------------------------- * All silos have read their bans, ready for action */ @@ -687,7 +710,8 @@ ban_check_object(struct object *o, struct vsl_log *vsl, struct ban *b; struct objcore *oc; struct ban * volatile b0; - unsigned tests, skipped; + unsigned tests, skipped, soft; + double now; CHECK_OBJ_NOTNULL(o, OBJECT_MAGIC); CHECK_OBJ_ORNULL(req_http, HTTP_MAGIC); @@ -708,6 +732,7 @@ ban_check_object(struct object *o, struct vsl_log *vsl, */ tests = 0; skipped = 0; + soft = 0; for (b = b0; b != oc->ban; b = VTAILQ_NEXT(b, list)) { CHECK_OBJ_NOTNULL(b, BAN_MAGIC); if (b->flags & BAN_F_GONE) @@ -724,15 +749,21 @@ ban_check_object(struct object *o, struct vsl_log *vsl, * be other bans that match, so we soldier on */ skipped++; - } else if (ban_evaluate(b->spec, o->http, req_http, &tests)) + } else if (ban_evaluate(b->spec, o->http, req_http, &tests)) { + if (b->flags & BAN_F_SOFT) { + soft = 1; + continue; + } + soft = 0; /* Found hard ban */ break; + } } Lck_Lock(&ban_mtx); VSC_C_main->bans_tested++; VSC_C_main->bans_tests_tested += tests; - if (b == oc->ban && skipped > 0) { + if (b == oc->ban && skipped > 0 && soft == 0) { AZ(req_http); Lck_Unlock(&ban_mtx); /* @@ -751,10 +782,21 @@ ban_check_object(struct object *o, struct vsl_log *vsl, } Lck_Unlock(&ban_mtx); - if (b == oc->ban) { /* not banned */ + if (soft == 0 && b == oc->ban) { /* not banned */ oc->ban = b0; oc_updatemeta(oc); return (0); + } else if (soft) { + now = VTIM_real(); + /* Softban, set ttl to now */ + if (o->exp.entered + o->exp.ttl > now) + o->exp.ttl = now - o->exp.entered; + oc->ban = b0; + oc_updatemeta(oc); + /* XXX: no req in lurker */ + VSLb(vsl, SLT_ExpBan, "%u was softbanned", o->vxid); + EXP_Rearm(o); + return (2); } else { EXP_Clr(&o->exp); oc->ban = NULL; @@ -1026,6 +1068,9 @@ ccf_ban(struct cli *cli, const char * const *av, void *priv) VCLI_SetResult(cli, CLIS_CANT); return; } + if (strcmp(av[1], "softban") == 0) { + b->flags |= BAN_F_SOFT; + } for (i = 0; i < narg; i += 4) if (BAN_AddTest(cli, b, av[i + 2], av[i + 3], av[i + 4])) { BAN_Free(b); @@ -1125,6 +1170,7 @@ ccf_ban_list(struct cli *cli, const char * const *av, void *priv) static struct cli_proto ban_cmds[] = { { CLI_BAN_URL, "", ccf_ban_url }, { CLI_BAN, "", ccf_ban }, + { CLI_SOFTBAN, "", ccf_ban }, { CLI_BAN_LIST, "", ccf_ban_list }, { NULL } }; diff --git a/bin/varnishd/cache/cache_vrt.c b/bin/varnishd/cache/cache_vrt.c index ed7ae59..70537fc 100644 --- a/bin/varnishd/cache/cache_vrt.c +++ b/bin/varnishd/cache/cache_vrt.c @@ -433,7 +433,7 @@ VRT_synth_page(const struct req *req, unsigned flags, const char *str, ...) /*--------------------------------------------------------------------*/ void -VRT_ban(const struct req *req, char *cmds, ...) +VRT_ban(const struct req *req, int soft, char *cmds, ...) { char *a1, *a2, *a3; va_list ap; @@ -442,6 +442,7 @@ VRT_ban(const struct req *req, char *cmds, ...) CHECK_OBJ_NOTNULL(req, REQ_MAGIC); b = BAN_New(); + BAN_Set_Soft(b, soft); va_start(ap, cmds); a1 = cmds; good = 0; @@ -468,7 +469,7 @@ VRT_ban(const struct req *req, char *cmds, ...) /*--------------------------------------------------------------------*/ void -VRT_ban_string(const struct req *req, const char *str) +VRT_ban_string(const struct req *req, int soft, const char *str) { char *a1, *a2, *a3; char **av; @@ -484,6 +485,7 @@ VRT_ban_string(const struct req *req, const char *str) return; } b = BAN_New(); + BAN_Set_Soft(b, soft); good = 0; for (i = 1; ;) { a1 = av[i++]; diff --git a/bin/varnishtest/tests/s00004.vtc b/bin/varnishtest/tests/s00004.vtc new file mode 100644 index 0000000..781d1dc --- /dev/null +++ b/bin/varnishtest/tests/s00004.vtc @@ -0,0 +1,47 @@ +varnishtest "Softbans from CLI" + +server s1 { + rxreq + txresp + + sema r1 sync 3 + + rxreq + txresp +} -start + +varnish v1 -vcl+backend { + sub vcl_hit { + if (obj.ttl <= 0s) { + set req.http.grace = "t"; + } + } + sub vcl_fetch { + set beresp.ttl = 1m; + set beresp.grace = 1m; + } + sub vcl_deliver { + set resp.http.grace = req.http.grace; + } +} -start + +client c1 { + txreq + rxresp + expect resp.status == 200 + delay 1 + txreq + sema r1 sync 3 + rxresp +} -start + +varnish v1 -cliok "softban req.url ~ ^" +delay 1; + +client c2 { + sema r1 sync 3 + txreq + rxresp + expect resp.http.grace == "t" + expect resp.status == 200 +} -run diff --git a/bin/varnishtest/tests/s00005.vtc b/bin/varnishtest/tests/s00005.vtc new file mode 100644 index 0000000..35d1a8a --- /dev/null +++ b/bin/varnishtest/tests/s00005.vtc @@ -0,0 +1,59 @@ +varnishtest "Softbans from VCL" + +server s1 { + rxreq + txresp + + sema r1 sync 3 + + rxreq + txresp +} -start + +varnish v1 -vcl+backend { + sub vcl_recv { + if (req.request == "SOFTBAN") { + softban("req.url ~ " + req.url); + error 410; + } + } + + sub vcl_hit { + if (obj.ttl <= 0s) { + set req.http.grace = "t"; + } + } + sub vcl_fetch { + set beresp.ttl = 1m; + set beresp.grace = 1m; + } + sub vcl_deliver { + set resp.http.grace = req.http.grace; + } +} -start + +client c1 { + txreq + rxresp + expect resp.status == 200 + delay 1 + txreq + sema r1 sync 3 + rxresp +} -start + +delay 1 +client c2 { + txreq -req SOFTBAN -url / + rxresp + expect resp.status == 410 +} -run + + +client c3 { + sema r1 sync 3 + txreq + rxresp + expect resp.http.grace == "t" + expect resp.status == 200 +} -run diff --git a/include/vcli.h b/include/vcli.h index 04ac11c..3d79e7b 100644 --- a/include/vcli.h +++ b/include/vcli.h @@ -78,6 +78,13 @@ "\tList the active bans.", \ 0, 0 +#define CLI_SOFTBAN \ + "softban", \ + "softban <field> <operator> <arg> [&& <field> <oper> <arg>]...", \ + "\tAll objects where the all the conditions match will be " \ + "marked obsolete, but still eligible for grace.", \ + 3, UINT_MAX + #define CLI_VCL_LOAD \ "vcl.load", \ "vcl.load <configname> <filename>", \ diff --git a/include/vrt.h b/include/vrt.h index c98e085..bb21f93 100644 --- a/include/vrt.h +++ b/include/vrt.h @@ -177,8 +177,8 @@ int VRT_re_match(struct req *, const char *, void *re); const char *VRT_regsub(struct req *, int all, const char *, void *, const char *); -void VRT_ban(const struct req *, char *, ...); -void VRT_ban_string(const struct req *, const char *); +void VRT_ban(const struct req *, int, char *, ...); +void VRT_ban_string(const struct req *, int, const char *); void VRT_purge(struct req *, double ttl, double grace); void VRT_count(struct req *, unsigned); diff --git a/lib/libvcl/vcc_action.c b/lib/libvcl/vcc_action.c index eae6231..3662a39 100644 --- a/lib/libvcl/vcc_action.c +++ b/lib/libvcl/vcc_action.c @@ -183,7 +183,7 @@ parse_ban(struct vcc *tl) ExpectErr(tl, '('); vcc_NextToken(tl); - Fb(tl, 1, "VRT_ban_string(req, "); + Fb(tl, 1, "VRT_ban_string(req, 0, "); vcc_Expr(tl, STRING); ERRCHK(tl); Fb(tl, 0, ");\n"); @@ -202,7 +202,7 @@ parse_ban_url(struct vcc *tl) ExpectErr(tl, '('); vcc_NextToken(tl); - Fb(tl, 1, "VRT_ban(req, \"req.url\", \"~\", "); + Fb(tl, 1, "VRT_ban(req, 0, \"req.url\", \"~\", "); vcc_Expr(tl, STRING); ERRCHK(tl); ExpectErr(tl, ')'); @@ -213,6 +213,26 @@ parse_ban_url(struct vcc *tl) /*--------------------------------------------------------------------*/ static void +parse_softban(struct vcc *tl) +{ + + vcc_NextToken(tl); + + ExpectErr(tl, '('); + vcc_NextToken(tl); + + Fb(tl, 1, "VRT_ban_string(req, 1, "); + vcc_Expr(tl, STRING); + ERRCHK(tl); + Fb(tl, 0, ");\n"); + + ExpectErr(tl, ')'); + vcc_NextToken(tl); +} + +/*--------------------------------------------------------------------*/ + +static void parse_new_syntax(struct vcc *tl) { @@ -325,6 +345,7 @@ static struct action_table { { "hash_data", parse_hash_data, VCL_MET_HASH }, { "ban", parse_ban }, { "ban_url", parse_ban_url }, + { "softban", parse_softban }, { "remove", parse_unset }, /* backward compatibility */ { "return", parse_return }, { "rollback", parse_rollback }, -- 1.7.10.4 _______________________________________________ varnish-dev mailing list varnish-dev@varnish-cache.org https://www.varnish-cache.org/lists/mailman/listinfo/varnish-dev