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