varnish-cache/bin/varnishd/cache/cache_ban_build.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
36
#include "cache_varnishd.h"
37
#include "cache_ban.h"
38
39
#include "vend.h"
40
#include "vtim.h"
41
#include "vnum.h"
42
43
void BAN_Build_Init(void);
44
void BAN_Build_Fini(void);
45
46
struct ban_proto {
47
        unsigned                magic;
48
#define BAN_PROTO_MAGIC         0xd8adc494
49
        unsigned                flags;          /* BANS_FLAG_* */
50
51
        struct vsb              *vsb;
52
        char                    *err;
53
};
54
55
/*--------------------------------------------------------------------
56
 * Variables we can ban on
57
 */
58
59
static const struct pvar {
60
        const char              *name;
61
        unsigned                flag;
62
        uint8_t                 tag;
63
} pvars[] = {
64
#define PVAR(a, b, c)   { (a), (b), (c) },
65
#include "tbl/ban_vars.h"
66
        { 0, 0, 0}
67
};
68
69
/* operators allowed per argument (pvar.tag) */
70
static const unsigned arg_opervalid[BAN_ARGARRSZ + 1] = {
71
#define ARGOPER(arg, mask) [BAN_ARGIDX(arg)] = (mask),
72
#include "tbl/ban_arg_oper.h"
73
        [BAN_ARGARRSZ] = 0
74
};
75
76
// init'ed in _Init
77
static const char *arg_operhelp[BAN_ARGARRSZ + 1];
78
79
// operators
80
const char * const ban_oper[BAN_OPERARRSZ + 1] = {
81
#define OPER(op, str) [BAN_OPERIDX(op)] = (str),
82
#include "tbl/ban_oper.h"
83
        [BAN_OPERARRSZ] = NULL
84
};
85
86
87
/*--------------------------------------------------------------------
88
 */
89
90
static char ban_build_err_no_mem[] = "No Memory";
91
92
/*--------------------------------------------------------------------
93
 */
94
95
struct ban_proto *
96 25219
BAN_Build(void)
97
{
98
        struct ban_proto *bp;
99
100 25219
        ALLOC_OBJ(bp, BAN_PROTO_MAGIC);
101 25219
        if (bp == NULL)
102 0
                return (bp);
103 25219
        bp->vsb = VSB_new_auto();
104 25219
        if (bp->vsb == NULL) {
105 0
                FREE_OBJ(bp);
106 0
                return (NULL);
107
        }
108 25219
        return (bp);
109 25219
}
110
111
// TODO: change to (struct ban_proto **)
112
void
113 25219
BAN_Abandon(struct ban_proto *bp)
114
{
115
116 25219
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
117 25219
        VSB_destroy(&bp->vsb);
118 25219
        FREE_OBJ(bp);
119 25219
}
120
121
/*--------------------------------------------------------------------
122
 */
123
124
static void
125 3425
ban_add_lump(const struct ban_proto *bp, const void *p, uint32_t len)
126
{
127 3425
        uint8_t buf[PRNDUP(sizeof len)] = { 0xff };
128
129 20050
        while (VSB_len(bp->vsb) & PALGN)
130 16625
                VSB_putc(bp->vsb, buf[0]);
131 3425
        vbe32enc(buf, len);
132 3425
        VSB_bcat(bp->vsb, buf, sizeof buf);
133 3425
        VSB_bcat(bp->vsb, p, len);
134 3425
}
135
136
/*--------------------------------------------------------------------
137
 */
138
139
static const char *
140 450
ban_error(struct ban_proto *bp, const char *fmt, ...)
141
{
142
        va_list ap;
143
144 450
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
145 450
        AN(bp->vsb);
146
147
        /* First error is sticky */
148 450
        if (bp->err == NULL) {
149 450
                if (fmt == ban_build_err_no_mem) {
150 0
                        bp->err = ban_build_err_no_mem;
151 0
                } else {
152
                        /* Record the error message in the vsb */
153 450
                        VSB_clear(bp->vsb);
154 450
                        va_start(ap, fmt);
155 450
                        VSB_vprintf(bp->vsb, fmt, ap);
156 450
                        va_end(ap);
157 450
                        AZ(VSB_finish(bp->vsb));
158 450
                        bp->err = VSB_data(bp->vsb);
159
                }
160 450
        }
161 450
        return (bp->err);
162
}
163
164
/*--------------------------------------------------------------------
165
 * Parse and add a http argument specification
166
 * Output something which HTTP_GetHdr understands
167
 */
168
169
static void
170 1100
ban_parse_http(const struct ban_proto *bp, const char *a1)
171
{
172
        int l;
173
174 1100
        l = strlen(a1) + 1;
175 1100
        assert(l <= 127);
176 1100
        VSB_putc(bp->vsb, (char)l);
177 1100
        VSB_cat(bp->vsb, a1);
178 1100
        VSB_putc(bp->vsb, ':');
179 1100
        VSB_putc(bp->vsb, '\0');
180 1100
}
181
182
/*--------------------------------------------------------------------
183
 * Parse and add a ban test specification
184
 */
185
186
static const char *
187 750
ban_parse_regexp(struct ban_proto *bp, const char *a3)
188
{
189
        struct vsb vsb[1];
190
        char errbuf[VRE_ERROR_LEN];
191
        int errorcode, erroroffset;
192
        size_t sz;
193
        vre_t *re, *rex;
194
195 750
        re = VRE_compile(a3, 0, &errorcode, &erroroffset, 0);
196 750
        if (re == NULL) {
197 25
                AN(VSB_init(vsb, errbuf, sizeof errbuf));
198 25
                AZ(VRE_error(vsb, errorcode));
199 25
                AZ(VSB_finish(vsb));
200 25
                VSB_fini(vsb);
201 25
                return (ban_error(bp, "Regex compile error: %s", errbuf));
202
        }
203
204 725
        rex = VRE_export(re, &sz);
205 725
        AN(rex);
206 725
        ban_add_lump(bp, rex, sz);
207 725
        VRE_free(&rex);
208 725
        VRE_free(&re);
209 725
        return (0);
210 750
}
211
212
static int
213 2900
ban_parse_oper(const char *p)
214
{
215
        int i;
216
217 6400
        for (i = 0; i < BAN_OPERARRSZ; i++) {
218 6300
                if (!strcmp(p, ban_oper[i]))
219 2800
                        return (BANS_OPER_OFF_ + i);
220 3500
        }
221 100
        return (-1);
222 2900
}
223
224
/*--------------------------------------------------------------------
225
 * Add a (and'ed) test-condition to a ban
226
 */
227
228
const char *
229 3125
BAN_AddTest(struct ban_proto *bp,
230
    const char *a1, const char *a2, const char *a3)
231
{
232
        const struct pvar *pv;
233
        double darg;
234
        uint64_t dtmp;
235
        uint8_t denc[sizeof darg];
236
        int op;
237
238 3125
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
239 3125
        AN(bp->vsb);
240 3125
        AN(a1);
241 3125
        AN(a2);
242 3125
        AN(a3);
243
244 3125
        if (bp->err != NULL)
245 0
                return (bp->err);
246
247 12475
        for (pv = pvars; pv->name != NULL; pv++) {
248 12275
                if (!(pv->flag & BANS_FLAG_HTTP) && !strcmp(a1, pv->name))
249 1800
                        break;
250 10475
                if ((pv->flag & BANS_FLAG_HTTP) && !strncmp(a1, pv->name, strlen(pv->name)))
251 1125
                        break;
252 9350
        }
253
254 3125
        if (pv->name == NULL)
255 400
                return (ban_error(bp,
256 200
                    "Unknown or unsupported field \"%s\"", a1));
257
258 2925
        bp->flags |= pv->flag;
259
260 2925
        VSB_putc(bp->vsb, pv->tag);
261 2925
        if (pv->flag & BANS_FLAG_HTTP) {
262 1125
                if (strlen(a1 + strlen(pv->name)) < 1)
263 50
                        return (ban_error(bp,
264 25
                            "Missing header name: \"%s\"", pv->name));
265 1100
                assert(BANS_HAS_ARG1_SPEC(pv->tag));
266 1100
                ban_parse_http(bp, a1 + strlen(pv->name));
267 1100
        }
268
269 2900
        op = ban_parse_oper(a2);
270 2900
        if (op < BANS_OPER_OFF_ ||
271 2800
            ((1U << BAN_OPERIDX(op)) & arg_opervalid[BAN_ARGIDX(pv->tag)]) == 0)
272 300
                return (ban_error(bp,
273
                    "expected conditional (%s) got \"%s\"",
274 150
                    arg_operhelp[BAN_ARGIDX(pv->tag)], a2));
275
276 2750
        if ((pv->flag & BANS_FLAG_DURATION) == 0) {
277 2025
                assert(! BANS_HAS_ARG2_DOUBLE(pv->tag));
278
279 2025
                ban_add_lump(bp, a3, strlen(a3) + 1);
280 2025
                VSB_putc(bp->vsb, op);
281
282 2025
                if (! BANS_HAS_ARG2_SPEC(op))
283 1275
                        return (NULL);
284
285 750
                return (ban_parse_regexp(bp, a3));
286
        }
287
288 725
        assert(pv->flag & BANS_FLAG_DURATION);
289 725
        assert(BANS_HAS_ARG2_DOUBLE(pv->tag));
290 725
        darg = VNUM_duration(a3);
291 725
        if (isnan(darg)) {
292 100
                return (ban_error(bp,
293 50
                    "expected duration <n.nn>[ms|s|m|h|d|w|y] got \"%s\"", a3));
294
        }
295
296 675
        assert(sizeof darg == sizeof dtmp);
297 675
        assert(sizeof dtmp == sizeof denc);
298 675
        memcpy(&dtmp, &darg, sizeof dtmp);
299 675
        vbe64enc(denc, dtmp);
300
301 675
        ban_add_lump(bp, denc, sizeof denc);
302 675
        VSB_putc(bp->vsb, op);
303 675
        return (NULL);
304 3125
}
305
306
/*--------------------------------------------------------------------
307
 * We maintain ban_start as a pointer to the first element of the list
308
 * as a separate variable from the VTAILQ, to avoid depending on the
309
 * internals of the VTAILQ macros.  We tacitly assume that a pointer
310
 * write is always atomic in doing so.
311
 *
312
 * Returns:
313
 *   0: Ban successfully inserted
314
 *  -1: Ban not inserted due to shutdown in progress. The ban has been
315
 *      deleted.
316
 */
317
318
const char *
319 24569
BAN_Commit(struct ban_proto *bp)
320
{
321
        struct ban  *b, *bi;
322
        ssize_t ln;
323
        vtim_real t0;
324
        uint64_t u;
325
326 24569
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
327 24569
        AN(bp->vsb);
328 24569
        assert(sizeof u == sizeof t0);
329
330 24569
        if (ban_shutdown)
331 0
                return (ban_error(bp, "Shutting down"));
332
333 24569
        AZ(VSB_finish(bp->vsb));
334 24569
        ln = VSB_len(bp->vsb);
335 24569
        assert(ln >= 0);
336
337 24569
        ALLOC_OBJ(b, BAN_MAGIC);
338 24569
        if (b == NULL)
339 0
                return (ban_error(bp, ban_build_err_no_mem));
340 24569
        VTAILQ_INIT(&b->objcore);
341
342 24569
        b->spec = malloc(ln + BANS_HEAD_LEN);
343 24569
        if (b->spec == NULL) {
344 0
                free(b);
345 0
                return (ban_error(bp, ban_build_err_no_mem));
346
        }
347
348 24569
        b->flags = bp->flags;
349
350 24569
        memset(b->spec, 0, BANS_HEAD_LEN);
351 24569
        t0 = VTIM_real();
352 24569
        memcpy(&u, &t0, sizeof u);
353 24569
        vbe64enc(b->spec + BANS_TIMESTAMP, u);
354 24569
        b->spec[BANS_FLAGS] = b->flags & 0xff;
355 24569
        memcpy(b->spec + BANS_HEAD_LEN, VSB_data(bp->vsb), ln);
356 24569
        ln += BANS_HEAD_LEN;
357 24569
        vbe32enc(b->spec + BANS_LENGTH, ln);
358
359 24569
        Lck_Lock(&ban_mtx);
360 24569
        if (ban_shutdown) {
361
                /* We could have raced a shutdown */
362 0
                Lck_Unlock(&ban_mtx);
363 0
                BAN_Free(b);
364 0
                return (ban_error(bp, "Shutting down"));
365
        }
366 24569
        bi = VTAILQ_FIRST(&ban_head);
367 24569
        VTAILQ_INSERT_HEAD(&ban_head, b, list);
368 24569
        ban_start = b;
369
370 24569
        VSC_C_main->bans++;
371 24569
        VSC_C_main->bans_added++;
372 24569
        bans_persisted_bytes += ln;
373 24569
        VSC_C_main->bans_persisted_bytes = bans_persisted_bytes;
374
375 24569
        if (b->flags & BANS_FLAG_OBJ)
376 1450
                VSC_C_main->bans_obj++;
377 24569
        if (b->flags & BANS_FLAG_REQ)
378 1025
                VSC_C_main->bans_req++;
379
380 24569
        if (bi != NULL)
381 2375
                ban_info_new(b->spec, ln);      /* Notify stevedores */
382
383 24569
        if (cache_param->ban_dups) {
384
                /* Hunt down duplicates, and mark them as completed */
385 30569
                for (bi = VTAILQ_NEXT(b, list); bi != NULL;
386 6000
                    bi = VTAILQ_NEXT(bi, list)) {
387 6000
                        if (!(bi->flags & BANS_FLAG_COMPLETED) &&
388 4500
                            ban_equal(b->spec, bi->spec)) {
389 325
                                ban_mark_completed(bi);
390 325
                                VSC_C_main->bans_dups++;
391 325
                        }
392 6000
                }
393 24569
        }
394 24569
        if (!(b->flags & BANS_FLAG_REQ))
395 23544
                ban_kick_lurker();
396 24569
        Lck_Unlock(&ban_mtx);
397
398 24569
        BAN_Abandon(bp);
399 24569
        return (NULL);
400 24569
}
401
402
static void
403 177552
ban_build_arg_operhelp(struct vsb *vsb, int arg)
404
{
405
        unsigned mask;
406 177552
        const char *p = NULL, *n = NULL;
407
        int i;
408
409 177552
        ASSERT_BAN_ARG(arg);
410 177552
        mask = arg_opervalid[BAN_ARGIDX(arg)];
411
412 1597968
        for (i = 0; i < BAN_OPERARRSZ; i++) {
413 1420416
                if ((mask & (1U << i)) == 0)
414 532656
                        continue;
415 887760
                if (p == NULL)
416 177552
                        p = ban_oper[i];
417 710208
                else if (n == NULL)
418 177552
                        n = ban_oper[i];
419
                else {
420 532656
                        VSB_cat(vsb, p);
421 532656
                        VSB_cat(vsb, ", ");
422 532656
                        p = n;
423 532656
                        n = ban_oper[i];
424
                }
425 887760
        }
426
427 177552
        if (n) {
428 177552
                AN(p);
429 177552
                VSB_cat(vsb, p);
430 177552
                VSB_cat(vsb, " or ");
431 177552
                VSB_cat(vsb, n);
432 177552
                return;
433
        }
434
435 0
        AN(p);
436 0
        VSB_cat(vsb, p);
437 177552
}
438
439
void
440 22194
BAN_Build_Init(void) {
441
        struct vsb *vsb;
442
        int i;
443
444 22194
        vsb = VSB_new_auto();
445 22194
        AN(vsb);
446 199746
        for (i = BANS_ARG_OFF_; i < BANS_ARG_LIM; i ++) {
447 177552
                VSB_clear(vsb);
448 177552
                ban_build_arg_operhelp(vsb, i);
449 177552
                AZ(VSB_finish(vsb));
450
451 177552
                arg_operhelp[BAN_ARGIDX(i)] = strdup(VSB_data(vsb));
452 177552
                AN(arg_operhelp[BAN_ARGIDX(i)]);
453 177552
        }
454 22194
        arg_operhelp[BAN_ARGIDX(i)] = NULL;
455 22194
        VSB_destroy(&vsb);
456 22194
}
457
458
void
459 21900
BAN_Build_Fini(void) {
460
        int i;
461
462 197100
        for (i = 0; i < BAN_ARGARRSZ; i++)
463 175200
                free(TRUST_ME(arg_operhelp[i]));
464 21900
}