varnish-cache/bin/varnishd/cache/cache_ban.c
0
/*-
1
 * Copyright (c) 2006 Verdens Gang AS
2
 * Copyright (c) 2006-2015 Varnish Software AS
3
 * All rights reserved.
4
 *
5
 * Author: Poul-Henning Kamp <phk@phk.freebsd.dk>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 *
9
 * Redistribution and use in source and binary forms, with or without
10
 * modification, are permitted provided that the following conditions
11
 * are met:
12
 * 1. Redistributions of source code must retain the above copyright
13
 *    notice, this list of conditions and the following disclaimer.
14
 * 2. Redistributions in binary form must reproduce the above copyright
15
 *    notice, this list of conditions and the following disclaimer in the
16
 *    documentation and/or other materials provided with the distribution.
17
 *
18
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
22
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28
 * SUCH DAMAGE.
29
 *
30
 */
31
32
#include "config.h"
33
34
#include <stdlib.h>
35
#include <stdio.h>
36
37
#include "cache_varnishd.h"
38
#include "cache_ban.h"
39
#include "cache_objhead.h"
40
41
#include "vcli_serve.h"
42
#include "vend.h"
43
#include "vmb.h"
44
45
/* cache_ban_build.c */
46
void BAN_Build_Init(void);
47
void BAN_Build_Fini(void);
48
49
struct lock ban_mtx;
50
int ban_shutdown;
51
struct banhead_s ban_head = VTAILQ_HEAD_INITIALIZER(ban_head);
52
struct ban * volatile ban_start;
53
54
static pthread_t ban_thread;
55
static int ban_holds;
56
uint64_t bans_persisted_bytes;
57
uint64_t bans_persisted_fragmentation;
58
59
struct ban_test {
60
        uint8_t                 oper;
61
        uint8_t                 arg1;
62
        const char              *arg1_spec;
63
        const char              *arg2;
64
        double                  arg2_double;
65
        const void              *arg2_spec;
66
};
67
68
static const char * const arg_name[BAN_ARGARRSZ + 1] = {
69
#define PVAR(a, b, c) [BAN_ARGIDX(c)] = (a),
70
#include "tbl/ban_vars.h"
71
        [BAN_ARGARRSZ] = NULL
72
};
73
74
/*--------------------------------------------------------------------
75
 * Storage handling of bans
76
 */
77
78
static struct ban *
79 1040
ban_alloc(void)
80
{
81
        struct ban *b;
82
83 1040
        ALLOC_OBJ(b, BAN_MAGIC);
84 1040
        if (b != NULL)
85 1040
                VTAILQ_INIT(&b->objcore);
86 1040
        return (b);
87
}
88
89
void
90 2883
BAN_Free(struct ban *b)
91
{
92
93 2883
        CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
94 2883
        AZ(b->refcount);
95 2883
        assert(VTAILQ_EMPTY(&b->objcore));
96
97 2883
        if (b->spec != NULL)
98 2883
                free(b->spec);
99 2883
        FREE_OBJ(b);
100 2883
}
101
102
/*--------------------------------------------------------------------
103
 * Get/release holds which prevent the ban_lurker from starting.
104
 * Holds are held while stevedores load zombie objects.
105
 */
106
107
void
108 1520
BAN_Hold(void)
109
{
110
111 1520
        Lck_Lock(&ban_mtx);
112
        /* Once holds are released, we allow no more */
113 1520
        assert(ban_holds > 0);
114 1520
        ban_holds++;
115 1520
        Lck_Unlock(&ban_mtx);
116 1520
}
117
118
void
119 38827
BAN_Release(void)
120
{
121
122 38827
        Lck_Lock(&ban_mtx);
123 38827
        assert(ban_holds > 0);
124 38827
        ban_holds--;
125 38827
        Lck_Unlock(&ban_mtx);
126 38827
        if (ban_holds == 0) {
127 37307
                BANIDX_fini();
128 37307
                WRK_BgThread(&ban_thread, "ban-lurker", ban_lurker, NULL);
129 37307
        }
130 38827
}
131
132
/*--------------------------------------------------------------------
133
 * Extract time and length from ban-spec
134
 */
135
136
vtim_real
137 38080
ban_time(const uint8_t *banspec)
138
{
139
        vtim_real t;
140
        uint64_t u;
141
142 38080
        assert(sizeof t == sizeof u);
143 38080
        assert(sizeof t == (BANS_LENGTH - BANS_TIMESTAMP));
144 38080
        u = vbe64dec(banspec + BANS_TIMESTAMP);
145 38080
        memcpy(&t, &u, sizeof t);
146 38080
        return (t);
147
}
148
149
unsigned
150 240351
ban_len(const uint8_t *banspec)
151
{
152
        unsigned u;
153
154 240351
        u = vbe32dec(banspec + BANS_LENGTH);
155 240351
        return (u);
156
}
157
158
int
159 10960
ban_equal(const uint8_t *bs1, const uint8_t *bs2)
160
{
161
        unsigned u;
162
163
        /*
164
         * Compare two ban-strings.
165
         */
166 10960
        u = ban_len(bs1);
167 10960
        if (u != ban_len(bs2))
168 4120
                return (0);
169 6840
        if (bs1[BANS_FLAGS] & BANS_FLAG_NODEDUP)
170 120
                return (0);
171
172 6720
        return (!memcmp(bs1 + BANS_LENGTH, bs2 + BANS_LENGTH, u - BANS_LENGTH));
173 10960
}
174
175
void
176 39347
ban_mark_completed(struct ban *b)
177
{
178
        unsigned ln;
179
180 39347
        CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
181 39347
        Lck_AssertHeld(&ban_mtx);
182
183 39347
        AN(b->spec);
184 39347
        if (!(b->flags & BANS_FLAG_COMPLETED)) {
185 39347
                ln = ban_len(b->spec);
186 39347
                b->flags |= BANS_FLAG_COMPLETED;
187 39347
                b->spec[BANS_FLAGS] |= BANS_FLAG_COMPLETED;
188 39347
                VWMB();
189 39347
                vbe32enc(b->spec + BANS_LENGTH, BANS_HEAD_LEN);
190 39347
                VSC_C_main->bans_completed++;
191 39347
                bans_persisted_fragmentation += ln - ban_len(b->spec);
192 39347
                VSC_C_main->bans_persisted_fragmentation =
193 39347
                    bans_persisted_fragmentation;
194 39347
        }
195 39347
}
196
197
/*--------------------------------------------------------------------
198
 * Access a lump of bytes in a ban test spec
199
 */
200
201
static const void *
202 16520
ban_get_lump(const uint8_t **bs)
203
{
204
        const void *r;
205
        unsigned ln;
206
207 101640
        while (**bs == 0xff)
208 85120
                *bs += 1;
209 16520
        ln = vbe32dec(*bs);
210 16520
        *bs += PRNDUP(sizeof(uint32_t));
211 16520
        assert(PAOK(*bs));
212 16520
        r = (const void*)*bs;
213 16520
        *bs += ln;
214 16520
        return (r);
215
}
216
217
/*--------------------------------------------------------------------
218
 * Pick a test apart from a spec string
219
 */
220
221
static void
222 14520
ban_iter(const uint8_t **bs, struct ban_test *bt)
223
{
224
        const void *lump;
225
        uint64_t dtmp;
226
227 14520
        memset(bt, 0, sizeof *bt);
228 14520
        bt->arg2_double = nan("");
229 14520
        bt->arg1 = *(*bs)++;
230 14520
        if (BANS_HAS_ARG1_SPEC(bt->arg1)) {
231 4080
                bt->arg1_spec = (const char *)*bs;
232 4080
                (*bs) += (*bs)[0] + 2;
233 4080
        }
234 14520
        lump = ban_get_lump(bs);
235 14520
        bt->oper = *(*bs)++;
236 14520
        if (BANS_HAS_ARG2_DOUBLE(bt->arg1)) {
237 6280
                dtmp = vbe64dec(lump);
238 6280
                memcpy(&bt->arg2_double, &dtmp, sizeof dtmp);
239 6280
                return;
240
        }
241 8240
        bt->arg2 = lump;
242 8240
        if (BANS_HAS_ARG2_SPEC(bt->oper))
243 2000
                bt->arg2_spec = ban_get_lump(bs);
244 14520
}
245
246
/*--------------------------------------------------------------------
247
 * A new object is created, grab a reference to the newest ban
248
 */
249
250
void
251 56759
BAN_NewObjCore(struct objcore *oc)
252
{
253
254 56759
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
255 56759
        AZ(oc->ban);
256 56759
        AN(oc->objhead);
257 56759
        Lck_Lock(&ban_mtx);
258 56759
        oc->ban = ban_start;
259 56759
        ban_start->refcount++;
260 56759
        VTAILQ_INSERT_TAIL(&ban_start->objcore, oc, ban_list);
261 56759
        Lck_Unlock(&ban_mtx);
262 56759
}
263
264
/*--------------------------------------------------------------------
265
 * An object is destroyed, release its ban reference
266
 */
267
268
void
269 74002
BAN_DestroyObj(struct objcore *oc)
270
{
271
272 74002
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
273 74002
        if (oc->ban == NULL)
274 59185
                return;
275 14817
        Lck_Lock(&ban_mtx);
276 14817
        CHECK_OBJ_ORNULL(oc->ban, BAN_MAGIC);
277 14817
        if (oc->ban != NULL) {
278 14817
                assert(oc->ban->refcount > 0);
279 14817
                oc->ban->refcount--;
280 14817
                VTAILQ_REMOVE(&oc->ban->objcore, oc, ban_list);
281 14817
                oc->ban = NULL;
282 14817
        }
283 14817
        Lck_Unlock(&ban_mtx);
284 74002
}
285
286
/*--------------------------------------------------------------------
287
 * Find a ban based on a timestamp.
288
 * Assume we have a BAN_Hold, so list traversal is safe.
289
 */
290
291
struct ban *
292 680
BAN_FindBan(vtim_real t0)
293
{
294
        struct ban *b;
295
        vtim_real t1;
296
297 680
        assert(ban_holds > 0);
298 680
        b = BANIDX_lookup(t0);
299 680
        VTAILQ_FOREACH_FROM(b, &ban_head, list) {
300 680
                t1 = ban_time(b->spec);
301 680
                if (t1 == t0)
302 680
                        return (b);
303 0
                if (t1 < t0)
304 0
                        break;
305 0
        }
306 0
        return (NULL);
307 680
}
308
309
/*--------------------------------------------------------------------
310
 * Grab a reference to a ban and associate the objcore with that ban.
311
 * Assume we have a BAN_Hold, so list traversal is safe.
312
 */
313
314
void
315 680
BAN_RefBan(struct objcore *oc, struct ban *b)
316
{
317
318 680
        Lck_Lock(&ban_mtx);
319 680
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
320 680
        AZ(oc->ban);
321 680
        CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
322 680
        assert(ban_holds > 0);
323 680
        b->refcount++;
324 680
        VTAILQ_INSERT_TAIL(&b->objcore, oc, ban_list);
325 680
        oc->ban = b;
326 680
        Lck_Unlock(&ban_mtx);
327 680
}
328
329
/*--------------------------------------------------------------------
330
 * Compile a full ban list and export this area to the stevedores for
331
 * persistence.
332
 */
333
334
static void
335 74187
ban_export(void)
336
{
337
        struct ban *b;
338
        struct vsb *vsb;
339
        unsigned ln;
340
341 74187
        Lck_AssertHeld(&ban_mtx);
342 74187
        ln = bans_persisted_bytes - bans_persisted_fragmentation;
343 74187
        vsb = VSB_new_auto();
344 74187
        AN(vsb);
345 151571
        VTAILQ_FOREACH_REVERSE(b, &ban_head, banhead_s, list)
346 77384
                AZ(VSB_bcat(vsb, b->spec, ban_len(b->spec)));
347 74187
        AZ(VSB_finish(vsb));
348 74187
        assert(VSB_len(vsb) == ln);
349 74187
        STV_BanExport((const uint8_t *)VSB_data(vsb), VSB_len(vsb));
350 74187
        VSB_destroy(&vsb);
351 74187
        VSC_C_main->bans_persisted_bytes =
352 74187
            bans_persisted_bytes = ln;
353 74187
        VSC_C_main->bans_persisted_fragmentation =
354 74187
            bans_persisted_fragmentation = 0;
355 74187
}
356
357
/*
358
 * For both of these we do a full export on info failure to remove
359
 * holes in the exported list.
360
 * XXX: we should keep track of the size of holes in the last exported list
361
 * XXX: check if the ban_export should be batched in ban_cleantail
362
 */
363
void
364 41307
ban_info_new(const uint8_t *ban, unsigned len)
365
{
366
        /* XXX martin pls review if ban_mtx needs to be held */
367 41307
        Lck_AssertHeld(&ban_mtx);
368 41307
        if (STV_BanInfoNew(ban, len))
369 0
                ban_export();
370 41307
}
371
372
void
373 2883
ban_info_drop(const uint8_t *ban, unsigned len)
374
{
375
        /* XXX martin pls review if ban_mtx needs to be held */
376 2883
        Lck_AssertHeld(&ban_mtx);
377 2883
        if (STV_BanInfoDrop(ban, len))
378 0
                ban_export();
379 2883
}
380
381
/*--------------------------------------------------------------------
382
 * Put a skeleton ban in the list, unless there is an identical,
383
 * time & condition, ban already in place.
384
 *
385
 * If a newer ban has same condition, mark the inserted ban COMPLETED,
386
 * also mark any older bans, with the same condition COMPLETED.
387
 */
388
389
static void
390 1360
ban_reload(const uint8_t *ban, unsigned len)
391
{
392
        struct ban *b, *b2;
393 1360
        int duplicate = 0;
394 1360
        vtim_real t0, t1, t2 = 9e99;
395 1360
        ASSERT_CLI();
396 1360
        Lck_AssertHeld(&ban_mtx);
397 1360
        assert(ban_holds > 0);
398
399 1360
        t0 = ban_time(ban);
400 1360
        assert(len == ban_len(ban));
401
402 1360
        b = BANIDX_lookup(t0);
403 2400
        VTAILQ_FOREACH_FROM(b, &ban_head, list) {
404 1760
                t1 = ban_time(b->spec);
405 1760
                assert(t1 < t2);
406 1760
                t2 = t1;
407 1760
                if (t1 == t0)
408 320
                        return;
409 1440
                if (t1 < t0)
410 400
                        break;
411 1040
                if (ban_equal(b->spec, ban))
412 720
                        duplicate = 1;
413 1040
        }
414
415 1040
        VSC_C_main->bans++;
416 1040
        VSC_C_main->bans_added++;
417
418 1040
        b2 = ban_alloc();
419 1040
        AN(b2);
420 1040
        b2->spec = malloc(len);
421 1040
        AN(b2->spec);
422 1040
        memcpy(b2->spec, ban, len);
423 1040
        if (ban[BANS_FLAGS] & BANS_FLAG_REQ) {
424 200
                VSC_C_main->bans_req++;
425 200
                b2->flags |= BANS_FLAG_REQ;
426 200
        }
427 1040
        if (duplicate)
428 720
                VSC_C_main->bans_dups++;
429 1040
        if (duplicate || (ban[BANS_FLAGS] & BANS_FLAG_COMPLETED))
430 760
                ban_mark_completed(b2);
431 1040
        if (b == NULL)
432 640
                VTAILQ_INSERT_TAIL(&ban_head, b2, list);
433
        else
434 400
                VTAILQ_INSERT_BEFORE(b, b2, list);
435 1040
        bans_persisted_bytes += len;
436 1040
        VSC_C_main->bans_persisted_bytes = bans_persisted_bytes;
437
438
        /* Hunt down older duplicates */
439 1640
        for (b = VTAILQ_NEXT(b2, list); b != NULL; b = VTAILQ_NEXT(b, list)) {
440 600
                if (b->flags & BANS_FLAG_COMPLETED)
441 560
                        continue;
442 40
                if (ban_equal(b->spec, ban)) {
443 0
                        ban_mark_completed(b);
444 0
                        VSC_C_main->bans_dups++;
445 0
                }
446 40
        }
447 1360
}
448
449
/*--------------------------------------------------------------------
450
 * Reload a series of persisted ban specs
451
 */
452
453
void
454 1520
BAN_Reload(const uint8_t *ptr, unsigned len)
455
{
456
        const uint8_t *pe;
457
        unsigned l;
458
459 1520
        AZ(ban_shutdown);
460 1520
        pe = ptr + len;
461 1520
        Lck_Lock(&ban_mtx);
462 2880
        while (ptr < pe) {
463
                /* XXX: This can be optimized by traversing the live
464
                 * ban list together with the reload list (combining
465
                 * the loops in BAN_Reload and ban_reload). */
466 1360
                l = ban_len(ptr);
467 1360
                assert(ptr + l <= pe);
468 1360
                ban_reload(ptr, l);
469 1360
                ptr += l;
470
        }
471 1520
        Lck_Unlock(&ban_mtx);
472 1520
}
473
474
/*--------------------------------------------------------------------
475
 * Get a bans timestamp
476
 */
477
478
vtim_real
479 2800
BAN_Time(const struct ban *b)
480
{
481
482 2800
        if (b == NULL)
483 880
                return (0.0);
484
485 1920
        CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
486 1920
        return (ban_time(b->spec));
487 2800
}
488
489
/*--------------------------------------------------------------------
490
 * Evaluate ban-spec
491
 */
492
493
int
494 3600
ban_evaluate(struct worker *wrk, const uint8_t *bsarg, struct objcore *oc,
495
    const struct http *reqhttp, unsigned *tests)
496
{
497
        struct ban_test bt;
498
        const uint8_t *bs, *be;
499
        const char *p;
500
        const char *arg1;
501
        double darg1, darg2;
502
        hdr_t hdr;
503
        int rv;
504
505
        /*
506
         * for ttl, age and last_hit, fix the point in time such that banning
507
         * refers to the same point in time when the ban is evaluated
508
         *
509
         * for grace/keep, we assume that the absolute values are pola and that
510
         * users will most likely also specify a ttl criterion if they want to
511
         * fix a point in time (such as "obj.ttl > 5h && obj.keep > 3h")
512
         */
513
514 3600
        bs = bsarg;
515 3600
        be = bs + ban_len(bs);
516 3600
        bs += BANS_HEAD_LEN;
517 6000
        while (bs < be) {
518 4160
                (*tests)++;
519 4160
                ban_iter(&bs, &bt);
520 4160
                arg1 = NULL;
521 4160
                darg1 = darg2 = nan("");
522 4160
                switch (bt.arg1) {
523
                case BANS_ARG_URL:
524 1080
                        AN(reqhttp);
525 1080
                        arg1 = reqhttp->hd[HTTP_HDR_URL].b;
526 1080
                        break;
527
                case BANS_ARG_REQHTTP:
528 360
                        AN(reqhttp);
529 360
                        CAST_HDR(hdr, bt.arg1_spec);
530 360
                        (void)http_GetHdr(reqhttp, hdr, &p);
531 360
                        arg1 = p;
532 360
                        break;
533
                case BANS_ARG_OBJHTTP:
534 1280
                        CAST_HDR(hdr, bt.arg1_spec);
535 1280
                        arg1 = HTTP_GetHdrPack(wrk, oc, hdr);
536 1280
                        break;
537
                case BANS_ARG_OBJSTATUS:
538 560
                        arg1 = HTTP_GetHdrPack(wrk, oc, H__Status);
539 560
                        break;
540
                case BANS_ARG_OBJTTL:
541 200
                        darg1 = oc->ttl + oc->t_origin;
542 200
                        darg2 = bt.arg2_double + ban_time(bsarg);
543 200
                        break;
544
                case BANS_ARG_OBJAGE:
545 200
                        darg1 = 0.0 - oc->t_origin;
546 200
                        darg2 = 0.0 - (ban_time(bsarg) - bt.arg2_double);
547 200
                        break;
548
                case BANS_ARG_OBJGRACE:
549 120
                        darg1 = oc->grace;
550 120
                        darg2 = bt.arg2_double;
551 120
                        break;
552
                case BANS_ARG_OBJKEEP:
553 280
                        darg1 = oc->keep;
554 280
                        darg2 = bt.arg2_double;
555 280
                        break;
556
                case BANS_ARG_OBJLASTHIT:
557 80
                        if (isnan(oc->last_lru))
558 0
                                return (0);
559 80
                        darg1 = 0.0 - oc->last_lru;
560 80
                        darg2 = 0.0 - (ban_time(bsarg) - bt.arg2_double);
561 80
                        break;
562
                default:
563 0
                        WRONG("Wrong BAN_ARG code");
564 0
                }
565
566 4160
                switch (bt.oper) {
567
                case BANS_OPER_EQ:
568 2240
                        if (arg1 == NULL) {
569 440
                                if (isnan(darg1) || darg1 != darg2)
570 200
                                        return (0);
571 2040
                        } else if (strcmp(arg1, bt.arg2)) {
572 840
                                return (0);
573
                        }
574 1200
                        break;
575
                case BANS_OPER_NEQ:
576 480
                        if (arg1 == NULL) {
577 280
                                if (! isnan(darg1) && darg1 == darg2)
578 160
                                        return (0);
579 320
                        } else if (!strcmp(arg1, bt.arg2)) {
580 80
                                return (0);
581
                        }
582 240
                        break;
583
                case BANS_OPER_MATCH:
584 960
                        if (arg1 == NULL)
585 40
                                return (0);
586 920
                        rv = VRE_match(bt.arg2_spec, arg1, 0, 0, NULL);
587 920
                        xxxassert(rv >= -1);
588 920
                        if (rv < 0)
589 80
                                return (0);
590 840
                        break;
591
                case BANS_OPER_NMATCH:
592 0
                        if (arg1 == NULL)
593 0
                                return (0);
594 0
                        rv = VRE_match(bt.arg2_spec, arg1, 0, 0, NULL);
595 0
                        xxxassert(rv >= -1);
596 0
                        if (rv >= 0)
597 0
                                return (0);
598 0
                        break;
599
                case BANS_OPER_GT:
600 320
                        AZ(arg1);
601 320
                        assert(! isnan(darg1));
602 320
                        if (!(darg1 > darg2))
603 320
                                return (0);
604 0
                        break;
605
                case BANS_OPER_GTE:
606 0
                        AZ(arg1);
607 0
                        assert(! isnan(darg1));
608 0
                        if (!(darg1 >= darg2))
609 0
                                return (0);
610 0
                        break;
611
                case BANS_OPER_LT:
612 120
                        AZ(arg1);
613 120
                        assert(! isnan(darg1));
614 120
                        if (!(darg1 < darg2))
615 40
                                return (0);
616 80
                        break;
617
                case BANS_OPER_LTE:
618 40
                        AZ(arg1);
619 40
                        assert(! isnan(darg1));
620 40
                        if (!(darg1 <= darg2))
621 0
                                return (0);
622 40
                        break;
623
                default:
624 0
                        WRONG("Wrong BAN_OPER code");
625 0
                }
626
        }
627 1840
        return (1);
628 3600
}
629
630
/*--------------------------------------------------------------------
631
 * Check an object against all applicable bans
632
 *
633
 * Return:
634
 *      -1 not all bans checked, but none of the checked matched
635
 *              Only if !has_req
636
 *      0 No bans matched, object moved to ban_start.
637
 *      1 Ban matched, object removed from ban list.
638
 */
639
640
int
641 154424
BAN_CheckObject(struct worker *wrk, struct objcore *oc, struct req *req)
642
{
643
        struct ban *b;
644
        struct vsl_log *vsl;
645
        struct ban *b0, *bn;
646
        unsigned tests;
647
648 154424
        CHECK_OBJ_NOTNULL(wrk, WORKER_MAGIC);
649 154424
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
650 154424
        CHECK_OBJ_NOTNULL(req, REQ_MAGIC);
651 154424
        Lck_AssertHeld(&oc->objhead->mtx);
652 154424
        assert(oc->refcnt > 0);
653
654 154424
        vsl = req->vsl;
655
656 154424
        CHECK_OBJ_NOTNULL(oc->ban, BAN_MAGIC);
657
658
        /* First do an optimistic unlocked check */
659 154424
        b0 = ban_start;
660 154424
        CHECK_OBJ_NOTNULL(b0, BAN_MAGIC);
661
662 154424
        if (b0 == oc->ban)
663 151984
                return (0);
664
665
        /* If that fails, make a safe check */
666 2440
        Lck_Lock(&ban_mtx);
667 2440
        b0 = ban_start;
668 2440
        bn = oc->ban;
669 2440
        if (b0 != bn)
670 2440
                bn->refcount++;
671 2440
        Lck_Unlock(&ban_mtx);
672
673 2440
        AN(bn);
674
675 2440
        if (b0 == bn)
676 0
                return (0);
677
678 2440
        AN(b0);
679 2440
        AN(bn);
680
681
        /*
682
         * This loop is safe without locks, because we know we hold
683
         * a refcount on a ban somewhere in the list and we do not
684
         * inspect the list past that ban.
685
         */
686 2440
        tests = 0;
687 4160
        for (b = b0; b != bn; b = VTAILQ_NEXT(b, list)) {
688 3080
                CHECK_OBJ_NOTNULL(b, BAN_MAGIC);
689 3080
                if (b->flags & BANS_FLAG_COMPLETED)
690 800
                        continue;
691 2280
                if (ban_evaluate(wrk, b->spec, oc, req->http, &tests))
692 1360
                        break;
693 920
        }
694
695 2440
        Lck_Lock(&ban_mtx);
696 2440
        bn->refcount--;
697 2440
        VSC_C_main->bans_tested++;
698 2440
        VSC_C_main->bans_tests_tested += tests;
699
700 2440
        if (b == bn) {
701
                /* not banned */
702 1080
                oc->ban->refcount--;
703 1080
                VTAILQ_REMOVE(&oc->ban->objcore, oc, ban_list);
704 1080
                VTAILQ_INSERT_TAIL(&b0->objcore, oc, ban_list);
705 1080
                b0->refcount++;
706 1080
                oc->ban = b0;
707 1080
                b = NULL;
708 1080
        }
709 2440
        if (b != NULL)
710 1360
                VSC_C_main->bans_obj_killed++;
711
712 2440
        if (VTAILQ_LAST(&ban_head, banhead_s)->refcount == 0)
713 880
                ban_kick_lurker();
714
715 2440
        Lck_Unlock(&ban_mtx);
716
717 2440
        if (b == NULL) {
718
                /* not banned */
719 1080
                ObjSendEvent(wrk, oc, OEV_BANCHG);
720 1080
                return (0);
721
        } else {
722 2720
                VSLb(vsl, SLT_ExpBan,
723 1360
                    "%ju banned lookup", VXID(ObjGetXID(wrk, oc)));
724 1360
                return (1);
725
        }
726 154424
}
727
728
/*--------------------------------------------------------------------
729
 * CLI functions to add bans
730
 */
731
732
static void v_matchproto_(cli_func_t)
733 3680
ccf_ban(struct cli *cli, const char * const *av, void *priv)
734
{
735
        int narg, i;
736
        struct ban_proto *bp;
737 3680
        const char *err = NULL;
738
739 3680
        (void)priv;
740
741
        /* First do some cheap checks on the arguments */
742 16520
        for (narg = 0; av[narg + 2] != NULL; narg++)
743 12840
                continue;
744 3680
        if ((narg % 4) != 3) {
745 80
                VCLI_Out(cli, "Wrong number of arguments");
746 80
                VCLI_SetResult(cli, CLIS_PARAM);
747 80
                return;
748
        }
749 3960
        for (i = 3; i < narg; i += 4) {
750 400
                if (strcmp(av[i + 2], "&&")) {
751 40
                        VCLI_Out(cli, "Found \"%s\" expected &&", av[i + 2]);
752 40
                        VCLI_SetResult(cli, CLIS_PARAM);
753 40
                        return;
754
                }
755 360
        }
756
757 3560
        bp = BAN_Build();
758 3560
        if (bp == NULL) {
759 0
                VCLI_Out(cli, "Out of Memory");
760 0
                VCLI_SetResult(cli, CLIS_CANT);
761 0
                return;
762
        }
763 7200
        for (i = 0; i < narg; i += 4) {
764 3920
                err = BAN_AddTest(bp, av[i + 2], av[i + 3], av[i + 4]);
765 3920
                if (err)
766 280
                        break;
767 3640
        }
768
769 3560
        if (err == NULL) {
770
                // XXX racy - grab wstat lock?
771 3280
                err = BAN_Commit(bp);
772 3280
        }
773
774 3560
        if (err != NULL) {
775 280
                VCLI_Out(cli, "%s", err);
776 280
                BAN_Abandon(bp);
777 280
                VCLI_SetResult(cli, CLIS_PARAM);
778 280
        }
779 3680
}
780
781
#define Ms 60
782
#define Hs (Ms * 60)
783
#define Ds (Hs * 24)
784
#define Ws (Ds * 7)
785
#define Ys (Ds * 365)
786
787
#define Xfmt(buf, var, s, unit)                                         \
788
        ((var) >= s && (var) % s == 0)                                  \
789
                bprintf((buf), "%ju" unit, (var) / s)
790
791
// XXX move to VTIM?
792
#define vdur_render(buf, dur) do {                                      \
793
        uintmax_t dec = (uintmax_t)floor(dur);                          \
794
        uintmax_t frac = (uintmax_t)floor((dur) * 1e3) % UINTMAX_C(1000); \
795
        if (dec == 0 && frac == 0)                                      \
796
                (void) strncpy(buf, "0s", sizeof(buf));                 \
797
        else if (dec == 0)                                              \
798
                bprintf((buf), "%jums", frac);                          \
799
        else if (frac != 0)                                             \
800
                bprintf((buf), "%ju.%03jus", dec, frac);                \
801
        else if Xfmt(buf, dec, Ys, "y");                                \
802
        else if Xfmt(buf, dec, Ws, "w");                                \
803
        else if Xfmt(buf, dec, Ds, "d");                                \
804
        else if Xfmt(buf, dec, Hs, "h");                                \
805
        else if Xfmt(buf, dec, Ms, "m");                                \
806
        else                                                            \
807
                bprintf((buf), "%jus", dec);                            \
808
        } while (0)
809
810
static void
811 12960
ban_render(struct cli *cli, const uint8_t *bs, int quote)
812
{
813
        struct ban_test bt;
814
        const uint8_t *be;
815
        char buf[64];
816
817 12960
        be = bs + ban_len(bs);
818 12960
        bs += BANS_HEAD_LEN;
819 23320
        while (bs < be) {
820 10360
                ban_iter(&bs, &bt);
821 10360
                ASSERT_BAN_ARG(bt.arg1);
822 10360
                ASSERT_BAN_OPER(bt.oper);
823
824 10360
                if (BANS_HAS_ARG1_SPEC(bt.arg1))
825 4880
                        VCLI_Out(cli, "%s%.*s",
826 2440
                            arg_name[BAN_ARGIDX(bt.arg1)],
827 2440
                            bt.arg1_spec[0] - 1, bt.arg1_spec + 1);
828
                else
829 7920
                        VCLI_Out(cli, "%s", arg_name[BAN_ARGIDX(bt.arg1)]);
830
831 10360
                VCLI_Out(cli, " %s ", ban_oper[BAN_OPERIDX(bt.oper)]);
832
833 10360
                if (BANS_HAS_ARG2_DOUBLE(bt.arg1)) {
834 10440
                        vdur_render(buf, bt.arg2_double);
835 5400
                        VCLI_Out(cli, "%s", buf);
836 10360
                } else if (quote) {
837 520
                        VCLI_Quote(cli, bt.arg2);
838 520
                } else {
839 4440
                        VCLI_Out(cli, "%s", bt.arg2);
840
                }
841
842 10360
                if (bs < be)
843 1000
                        VCLI_Out(cli, " && ");
844
        }
845 12960
}
846
847
static void
848 2920
ban_list(struct cli *cli, struct ban *bl)
849
{
850
        struct ban *b;
851
        int64_t o;
852
853 2920
        VCLI_Out(cli, "Present bans:\n");
854 14880
        VTAILQ_FOREACH(b, &ban_head, list) {
855 11960
                o = bl == b ? 1 : 0;
856 23920
                VCLI_Out(cli, "%10.6f %5ju %s", ban_time(b->spec),
857 11960
                    (intmax_t)(b->refcount - o),
858 11960
                    b->flags & BANS_FLAG_COMPLETED ? "C" : "-");
859 11960
                if (DO_DEBUG(DBG_LURKER)) {
860 3760
                        VCLI_Out(cli, "%s%s %p ",
861 1880
                            b->flags & BANS_FLAG_REQ ? "R" : "-",
862 1880
                            b->flags & BANS_FLAG_OBJ ? "O" : "-",
863 1880
                            b);
864 1880
                }
865 11960
                VCLI_Out(cli, "  ");
866 11960
                ban_render(cli, b->spec, 0);
867 11960
                VCLI_Out(cli, "\n");
868 11960
                if (VCLI_Overflow(cli))
869 0
                        break;
870 11960
                if (DO_DEBUG(DBG_LURKER)) {
871 1880
                        Lck_Lock(&ban_mtx);
872
                        struct objcore *oc;
873 3160
                        VTAILQ_FOREACH(oc, &b->objcore, ban_list)
874 1280
                                VCLI_Out(cli, "  oc = %p\n", oc);
875 1880
                        Lck_Unlock(&ban_mtx);
876 1880
                }
877 11960
        }
878 2920
}
879
880
static void
881 240
ban_list_json(struct cli *cli, const char * const *av, struct ban *bl)
882
{
883
        struct ban *b;
884
        int64_t o;
885 240
        int n = 0;
886
        int ocs;
887
888 240
        VCLI_JSON_begin(cli, 2, av);
889 240
        VCLI_Out(cli, ",\n");
890 1240
        VTAILQ_FOREACH(b, &ban_head, list) {
891 1000
                o = bl == b ? 1 : 0;
892 1000
                VCLI_Out(cli, "%s", n ? ",\n" : "");
893 1000
                n++;
894 1000
                VCLI_Out(cli, "{\n");
895 1000
                VSB_indent(cli->sb, 2);
896 1000
                VCLI_Out(cli, "\"time\": %.6f,\n", ban_time(b->spec));
897 1000
                VCLI_Out(cli, "\"refs\": %ju,\n", (intmax_t)(b->refcount - o));
898 2000
                VCLI_Out(cli, "\"completed\": %s,\n",
899 1000
                         b->flags & BANS_FLAG_COMPLETED ? "true" : "false");
900 1000
                VCLI_Out(cli, "\"spec\": \"");
901 1000
                ban_render(cli, b->spec, 1);
902 1000
                VCLI_Out(cli, "\"");
903
904 1000
                if (DO_DEBUG(DBG_LURKER)) {
905 240
                        VCLI_Out(cli, ",\n");
906 480
                        VCLI_Out(cli, "\"req_tests\": %s,\n",
907 240
                                 b->flags & BANS_FLAG_REQ ? "true" : "false");
908 480
                        VCLI_Out(cli, "\"obj_tests\": %s,\n",
909 240
                                 b->flags & BANS_FLAG_OBJ ? "true" : "false");
910 240
                        VCLI_Out(cli, "\"pointer\": \"%p\",\n", b);
911 240
                        if (VCLI_Overflow(cli))
912 0
                                break;
913
914 240
                        ocs = 0;
915 240
                        VCLI_Out(cli, "\"objcores\": [\n");
916 240
                        VSB_indent(cli->sb, 2);
917 240
                        Lck_Lock(&ban_mtx);
918
                        struct objcore *oc;
919 240
                        VTAILQ_FOREACH(oc, &b->objcore, ban_list) {
920 0
                                if (ocs)
921 0
                                        VCLI_Out(cli, ",\n");
922 0
                                VCLI_Out(cli, "%p", oc);
923 0
                                ocs++;
924 0
                        }
925 240
                        Lck_Unlock(&ban_mtx);
926 240
                        VSB_indent(cli->sb, -2);
927 240
                        VCLI_Out(cli, "\n]");
928 240
                }
929 1000
                VSB_indent(cli->sb, -2);
930 1000
                VCLI_Out(cli, "\n}");
931 1000
        }
932 240
        VCLI_JSON_end(cli);
933 240
}
934
935
static void v_matchproto_(cli_func_t)
936 3160
ccf_ban_list(struct cli *cli, const char * const *av, void *priv)
937
{
938
        struct ban *bl;
939
940 3160
        (void)priv;
941
942
        /* Get a reference so we are safe to traverse the list */
943 3160
        Lck_Lock(&ban_mtx);
944 3160
        bl = VTAILQ_LAST(&ban_head, banhead_s);
945 3160
        bl->refcount++;
946 3160
        Lck_Unlock(&ban_mtx);
947
948 3160
        if (av[2] != NULL && strcmp(av[2], "-j") == 0)
949 240
                ban_list_json(cli, av, bl);
950
        else
951 2920
                ban_list(cli, bl);
952
953 3160
        Lck_Lock(&ban_mtx);
954 3160
        bl->refcount--;
955 3160
        ban_kick_lurker();      // XXX: Mostly for testcase b00009.vtc
956 3160
        Lck_Unlock(&ban_mtx);
957 3160
}
958
959
static struct cli_proto ban_cmds[] = {
960
        { CLICMD_BAN,                           "", ccf_ban },
961
        { CLICMD_BAN_LIST,                      "", ccf_ban_list,
962
          ccf_ban_list },
963
        { NULL }
964
};
965
966
/*--------------------------------------------------------------------
967
 */
968
969
void
970 37307
BAN_Compile(void)
971
{
972
        struct ban *b;
973
974
        /*
975
         * All bans have been read from all persistent stevedores. Export
976
         * the compiled list
977
         */
978
979 37307
        ASSERT_CLI();
980 37307
        AZ(ban_shutdown);
981
982 37307
        Lck_Lock(&ban_mtx);
983
984
        /* Report the place-holder ban */
985 37307
        b = VTAILQ_FIRST(&ban_head);
986 37307
        ban_info_new(b->spec, ban_len(b->spec));
987
988 37307
        ban_export();
989
990 37307
        Lck_Unlock(&ban_mtx);
991
992 37307
        ban_start = VTAILQ_FIRST(&ban_head);
993 37307
        BAN_Release();
994 37307
}
995
996
void
997 37387
BAN_Init(void)
998
{
999
        struct ban_proto *bp;
1000
1001 37387
        BAN_Build_Init();
1002 37387
        Lck_New(&ban_mtx, lck_ban);
1003 37387
        CLI_AddFuncs(ban_cmds);
1004
1005 37387
        ban_holds = 1;
1006
1007
        /* Add a placeholder ban */
1008 37387
        bp = BAN_Build();
1009 37387
        AN(bp);
1010 37387
        PTOK(pthread_cond_init(&ban_lurker_cond, NULL));
1011 37387
        AZ(BAN_Commit(bp));
1012 37387
        Lck_Lock(&ban_mtx);
1013 37387
        ban_mark_completed(VTAILQ_FIRST(&ban_head));
1014 37387
        Lck_Unlock(&ban_mtx);
1015 37387
}
1016
1017
/*--------------------------------------------------------------------
1018
 * Shutdown of the ban system.
1019
 *
1020
 * When this function returns, no new bans will be accepted, and no
1021
 * bans will be dropped (ban lurker thread stopped), so that no
1022
 * STV_BanInfo calls will be executed.
1023
 */
1024
1025
void
1026 36880
BAN_Shutdown(void)
1027
{
1028
        void *status;
1029
1030 36880
        Lck_Lock(&ban_mtx);
1031 36880
        ban_shutdown = 1;
1032 36880
        ban_kick_lurker();
1033 36880
        Lck_Unlock(&ban_mtx);
1034
1035 36880
        PTOK(pthread_join(ban_thread, &status));
1036 36880
        AZ(status);
1037
1038 36880
        Lck_Lock(&ban_mtx);
1039
        /* Export the ban list to compact it */
1040 36880
        ban_export();
1041 36880
        Lck_Unlock(&ban_mtx);
1042
1043 36880
        BAN_Build_Fini();
1044 36880
}