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 3161
BAN_Build(void)
97
{
98
        struct ban_proto *bp;
99
100 3161
        ALLOC_OBJ(bp, BAN_PROTO_MAGIC);
101 3161
        if (bp == NULL)
102 0
                return (bp);
103 3161
        bp->vsb = VSB_new_auto();
104 3161
        if (bp->vsb == NULL) {
105 0
                FREE_OBJ(bp);
106 0
                return (NULL);
107
        }
108 3161
        return (bp);
109 3161
}
110
111
// TODO: change to (struct ban_proto **)
112
void
113 3161
BAN_Abandon(struct ban_proto *bp)
114
{
115
116 3161
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
117 3161
        VSB_destroy(&bp->vsb);
118 3161
        FREE_OBJ(bp);
119 3161
}
120
121
/*--------------------------------------------------------------------
122
 */
123
124
static void
125 423
ban_add_lump(const struct ban_proto *bp, const void *p, uint32_t len)
126
{
127 423
        uint8_t buf[PRNDUP(sizeof len)] = { 0xff };
128
129 2442
        while (VSB_len(bp->vsb) & PALGN)
130 2019
                VSB_putc(bp->vsb, buf[0]);
131 423
        vbe32enc(buf, len);
132 423
        VSB_bcat(bp->vsb, buf, sizeof buf);
133 423
        VSB_bcat(bp->vsb, p, len);
134 423
}
135
136
/*--------------------------------------------------------------------
137
 */
138
139
static const char *
140 54
ban_error(struct ban_proto *bp, const char *fmt, ...)
141
{
142
        va_list ap;
143
144 54
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
145 54
        AN(bp->vsb);
146
147
        /* First error is sticky */
148 54
        if (bp->err == NULL) {
149 54
                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 54
                        VSB_clear(bp->vsb);
154 54
                        va_start(ap, fmt);
155 54
                        VSB_vprintf(bp->vsb, fmt, ap);
156 54
                        va_end(ap);
157 54
                        AZ(VSB_finish(bp->vsb));
158 54
                        bp->err = VSB_data(bp->vsb);
159
                }
160 54
        }
161 54
        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 144
ban_parse_http(const struct ban_proto *bp, const char *a1)
171
{
172
        int l;
173
174 144
        l = strlen(a1) + 1;
175 144
        assert(l <= 127);
176 144
        VSB_putc(bp->vsb, (char)l);
177 144
        VSB_cat(bp->vsb, a1);
178 144
        VSB_putc(bp->vsb, ':');
179 144
        VSB_putc(bp->vsb, '\0');
180 144
}
181
182
/*--------------------------------------------------------------------
183
 * Parse and add a ban test specification
184
 */
185
186
static const char *
187 90
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 90
        re = VRE_compile(a3, 0, &errorcode, &erroroffset, 0);
196 90
        if (re == NULL) {
197 3
                AN(VSB_init(vsb, errbuf, sizeof errbuf));
198 3
                AZ(VRE_error(vsb, errorcode));
199 3
                AZ(VSB_finish(vsb));
200 3
                VSB_fini(vsb);
201 3
                return (ban_error(bp, "Regex compile error: %s", errbuf));
202
        }
203
204 87
        rex = VRE_export(re, &sz);
205 87
        AN(rex);
206 87
        ban_add_lump(bp, rex, sz);
207 87
        VRE_free(&rex);
208 87
        VRE_free(&re);
209 87
        return (0);
210 90
}
211
212
static int
213 360
ban_parse_oper(const char *p)
214
{
215
        int i;
216
217 780
        for (i = 0; i < BAN_OPERARRSZ; i++) {
218 768
                if (!strcmp(p, ban_oper[i]))
219 348
                        return (BANS_OPER_OFF_ + i);
220 420
        }
221 12
        return (-1);
222 360
}
223
224
/*--------------------------------------------------------------------
225
 * Add a (and'ed) test-condition to a ban
226
 */
227
static const char *
228 255
ban_add_spec(struct ban_proto *bp, const struct pvar *pv, int op, const char *a3)
229
{
230
231 255
        assert(! BANS_HAS_ARG2_DOUBLE(pv->tag));
232
233 255
        ban_add_lump(bp, a3, strlen(a3) + 1);
234 255
        VSB_putc(bp->vsb, op);
235
236 255
        if (! BANS_HAS_ARG2_SPEC(op))
237 165
                return (NULL);
238
239 90
        return (ban_parse_regexp(bp, a3));
240 255
}
241
242
static const char *
243 81
ban_add_double(const struct ban_proto *bp, const struct pvar *pv, int op, double darg)
244
{
245
        uint64_t dtmp;
246
        uint8_t denc[sizeof darg];
247
248 81
        assert(BANS_HAS_ARG2_DOUBLE(pv->tag));
249 81
        assert(sizeof darg == sizeof dtmp);
250 81
        assert(sizeof dtmp == sizeof denc);
251 81
        memcpy(&dtmp, &darg, sizeof dtmp);
252 81
        vbe64enc(denc, dtmp);
253
254 81
        ban_add_lump(bp, denc, sizeof denc);
255 81
        VSB_putc(bp->vsb, op);
256 81
        return (NULL);
257
}
258
259
static const char *
260 87
ban_add_duration(struct ban_proto *bp, const struct pvar *pv, int op, const char *a3)
261
{
262
        double darg;
263
264 87
        assert(pv->flag & BANS_FLAG_DURATION);
265 87
        darg = VNUM_duration(a3);
266 87
        if (isnan(darg)) {
267 12
                return (ban_error(bp,
268 6
                    "expected duration <n.nn>[ms|s|m|h|d|w|y] got \"%s\"", a3));
269
        }
270 81
        return (ban_add_double(bp, pv, op, darg));
271 87
}
272
273
const char *
274 387
BAN_AddTest(struct ban_proto *bp,
275
    const char *a1, const char *a2, const char *a3)
276
{
277
        const struct pvar *pv;
278
        int op;
279
280 387
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
281 387
        AN(bp->vsb);
282 387
        AN(a1);
283 387
        AN(a2);
284 387
        AN(a3);
285
286 387
        if (bp->err != NULL)
287 0
                return (bp->err);
288
289 1539
        for (pv = pvars; pv->name != NULL; pv++) {
290 1515
                if (!(pv->flag & BANS_FLAG_HTTP) && !strcmp(a1, pv->name))
291 216
                        break;
292 1299
                if ((pv->flag & BANS_FLAG_HTTP) && !strncmp(a1, pv->name, strlen(pv->name)))
293 147
                        break;
294 1152
        }
295
296 387
        if (pv->name == NULL)
297 48
                return (ban_error(bp,
298 24
                    "Unknown or unsupported field \"%s\"", a1));
299
300 363
        bp->flags |= pv->flag;
301
302 363
        VSB_putc(bp->vsb, pv->tag);
303 363
        if (pv->flag & BANS_FLAG_HTTP) {
304 147
                if (strlen(a1 + strlen(pv->name)) < 1)
305 6
                        return (ban_error(bp,
306 3
                            "Missing header name: \"%s\"", pv->name));
307 144
                assert(BANS_HAS_ARG1_SPEC(pv->tag));
308 144
                ban_parse_http(bp, a1 + strlen(pv->name));
309 144
        }
310
311 360
        op = ban_parse_oper(a2);
312 360
        if (op < BANS_OPER_OFF_ ||
313 348
            ((1U << BAN_OPERIDX(op)) & arg_opervalid[BAN_ARGIDX(pv->tag)]) == 0)
314 36
                return (ban_error(bp,
315
                    "expected conditional (%s) got \"%s\"",
316 18
                    arg_operhelp[BAN_ARGIDX(pv->tag)], a2));
317
318 342
        if (pv->flag & BANS_FLAG_DURATION)
319 87
                return (ban_add_duration(bp, pv, op, a3));
320
        else
321 255
                return (ban_add_spec(bp, pv, op, a3));
322 387
}
323
324
/*--------------------------------------------------------------------
325
 * We maintain ban_start as a pointer to the first element of the list
326
 * as a separate variable from the VTAILQ, to avoid depending on the
327
 * internals of the VTAILQ macros.  We tacitly assume that a pointer
328
 * write is always atomic in doing so.
329
 *
330
 * Returns:
331
 *   0: Ban successfully inserted
332
 *  -1: Ban not inserted due to shutdown in progress. The ban has been
333
 *      deleted.
334
 */
335
336
const char *
337 3083
BAN_Commit(struct ban_proto *bp)
338
{
339
        struct ban  *b, *bi;
340
        ssize_t ln;
341
        vtim_real t0;
342
        uint64_t u;
343
344 3083
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
345 3083
        AN(bp->vsb);
346 3083
        assert(sizeof u == sizeof t0);
347
348 3083
        if (ban_shutdown)
349 0
                return (ban_error(bp, "Shutting down"));
350
351 3083
        AZ(VSB_finish(bp->vsb));
352 3083
        ln = VSB_len(bp->vsb);
353 3083
        assert(ln >= 0);
354
355 3083
        ALLOC_OBJ(b, BAN_MAGIC);
356 3083
        if (b == NULL)
357 0
                return (ban_error(bp, ban_build_err_no_mem));
358 3083
        VTAILQ_INIT(&b->objcore);
359
360 3083
        b->spec = malloc(ln + BANS_HEAD_LEN);
361 3083
        if (b->spec == NULL) {
362 0
                free(b);
363 0
                return (ban_error(bp, ban_build_err_no_mem));
364
        }
365
366 3083
        b->flags = bp->flags;
367
368 3083
        memset(b->spec, 0, BANS_HEAD_LEN);
369 3083
        t0 = VTIM_real();
370 3083
        memcpy(&u, &t0, sizeof u);
371 3083
        vbe64enc(b->spec + BANS_TIMESTAMP, u);
372 3083
        b->spec[BANS_FLAGS] = b->flags & 0xff;
373 3083
        memcpy(b->spec + BANS_HEAD_LEN, VSB_data(bp->vsb), ln);
374 3083
        ln += BANS_HEAD_LEN;
375 3083
        vbe32enc(b->spec + BANS_LENGTH, ln);
376
377 3083
        Lck_Lock(&ban_mtx);
378 3083
        if (ban_shutdown) {
379
                /* We could have raced a shutdown */
380 0
                Lck_Unlock(&ban_mtx);
381 0
                BAN_Free(b);
382 0
                return (ban_error(bp, "Shutting down"));
383
        }
384 3083
        bi = VTAILQ_FIRST(&ban_head);
385 3083
        VTAILQ_INSERT_HEAD(&ban_head, b, list);
386 3083
        ban_start = b;
387
388 3083
        VSC_C_main->bans++;
389 3083
        VSC_C_main->bans_added++;
390 3083
        bans_persisted_bytes += ln;
391 3083
        VSC_C_main->bans_persisted_bytes = bans_persisted_bytes;
392
393 3083
        if (b->flags & BANS_FLAG_OBJ)
394 183
                VSC_C_main->bans_obj++;
395 3083
        if (b->flags & BANS_FLAG_REQ)
396 126
                VSC_C_main->bans_req++;
397
398 3083
        if (bi != NULL)
399 297
                ban_info_new(b->spec, ln);      /* Notify stevedores */
400
401 3083
        if (cache_param->ban_dups) {
402
                /* Hunt down duplicates, and mark them as completed */
403 3824
                for (bi = VTAILQ_NEXT(b, list); bi != NULL;
404 741
                    bi = VTAILQ_NEXT(bi, list)) {
405 741
                        if (!(bi->flags & BANS_FLAG_COMPLETED) &&
406 549
                            ban_equal(b->spec, bi->spec)) {
407 39
                                ban_mark_completed(bi);
408 39
                                VSC_C_main->bans_dups++;
409 39
                        }
410 741
                }
411 3083
        }
412 3083
        if (!(b->flags & BANS_FLAG_REQ))
413 2957
                ban_kick_lurker();
414 3083
        Lck_Unlock(&ban_mtx);
415
416 3083
        BAN_Abandon(bp);
417 3083
        return (NULL);
418 3083
}
419
420
static void
421 22288
ban_build_arg_operhelp(struct vsb *vsb, int arg)
422
{
423
        unsigned mask;
424 22288
        const char *p = NULL, *n = NULL;
425
        int i;
426
427 22288
        ASSERT_BAN_ARG(arg);
428 22288
        mask = arg_opervalid[BAN_ARGIDX(arg)];
429
430 200592
        for (i = 0; i < BAN_OPERARRSZ; i++) {
431 178304
                if ((mask & (1U << i)) == 0)
432 66864
                        continue;
433 111440
                if (p == NULL)
434 22288
                        p = ban_oper[i];
435 89152
                else if (n == NULL)
436 22288
                        n = ban_oper[i];
437
                else {
438 66864
                        VSB_cat(vsb, p);
439 66864
                        VSB_cat(vsb, ", ");
440 66864
                        p = n;
441 66864
                        n = ban_oper[i];
442
                }
443 111440
        }
444
445 22288
        if (n) {
446 22288
                AN(p);
447 22288
                VSB_cat(vsb, p);
448 22288
                VSB_cat(vsb, " or ");
449 22288
                VSB_cat(vsb, n);
450 22288
                return;
451
        }
452
453 0
        AN(p);
454 0
        VSB_cat(vsb, p);
455 22288
}
456
457
void
458 2786
BAN_Build_Init(void) {
459
        struct vsb *vsb;
460
        int i;
461
462 2786
        vsb = VSB_new_auto();
463 2786
        AN(vsb);
464 25074
        for (i = BANS_ARG_OFF_; i < BANS_ARG_LIM; i ++) {
465 22288
                VSB_clear(vsb);
466 22288
                ban_build_arg_operhelp(vsb, i);
467 22288
                AZ(VSB_finish(vsb));
468
469 22288
                arg_operhelp[BAN_ARGIDX(i)] = strdup(VSB_data(vsb));
470 22288
                AN(arg_operhelp[BAN_ARGIDX(i)]);
471 22288
        }
472 2786
        arg_operhelp[BAN_ARGIDX(i)] = NULL;
473 2786
        VSB_destroy(&vsb);
474 2786
}
475
476
void
477 2748
BAN_Build_Fini(void) {
478
        int i;
479
480 24732
        for (i = 0; i < BAN_ARGARRSZ; i++)
481 21984
                free(TRUST_ME(arg_operhelp[i]));
482 2748
}