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 41461
BAN_Build(void)
97
{
98
        struct ban_proto *bp;
99
100 41461
        ALLOC_OBJ(bp, BAN_PROTO_MAGIC);
101 41461
        if (bp == NULL)
102 0
                return (bp);
103 41461
        bp->vsb = VSB_new_auto();
104 41461
        if (bp->vsb == NULL) {
105 0
                FREE_OBJ(bp);
106 0
                return (NULL);
107
        }
108 41461
        return (bp);
109 41461
}
110
111
// TODO: change to (struct ban_proto **)
112
void
113 41461
BAN_Abandon(struct ban_proto *bp)
114
{
115
116 41461
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
117 41461
        VSB_destroy(&bp->vsb);
118 41461
        FREE_OBJ(bp);
119 41461
}
120
121
/*--------------------------------------------------------------------
122
 */
123
124
static void
125 5480
ban_add_lump(const struct ban_proto *bp, const void *p, uint32_t len)
126
{
127 5480
        uint8_t buf[PRNDUP(sizeof len)] = { 0xff };
128
129 32080
        while (VSB_len(bp->vsb) & PALGN)
130 26600
                VSB_putc(bp->vsb, buf[0]);
131 5480
        vbe32enc(buf, len);
132 5480
        VSB_bcat(bp->vsb, buf, sizeof buf);
133 5480
        VSB_bcat(bp->vsb, p, len);
134 5480
}
135
136
/*--------------------------------------------------------------------
137
 */
138
139
static const char *
140 720
ban_error(struct ban_proto *bp, const char *fmt, ...)
141
{
142
        va_list ap;
143
144 720
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
145 720
        AN(bp->vsb);
146
147
        /* First error is sticky */
148 720
        if (bp->err == NULL) {
149 720
                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 720
                        VSB_clear(bp->vsb);
154 720
                        va_start(ap, fmt);
155 720
                        VSB_vprintf(bp->vsb, fmt, ap);
156 720
                        va_end(ap);
157 720
                        AZ(VSB_finish(bp->vsb));
158 720
                        bp->err = VSB_data(bp->vsb);
159
                }
160 720
        }
161 720
        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 1760
ban_parse_http(const struct ban_proto *bp, const char *a1)
171
{
172
        int l;
173
174 1760
        l = strlen(a1) + 1;
175 1760
        assert(l <= 127);
176 1760
        VSB_putc(bp->vsb, (char)l);
177 1760
        VSB_cat(bp->vsb, a1);
178 1760
        VSB_putc(bp->vsb, ':');
179 1760
        VSB_putc(bp->vsb, '\0');
180 1760
}
181
182
/*--------------------------------------------------------------------
183
 * Parse and add a ban test specification
184
 */
185
186
static const char *
187 1200
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 1200
        re = VRE_compile(a3, 0, &errorcode, &erroroffset, 0);
196 1200
        if (re == NULL) {
197 40
                AN(VSB_init(vsb, errbuf, sizeof errbuf));
198 40
                AZ(VRE_error(vsb, errorcode));
199 40
                AZ(VSB_finish(vsb));
200 40
                VSB_fini(vsb);
201 40
                return (ban_error(bp, "Regex compile error: %s", errbuf));
202
        }
203
204 1160
        rex = VRE_export(re, &sz);
205 1160
        AN(rex);
206 1160
        ban_add_lump(bp, rex, sz);
207 1160
        VRE_free(&rex);
208 1160
        VRE_free(&re);
209 1160
        return (0);
210 1200
}
211
212
static int
213 4640
ban_parse_oper(const char *p)
214
{
215
        int i;
216
217 10240
        for (i = 0; i < BAN_OPERARRSZ; i++) {
218 10080
                if (!strcmp(p, ban_oper[i]))
219 4480
                        return (BANS_OPER_OFF_ + i);
220 5600
        }
221 160
        return (-1);
222 4640
}
223
224
/*--------------------------------------------------------------------
225
 * Add a (and'ed) test-condition to a ban
226
 */
227
228
const char *
229 5000
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 5000
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
239 5000
        AN(bp->vsb);
240 5000
        AN(a1);
241 5000
        AN(a2);
242 5000
        AN(a3);
243
244 5000
        if (bp->err != NULL)
245 0
                return (bp->err);
246
247 19960
        for (pv = pvars; pv->name != NULL; pv++) {
248 19640
                if (!(pv->flag & BANS_FLAG_HTTP) && !strcmp(a1, pv->name))
249 2880
                        break;
250 16760
                if ((pv->flag & BANS_FLAG_HTTP) && !strncmp(a1, pv->name, strlen(pv->name)))
251 1800
                        break;
252 14960
        }
253
254 5000
        if (pv->name == NULL)
255 640
                return (ban_error(bp,
256 320
                    "Unknown or unsupported field \"%s\"", a1));
257
258 4680
        bp->flags |= pv->flag;
259
260 4680
        VSB_putc(bp->vsb, pv->tag);
261 4680
        if (pv->flag & BANS_FLAG_HTTP) {
262 1800
                if (strlen(a1 + strlen(pv->name)) < 1)
263 80
                        return (ban_error(bp,
264 40
                            "Missing header name: \"%s\"", pv->name));
265 1760
                assert(BANS_HAS_ARG1_SPEC(pv->tag));
266 1760
                ban_parse_http(bp, a1 + strlen(pv->name));
267 1760
        }
268
269 4640
        op = ban_parse_oper(a2);
270 4640
        if (op < BANS_OPER_OFF_ ||
271 4480
            ((1U << BAN_OPERIDX(op)) & arg_opervalid[BAN_ARGIDX(pv->tag)]) == 0)
272 480
                return (ban_error(bp,
273
                    "expected conditional (%s) got \"%s\"",
274 240
                    arg_operhelp[BAN_ARGIDX(pv->tag)], a2));
275
276 4400
        if ((pv->flag & BANS_FLAG_DURATION) == 0) {
277 3240
                assert(! BANS_HAS_ARG2_DOUBLE(pv->tag));
278
279 3240
                ban_add_lump(bp, a3, strlen(a3) + 1);
280 3240
                VSB_putc(bp->vsb, op);
281
282 3240
                if (! BANS_HAS_ARG2_SPEC(op))
283 2040
                        return (NULL);
284
285 1200
                return (ban_parse_regexp(bp, a3));
286
        }
287
288 1160
        assert(pv->flag & BANS_FLAG_DURATION);
289 1160
        assert(BANS_HAS_ARG2_DOUBLE(pv->tag));
290 1160
        darg = VNUM_duration(a3);
291 1160
        if (isnan(darg)) {
292 160
                return (ban_error(bp,
293 80
                    "expected duration <n.nn>[ms|s|m|h|d|w|y] got \"%s\"", a3));
294
        }
295
296 1080
        assert(sizeof darg == sizeof dtmp);
297 1080
        assert(sizeof dtmp == sizeof denc);
298 1080
        memcpy(&dtmp, &darg, sizeof dtmp);
299 1080
        vbe64enc(denc, dtmp);
300
301 1080
        ban_add_lump(bp, denc, sizeof denc);
302 1080
        VSB_putc(bp->vsb, op);
303 1080
        return (NULL);
304 5000
}
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 40421
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 40421
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
327 40421
        AN(bp->vsb);
328 40421
        assert(sizeof u == sizeof t0);
329
330 40421
        if (ban_shutdown)
331 0
                return (ban_error(bp, "Shutting down"));
332
333 40421
        AZ(VSB_finish(bp->vsb));
334 40421
        ln = VSB_len(bp->vsb);
335 40421
        assert(ln >= 0);
336
337 40421
        ALLOC_OBJ(b, BAN_MAGIC);
338 40421
        if (b == NULL)
339 0
                return (ban_error(bp, ban_build_err_no_mem));
340 40421
        VTAILQ_INIT(&b->objcore);
341
342 40421
        b->spec = malloc(ln + BANS_HEAD_LEN);
343 40421
        if (b->spec == NULL) {
344 0
                free(b);
345 0
                return (ban_error(bp, ban_build_err_no_mem));
346
        }
347
348 40421
        b->flags = bp->flags;
349
350 40421
        memset(b->spec, 0, BANS_HEAD_LEN);
351 40421
        t0 = VTIM_real();
352 40421
        memcpy(&u, &t0, sizeof u);
353 40421
        vbe64enc(b->spec + BANS_TIMESTAMP, u);
354 40421
        b->spec[BANS_FLAGS] = b->flags & 0xff;
355 40421
        memcpy(b->spec + BANS_HEAD_LEN, VSB_data(bp->vsb), ln);
356 40421
        ln += BANS_HEAD_LEN;
357 40421
        vbe32enc(b->spec + BANS_LENGTH, ln);
358
359 40421
        Lck_Lock(&ban_mtx);
360 40421
        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 40421
        bi = VTAILQ_FIRST(&ban_head);
367 40421
        VTAILQ_INSERT_HEAD(&ban_head, b, list);
368 40421
        ban_start = b;
369
370 40421
        VSC_C_main->bans++;
371 40421
        VSC_C_main->bans_added++;
372 40421
        bans_persisted_bytes += ln;
373 40421
        VSC_C_main->bans_persisted_bytes = bans_persisted_bytes;
374
375 40421
        if (b->flags & BANS_FLAG_OBJ)
376 2320
                VSC_C_main->bans_obj++;
377 40421
        if (b->flags & BANS_FLAG_REQ)
378 1640
                VSC_C_main->bans_req++;
379
380 40421
        if (bi != NULL)
381 3800
                ban_info_new(b->spec, ln);      /* Notify stevedores */
382
383 40421
        if (cache_param->ban_dups) {
384
                /* Hunt down duplicates, and mark them as completed */
385 50020
                for (bi = VTAILQ_NEXT(b, list); bi != NULL;
386 9599
                    bi = VTAILQ_NEXT(bi, list)) {
387 9599
                        if (!(bi->flags & BANS_FLAG_COMPLETED) &&
388 7200
                            ban_equal(b->spec, bi->spec)) {
389 520
                                ban_mark_completed(bi);
390 520
                                VSC_C_main->bans_dups++;
391 520
                        }
392 9599
                }
393 40421
        }
394 40421
        if (!(b->flags & BANS_FLAG_REQ))
395 38781
                ban_kick_lurker();
396 40421
        Lck_Unlock(&ban_mtx);
397
398 40421
        BAN_Abandon(bp);
399 40421
        return (NULL);
400 40421
}
401
402
static void
403 292968
ban_build_arg_operhelp(struct vsb *vsb, int arg)
404
{
405
        unsigned mask;
406 292968
        const char *p = NULL, *n = NULL;
407
        int i;
408
409 292968
        ASSERT_BAN_ARG(arg);
410 292968
        mask = arg_opervalid[BAN_ARGIDX(arg)];
411
412 2636712
        for (i = 0; i < BAN_OPERARRSZ; i++) {
413 2343744
                if ((mask & (1U << i)) == 0)
414 878904
                        continue;
415 1464840
                if (p == NULL)
416 292968
                        p = ban_oper[i];
417 1171872
                else if (n == NULL)
418 292968
                        n = ban_oper[i];
419
                else {
420 878904
                        VSB_cat(vsb, p);
421 878904
                        VSB_cat(vsb, ", ");
422 878904
                        p = n;
423 878904
                        n = ban_oper[i];
424
                }
425 1464840
        }
426
427 292968
        if (n) {
428 292968
                AN(p);
429 292968
                VSB_cat(vsb, p);
430 292968
                VSB_cat(vsb, " or ");
431 292968
                VSB_cat(vsb, n);
432 292968
                return;
433
        }
434
435 0
        AN(p);
436 0
        VSB_cat(vsb, p);
437 292968
}
438
439
void
440 36621
BAN_Build_Init(void) {
441
        struct vsb *vsb;
442
        int i;
443
444 36621
        vsb = VSB_new_auto();
445 36621
        AN(vsb);
446 329589
        for (i = BANS_ARG_OFF_; i < BANS_ARG_LIM; i ++) {
447 292968
                VSB_clear(vsb);
448 292968
                ban_build_arg_operhelp(vsb, i);
449 292968
                AZ(VSB_finish(vsb));
450
451 292968
                arg_operhelp[BAN_ARGIDX(i)] = strdup(VSB_data(vsb));
452 292968
                AN(arg_operhelp[BAN_ARGIDX(i)]);
453 292968
        }
454 36621
        arg_operhelp[BAN_ARGIDX(i)] = NULL;
455 36621
        VSB_destroy(&vsb);
456 36621
}
457
458
void
459 36120
BAN_Build_Fini(void) {
460
        int i;
461
462 325080
        for (i = 0; i < BAN_ARGARRSZ; i++)
463 288960
                free(TRUST_ME(arg_operhelp[i]));
464 36120
}