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 41511
BAN_Build(void)
97
{
98
        struct ban_proto *bp;
99
100 41511
        ALLOC_OBJ(bp, BAN_PROTO_MAGIC);
101 41511
        if (bp == NULL)
102 0
                return (bp);
103 41511
        bp->vsb = VSB_new_auto();
104 41511
        if (bp->vsb == NULL) {
105 0
                FREE_OBJ(bp);
106 0
                return (NULL);
107
        }
108 41511
        return (bp);
109 41511
}
110
111
// TODO: change to (struct ban_proto **)
112
void
113 41511
BAN_Abandon(struct ban_proto *bp)
114
{
115
116 41511
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
117 41511
        VSB_destroy(&bp->vsb);
118 41511
        FREE_OBJ(bp);
119 41511
}
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 40471
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 40471
        CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC);
327 40471
        AN(bp->vsb);
328 40471
        assert(sizeof u == sizeof t0);
329
330 40471
        if (ban_shutdown)
331 0
                return (ban_error(bp, "Shutting down"));
332
333 40471
        AZ(VSB_finish(bp->vsb));
334 40471
        ln = VSB_len(bp->vsb);
335 40471
        assert(ln >= 0);
336
337 40471
        ALLOC_OBJ(b, BAN_MAGIC);
338 40471
        if (b == NULL)
339 0
                return (ban_error(bp, ban_build_err_no_mem));
340 40471
        VTAILQ_INIT(&b->objcore);
341
342 40471
        b->spec = malloc(ln + BANS_HEAD_LEN);
343 40471
        if (b->spec == NULL) {
344 0
                free(b);
345 0
                return (ban_error(bp, ban_build_err_no_mem));
346
        }
347
348 40471
        b->flags = bp->flags;
349
350 40471
        memset(b->spec, 0, BANS_HEAD_LEN);
351 40471
        t0 = VTIM_real();
352 40471
        memcpy(&u, &t0, sizeof u);
353 40471
        vbe64enc(b->spec + BANS_TIMESTAMP, u);
354 40471
        b->spec[BANS_FLAGS] = b->flags & 0xff;
355 40471
        memcpy(b->spec + BANS_HEAD_LEN, VSB_data(bp->vsb), ln);
356 40471
        ln += BANS_HEAD_LEN;
357 40471
        vbe32enc(b->spec + BANS_LENGTH, ln);
358
359 40471
        Lck_Lock(&ban_mtx);
360 40471
        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 40471
        bi = VTAILQ_FIRST(&ban_head);
367 40471
        VTAILQ_INSERT_HEAD(&ban_head, b, list);
368 40471
        ban_start = b;
369
370 40471
        VSC_C_main->bans++;
371 40471
        VSC_C_main->bans_added++;
372 40471
        bans_persisted_bytes += ln;
373 40471
        VSC_C_main->bans_persisted_bytes = bans_persisted_bytes;
374
375 40471
        if (b->flags & BANS_FLAG_OBJ)
376 2320
                VSC_C_main->bans_obj++;
377 40471
        if (b->flags & BANS_FLAG_REQ)
378 1640
                VSC_C_main->bans_req++;
379
380 40471
        if (bi != NULL)
381 3800
                ban_info_new(b->spec, ln);      /* Notify stevedores */
382
383 40471
        if (cache_param->ban_dups) {
384
                /* Hunt down duplicates, and mark them as completed */
385 50069
                for (bi = VTAILQ_NEXT(b, list); bi != NULL;
386 9598
                    bi = VTAILQ_NEXT(bi, list)) {
387 9598
                        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 9598
                }
393 40471
        }
394 40471
        if (!(b->flags & BANS_FLAG_REQ))
395 38831
                ban_kick_lurker();
396 40471
        Lck_Unlock(&ban_mtx);
397
398 40471
        BAN_Abandon(bp);
399 40471
        return (NULL);
400 40471
}
401
402
static void
403 293368
ban_build_arg_operhelp(struct vsb *vsb, int arg)
404
{
405
        unsigned mask;
406 293368
        const char *p = NULL, *n = NULL;
407
        int i;
408
409 293368
        ASSERT_BAN_ARG(arg);
410 293368
        mask = arg_opervalid[BAN_ARGIDX(arg)];
411
412 2640312
        for (i = 0; i < BAN_OPERARRSZ; i++) {
413 2346944
                if ((mask & (1U << i)) == 0)
414 880104
                        continue;
415 1466840
                if (p == NULL)
416 293368
                        p = ban_oper[i];
417 1173472
                else if (n == NULL)
418 293368
                        n = ban_oper[i];
419
                else {
420 880104
                        VSB_cat(vsb, p);
421 880104
                        VSB_cat(vsb, ", ");
422 880104
                        p = n;
423 880104
                        n = ban_oper[i];
424
                }
425 1466840
        }
426
427 293368
        if (n) {
428 293368
                AN(p);
429 293368
                VSB_cat(vsb, p);
430 293368
                VSB_cat(vsb, " or ");
431 293368
                VSB_cat(vsb, n);
432 293368
                return;
433
        }
434
435 0
        AN(p);
436 0
        VSB_cat(vsb, p);
437 293368
}
438
439
void
440 36671
BAN_Build_Init(void) {
441
        struct vsb *vsb;
442
        int i;
443
444 36671
        vsb = VSB_new_auto();
445 36671
        AN(vsb);
446 330039
        for (i = BANS_ARG_OFF_; i < BANS_ARG_LIM; i ++) {
447 293368
                VSB_clear(vsb);
448 293368
                ban_build_arg_operhelp(vsb, i);
449 293368
                AZ(VSB_finish(vsb));
450
451 293368
                arg_operhelp[BAN_ARGIDX(i)] = strdup(VSB_data(vsb));
452 293368
                AN(arg_operhelp[BAN_ARGIDX(i)]);
453 293368
        }
454 36671
        arg_operhelp[BAN_ARGIDX(i)] = NULL;
455 36671
        VSB_destroy(&vsb);
456 36671
}
457
458
void
459 36160
BAN_Build_Fini(void) {
460
        int i;
461
462 325440
        for (i = 0; i < BAN_ARGARRSZ; i++)
463 289280
                free(TRUST_ME(arg_operhelp[i]));
464 36160
}