vinyl-cache/vmod/vmod_debug_filters.c
0
/*-
1
 * Copyright (c) 2012-2019 Varnish Software AS
2
 * All rights reserved.
3
 *
4
 * Author: Poul-Henning Kamp <phk@FreeBSD.org>
5
 *
6
 * SPDX-License-Identifier: BSD-2-Clause
7
 *
8
 * Redistribution and use in source and binary forms, with or without
9
 * modification, are permitted provided that the following conditions
10
 * are met:
11
 * 1. Redistributions of source code must retain the above copyright
12
 *    notice, this list of conditions and the following disclaimer.
13
 * 2. Redistributions in binary form must reproduce the above copyright
14
 *    notice, this list of conditions and the following disclaimer in the
15
 *    documentation and/or other materials provided with the distribution.
16
 *
17
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
 * SUCH DAMAGE.
28
 */
29
30
#include "config.h"
31
32
#include <stdlib.h>
33
#include <stdio.h>
34
#include <string.h>
35
#include <sys/socket.h>
36
#include <unistd.h>
37
38
#include "cache/cache_int.h"
39
#include "cache/cache_filter.h"
40
41
#include "vgz.h"
42
#include "vsha256.h"
43
#include "vtim.h"
44
#include "vcc_debug_if.h"
45
46
#include "vmod_debug.h"
47
48
/**********************************************************************/
49
50
static enum vfp_status v_matchproto_(vfp_pull_f)
51 27
xyzzy_vfp_rot13_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
52
    ssize_t *lp)
53
{
54
        enum vfp_status vp;
55
        char *q;
56
        ssize_t l;
57
58 27
        (void)vfe;
59 27
        vp = VFP_Suck(vc, p, lp);
60 27
        if (vp == VFP_ERROR)
61 0
                return (vp);
62 27
        q = p;
63 783
        for (l = 0; l < *lp; l++, q++) {
64 756
                if (*q >= 'A' && *q <= 'Z')
65 108
                        *q = (((*q - 'A') + 13) % 26) + 'A';
66 756
                if (*q >= 'a' && *q <= 'z')
67 513
                        *q = (((*q - 'a') + 13) % 26) + 'a';
68 756
        }
69 27
        return (vp);
70 27
}
71
72
static const struct vfp xyzzy_vfp_rot13 = {
73
        .name = "rot13",
74
        .pull = xyzzy_vfp_rot13_pull,
75
};
76
77
/**********************************************************************/
78
79
// deliberately fragmenting the stream to make testing more interesting
80
#define ROT13_BUFSZ 8
81
82
static int v_matchproto_(vdp_init_f)
83 75
xyzzy_vdp_rot13_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
84
{
85
86 75
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
87 75
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
88 75
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
89 75
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
90 75
        AN(vdc->clen);
91
92 75
        AN(priv);
93
94 75
        *priv = malloc(ROT13_BUFSZ);
95 75
        if (*priv == NULL)
96 0
                return (-1);
97
98 75
        return (0);
99 75
}
100
101
static int v_matchproto_(vdp_bytes_f)
102 114
xyzzy_vdp_rot13_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
103
    const void *ptr, ssize_t len)
104
{
105
        char *q;
106
        const char *pp;
107 114
        int i, j, retval = 0;
108
109 114
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
110 114
        AN(priv);
111 114
        AN(*priv);
112 114
        if (len <= 0)
113 18
                return (VDP_bytes(vdc, act, ptr, len));
114 96
        AN(ptr);
115 96
        if (act != VDP_END)
116 30
                act = VDP_FLUSH;
117 96
        q = *priv;
118 96
        pp = ptr;
119
120 316512
        for (i = 0, j = 0; j < len; i++, j++) {
121 316416
                if (pp[j] >= 'A' && pp[j] <= 'Z')
122 86278
                        q[i] = (((pp[j] - 'A') + 13) % 26) + 'A';
123 230138
                else if (pp[j] >= 'a' && pp[j] <= 'z')
124 85490
                        q[i] = (((pp[j] - 'a') + 13) % 26) + 'a';
125
                else
126 144648
                        q[i] = pp[j];
127 316416
                if (i == ROT13_BUFSZ - 1 && j < len - 1) {
128 39504
                        retval = VDP_bytes(vdc, VDP_FLUSH, q, ROT13_BUFSZ);
129 39504
                        if (retval != 0)
130 0
                                return (retval);
131 39504
                        i = -1;
132 39504
                }
133 316416
        }
134 96
        if (i >= 0)
135 96
                retval = VDP_bytes(vdc, act, q, i);
136 96
        return (retval);
137 114
}
138
139
static int v_matchproto_(vdp_fini_f)
140 75
xyzzy_vdp_rot13_fini(struct vdp_ctx *vdc, void **priv)
141
{
142 75
        (void)vdc;
143 75
        AN(priv);
144 75
        free(*priv);
145 75
        *priv = NULL;
146 75
        return (0);
147
}
148
149
static const struct vdp xyzzy_vdp_rot13 = {
150
        .name  = "rot13",
151
        .init  = xyzzy_vdp_rot13_init,
152
        .bytes = xyzzy_vdp_rot13_bytes,
153
        .fini  = xyzzy_vdp_rot13_fini,
154
};
155
156
VCL_VOID v_matchproto_(td_debug_rot104)
157 3
xyzzy_rot104(VRT_CTX)
158
{
159
160 3
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
161
        // This should fail
162 3
        AN(VRT_AddFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13));
163 3
}
164
165
/**********************************************************************
166
 * vdp debug_chunked: force http1 chunked encoding by removing the
167
 * Content-Length header
168
 *
169
 * this happens in a VDP because cnt_transmit() runs after VCL and
170
 * restores it
171
 */
172
173
static int v_matchproto_(vdp_init_f)
174 96
xyzzy_vdp_chunked_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
175
{
176
177 96
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
178 96
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
179 96
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
180 96
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
181 96
        AN(vdc->clen);
182 96
        AN(priv);
183
184 96
        *vdc->clen = -1;
185
186 96
        return (1);
187
}
188
189
static const struct vdp xyzzy_vdp_chunked = {
190
        .name  = "debug.chunked",
191
        .init  = xyzzy_vdp_chunked_init,
192
};
193
194
/**********************************************************************
195
 * pedantic tests of the VDP API:
196
 * - assert that we see a VDP_END
197
 * - assert that _fini gets called before the task ends
198
 *
199
 * note:
200
 * we could lookup our own vdpe in _fini and check for vdpe->end == VDP_END
201
 * yet that would cross the API
202
 */
203
204
enum vdp_state_e {
205
        VDPS_NULL = 0,
206
        VDPS_INIT,      // _init called
207
        VDPS_BYTES,     // _bytes called act != VDP_END
208
        VDPS_END,       // _bytes called act == VDP_END
209
        VDPS_FINI       // _fini called
210
};
211
212
struct vdp_state_s {
213
        unsigned                magic;
214
#define VDP_STATE_MAGIC 0x57c8d309
215
        enum vdp_state_e        state;
216
};
217
218
static void v_matchproto_(vmod_priv_fini_f)
219 600
priv_pedantic_fini(VRT_CTX, void *priv)
220
{
221
        struct vdp_state_s *vdps;
222
223 600
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
224 600
        CAST_OBJ_NOTNULL(vdps, priv, VDP_STATE_MAGIC);
225
226 600
        assert(vdps->state == VDPS_FINI);
227 600
}
228
229
static const struct vmod_priv_methods priv_pedantic_methods[1] = {{
230
        .magic = VMOD_PRIV_METHODS_MAGIC,
231
        .type = "debug_vdp_pedantic",
232
        .fini = priv_pedantic_fini
233
}};
234
235
static int v_matchproto_(vdp_init_f)
236 624
xyzzy_pedantic_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
237
{
238
        struct vdp_state_s *vdps;
239
        struct vmod_priv *p;
240
241 624
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
242 624
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
243 624
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
244 624
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
245 624
        AN(vdc->clen);
246 624
        AN(priv);
247
248 1224
        WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_STATE_MAGIC);
249 624
        if (vdps == NULL)
250 24
                return (-1);
251 600
        assert(vdps->state == VDPS_NULL);
252
253 600
        p = VRT_priv_task(ctx, (void *)vdc);
254 600
        if (p == NULL)
255 0
                return (-1);
256 600
        p->priv = vdps;
257 600
        p->methods = priv_pedantic_methods;
258
259 600
        *priv = vdps;
260
261 600
        vdps->state = VDPS_INIT;
262
263 600
        return (0);
264 624
}
265
266
static int v_matchproto_(vdp_bytes_f)
267 759
xyzzy_pedantic_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
268
    const void *ptr, ssize_t len)
269
{
270
        struct vdp_state_s *vdps;
271
272 759
        CAST_OBJ_NOTNULL(vdps, *priv, VDP_STATE_MAGIC);
273 759
        assert(vdps->state >= VDPS_INIT);
274 759
        assert(vdps->state < VDPS_END);
275
276 759
        if (act == VDP_END)
277 210
                vdps->state = VDPS_END;
278
        else
279 549
                vdps->state = VDPS_BYTES;
280
281 759
        return (VDP_bytes(vdc, act, ptr, len));
282
}
283
284
static int v_matchproto_(vdp_fini_f)
285 624
xyzzy_pedantic_fini(struct vdp_ctx *vdc, void **priv)
286
{
287
        struct vdp_state_s *vdps;
288
289 624
        (void) vdc;
290 624
        AN(priv);
291 624
        if (*priv == NULL)
292 24
                return (0);
293 600
        TAKE_OBJ_NOTNULL(vdps, priv, VDP_STATE_MAGIC);
294 600
        assert(vdps->state == VDPS_INIT || vdps->state == VDPS_END);
295 600
        vdps->state = VDPS_FINI;
296
297 600
        return (0);
298 624
}
299
300
static const struct vdp xyzzy_vdp_pedantic = {
301
        .name  = "debug.pedantic",
302
        .init  = xyzzy_pedantic_init,
303
        .bytes = xyzzy_pedantic_bytes,
304
        .fini  = xyzzy_pedantic_fini,
305
};
306
307
/**********************************************************************
308
 *
309
 * this trivial copy/paste/edit filter (of rot13) was specifically made for
310
 * someone who added a DBG_SLOW_BEREQ debug flag. It should actually be turned
311
 * in a proper "bandwidth control" filter, but that exceeds an evening's work,
312
 * so it's kept for later
313
 */
314
315
static enum vfp_status v_matchproto_(vfp_pull_f)
316 0
xyzzy_vfp_slow_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p,
317
    ssize_t *lp)
318
{
319
320 0
        (void)vfe;
321 0
        VTIM_sleep(1.0);
322 0
        return (VFP_Suck(vc, p, lp));
323
}
324
325
static const struct vfp xyzzy_vfp_slow = {
326
        .name = "debug.slow",
327
        .pull = xyzzy_vfp_slow_pull,
328
};
329
330
/**********************************************************************/
331
332
static int v_matchproto_(vdp_bytes_f)
333 12
xyzzy_vdp_slow_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
334
    const void *ptr, ssize_t len)
335
{
336
337 12
        (void)priv;
338 12
        VTIM_sleep(1.0);
339 12
        return (VDP_bytes(vdc, act, ptr, len));
340
}
341
342
static const struct vdp xyzzy_vdp_slow = {
343
        .name  = "debug.slow",
344
        .bytes = xyzzy_vdp_slow_bytes
345
};
346
347
/*
348
 * check VDPs:
349
 *
350
 * test that the stream of bytes has a certain checksum or length and either log
351
 * or panic
352
 *
353
 * The sha256 and crc32 variants are basically identical, but the amount of
354
 * code does not justify generalizing. (slink)
355
 */
356
357
enum vdp_chk_mode_e {
358
        //lint -esym(749, vdp_chk_mode_e::VDP_CHK_INVAL) deliberately not referenced
359
        VDP_CHK_INVAL = 0,
360
        VDP_CHK_LOG,
361
        VDP_CHK_PANIC,
362
        VDP_CHK_PANIC_UNLESS_ERROR
363
};
364
365
struct vdp_chksha256_cfg_s {
366
        unsigned                        magic;
367
#define VDP_CHKSHA256_CFG_MAGIC         0x624f5b32
368
        enum vdp_chk_mode_e             mode;
369
        unsigned char                   expected[VSHA256_DIGEST_LENGTH];
370
};
371
372
struct vdp_chkcrc32_cfg_s {
373
        unsigned                        magic;
374
#define VDP_CHKCRC32_CFG_MAGIC          0x5a7a835c
375
        enum vdp_chk_mode_e             mode;
376
        uint32_t                        expected;
377
};
378
379
struct vdp_chklen_cfg_s {
380
        unsigned                        magic;
381
#define VDP_CHKLEN_CFG_MAGIC            0x08cf3426
382
        enum vdp_chk_mode_e             mode;
383
        size_t                          expected;
384
};
385
386
struct vdp_chksha256_s {
387
        unsigned                        magic;
388
#define VDP_CHKSHA256_MAGIC             0x6856e913
389
        unsigned                        called;
390
        size_t                          bytes;
391
        struct VSHA256Context           cx[1];
392
        struct vdp_chksha256_cfg_s      *cfg;
393
};
394
395
struct vdp_chkcrc32_s {
396
        unsigned                        magic;
397
#define VDP_CHKCRC32_MAGIC              0x15c03d3c
398
        unsigned                        called;
399
        size_t                          bytes;
400
        uint32_t                        crc;
401
        struct vdp_chkcrc32_cfg_s       *cfg;
402
};
403
404
struct vdp_chklen_s {
405
        unsigned                        magic;
406
#define VDP_CHKLEN_MAGIC                0x029811f5
407
        unsigned                        called;
408
        size_t                          bytes;
409
        struct vdp_chklen_cfg_s         *cfg;
410
};
411
412
static const void * const chksha256_priv_id = &chksha256_priv_id;
413
static const void * const chkcrc32_priv_id = &chkcrc32_priv_id;
414
static const void * const chklen_priv_id = &chklen_priv_id;
415
416
static int v_matchproto_(vdp_init_f)
417 6
xyzzy_chksha256_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
418
{
419
        struct vdp_chksha256_s *vdps;
420
        struct vmod_priv *p;
421
422 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
423 6
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
424 6
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
425 6
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
426 6
        AN(vdc->clen);
427 6
        AN(priv);
428
429 12
        WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_CHKSHA256_MAGIC);
430 6
        if (vdps == NULL)
431 0
                return (-1);
432 6
        VSHA256_Init(vdps->cx);
433
434 6
        p = VRT_priv_task_get(ctx, chksha256_priv_id);
435 6
        if (p == NULL)
436 0
                return (-1);
437
438 6
        assert(p->len == sizeof(struct vdp_chksha256_cfg_s));
439 6
        CAST_OBJ_NOTNULL(vdps->cfg, p->priv, VDP_CHKSHA256_CFG_MAGIC);
440 6
        *priv = vdps;
441
442 6
        return (0);
443 6
}
444
445
static int v_matchproto_(vdp_init_f)
446 6
xyzzy_chkcrc32_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
447
{
448
        struct vdp_chkcrc32_s *vdps;
449
        struct vmod_priv *p;
450
451 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
452 6
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
453 6
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
454 6
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
455 6
        AN(vdc->clen);
456 6
        AN(priv);
457
458 12
        WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_CHKCRC32_MAGIC);
459 6
        if (vdps == NULL)
460 0
                return (-1);
461 6
        vdps->crc = crc32(0L, Z_NULL, 0);
462
463 6
        p = VRT_priv_task_get(ctx, chkcrc32_priv_id);
464 6
        if (p == NULL)
465 0
                return (-1);
466
467 6
        assert(p->len == sizeof(struct vdp_chkcrc32_cfg_s));
468 6
        CAST_OBJ_NOTNULL(vdps->cfg, p->priv, VDP_CHKCRC32_CFG_MAGIC);
469 6
        *priv = vdps;
470
471 6
        return (0);
472 6
}
473
474
static int v_matchproto_(vdp_init_f)
475 6
xyzzy_chklen_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
476
{
477
        struct vdp_chklen_s *vdps;
478
        struct vmod_priv *p;
479
480 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
481 6
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
482 6
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
483 6
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
484 6
        AN(vdc->clen);
485 6
        AN(priv);
486
487 12
        WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_CHKLEN_MAGIC);
488 6
        if (vdps == NULL)
489 0
                return (-1);
490 6
        AZ(vdps->bytes);
491
492 6
        p = VRT_priv_task_get(ctx, chklen_priv_id);
493 6
        if (p == NULL)
494 0
                return (-1);
495
496 6
        assert(p->len == sizeof(struct vdp_chklen_cfg_s));
497 6
        CAST_OBJ_NOTNULL(vdps->cfg, p->priv, VDP_CHKLEN_CFG_MAGIC);
498 6
        *priv = vdps;
499
500 6
        return (0);
501 6
}
502
503
static int v_matchproto_(vdp_bytes_f)
504 18
xyzzy_chksha256_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
505
    const void *ptr, ssize_t len)
506
{
507
        struct vdp_chksha256_s *vdps;
508
509 18
        CAST_OBJ_NOTNULL(vdps, *priv, VDP_CHKSHA256_MAGIC);
510 18
        if (len != 0)
511 9
                VSHA256_Update(vdps->cx, ptr, len);
512 18
        vdps->called++;
513 18
        vdps->bytes += len;
514 18
        return (VDP_bytes(vdc, act, ptr, len));
515
}
516
517
static int v_matchproto_(vdp_bytes_f)
518 18
xyzzy_chkcrc32_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
519
    const void *ptr, ssize_t len)
520
{
521
        struct vdp_chkcrc32_s *vdps;
522
523 18
        CAST_OBJ_NOTNULL(vdps, *priv, VDP_CHKCRC32_MAGIC);
524 18
        if (len > 0)
525 9
                vdps->crc = crc32(vdps->crc, ptr, len);
526 18
        vdps->called++;
527 18
        vdps->bytes += len;
528 18
        return (VDP_bytes(vdc, act, ptr, len));
529
}
530
531
static int v_matchproto_(vdp_bytes_f)
532 18
xyzzy_chklen_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
533
    const void *ptr, ssize_t len)
534
{
535
        struct vdp_chklen_s *vdps;
536
537 18
        CAST_OBJ_NOTNULL(vdps, *priv, VDP_CHKLEN_MAGIC);
538 18
        vdps->called++;
539 18
        vdps->bytes += len;
540 18
        return (VDP_bytes(vdc, act, ptr, len));
541
}
542
543
static int v_matchproto_(vdp_fini_f)
544 6
xyzzy_chksha256_fini(struct vdp_ctx *vdc, void **priv)
545
{
546
        unsigned char digest[VSHA256_DIGEST_LENGTH];
547
        enum vdp_chk_mode_e mode;
548
        struct vdp_chksha256_s *vdps;
549
        struct vsb *vsb;
550
        int r;
551
552 6
        (void) vdc;
553 6
        AN(priv);
554 6
        if (*priv == NULL)
555 0
                return (0);
556 6
        TAKE_OBJ_NOTNULL(vdps, priv, VDP_CHKSHA256_MAGIC);
557
558 6
        VSHA256_Final(digest, vdps->cx);
559 6
        r = memcmp(digest, vdps->cfg->expected, sizeof digest);
560 6
        if (r == 0)
561 3
                return (0);
562
563 3
        mode = vdps->cfg->mode;
564 3
        if (mode == VDP_CHK_PANIC_UNLESS_ERROR)
565 0
                mode = (vdps->called == 0 || vdc->retval != 0) ? VDP_CHK_LOG : VDP_CHK_PANIC;
566
567 3
        if (mode == VDP_CHK_LOG) {
568 3
                VSLb(vdc->vsl, SLT_Debug, "sha256 checksum mismatch");
569
570 3
                vsb = VSB_new_auto();
571 3
                AN(vsb);
572 3
                VSB_quote(vsb, digest, sizeof digest, VSB_QUOTE_HEX);
573 3
                AZ(VSB_finish(vsb));
574 3
                VSLb(vdc->vsl, SLT_Debug, "got: %s", VSB_data(vsb));
575
576 3
                VSB_clear(vsb);
577 3
                VSB_quote(vsb, vdps->cfg->expected, sizeof digest, VSB_QUOTE_HEX);
578 3
                AZ(VSB_finish(vsb));
579 3
                VSLb(vdc->vsl, SLT_Debug, "exp: %s", VSB_data(vsb));
580 3
                VSB_destroy(&vsb);
581 3
        }
582 0
        else if (mode == VDP_CHK_PANIC)
583 0
                WRONG("body checksum");
584
        else
585 0
                WRONG("mode");
586
587 3
        return (0);
588 6
}
589
590
static int v_matchproto_(vdp_fini_f)
591 6
xyzzy_chkcrc32_fini(struct vdp_ctx *vdc, void **priv)
592
{
593
        enum vdp_chk_mode_e mode;
594
        struct vdp_chkcrc32_s *vdps;
595
596 6
        (void) vdc;
597 6
        AN(priv);
598 6
        if (*priv == NULL)
599 0
                return (0);
600 6
        TAKE_OBJ_NOTNULL(vdps, priv, VDP_CHKCRC32_MAGIC);
601
602 6
        if (vdps->crc == vdps->cfg->expected)
603 3
                return (0);
604
605 3
        mode = vdps->cfg->mode;
606 3
        if (mode == VDP_CHK_PANIC_UNLESS_ERROR)
607 0
                mode = (vdps->called == 0 || vdc->retval != 0) ? VDP_CHK_LOG : VDP_CHK_PANIC;
608
609 3
        if (mode == VDP_CHK_LOG) {
610 3
                VSLb(vdc->vsl, SLT_Debug, "crc32 checksum mismatch");
611 3
                VSLb(vdc->vsl, SLT_Debug, "got: %08x", vdps->crc);
612 3
                VSLb(vdc->vsl, SLT_Debug, "exp: %08x", vdps->cfg->expected);
613 3
        }
614 0
        else if (mode == VDP_CHK_PANIC)
615 0
                WRONG("body checksum");
616
        else
617 0
                WRONG("mode");
618
619 3
        return (0);
620 6
}
621
622
static int v_matchproto_(vdp_fini_f)
623 6
xyzzy_chklen_fini(struct vdp_ctx *vdc, void **priv)
624
{
625
        enum vdp_chk_mode_e mode;
626
        struct vdp_chklen_s *vdps;
627
628 6
        (void) vdc;
629 6
        AN(priv);
630 6
        if (*priv == NULL)
631 0
                return (0);
632 6
        TAKE_OBJ_NOTNULL(vdps, priv, VDP_CHKLEN_MAGIC);
633
634 6
        if (vdps->bytes == vdps->cfg->expected)
635 3
                return (0);
636
637 3
        mode = vdps->cfg->mode;
638 3
        if (mode == VDP_CHK_PANIC_UNLESS_ERROR)
639 0
                mode = (vdps->called == 0 || vdc->retval != 0) ? VDP_CHK_LOG : VDP_CHK_PANIC;
640
641 3
        if (mode == VDP_CHK_LOG) {
642 3
                VSLb(vdc->vsl, SLT_Debug, "length mismatch");
643 3
                VSLb(vdc->vsl, SLT_Debug, "got: %zd", vdps->bytes);
644 3
                VSLb(vdc->vsl, SLT_Debug, "exp: %zd", vdps->cfg->expected);
645 3
        }
646 0
        else if (mode == VDP_CHK_PANIC)
647 0
                WRONG("body length");
648
        else
649 0
                WRONG("mode");
650
651 3
        return (0);
652 6
}
653
654
static const struct vdp xyzzy_vdp_chksha256 = {
655
        .name  = "debug.chksha256",
656
        .init  = xyzzy_chksha256_init,
657
        .bytes = xyzzy_chksha256_bytes,
658
        .fini  = xyzzy_chksha256_fini,
659
};
660
661
static const struct vdp xyzzy_vdp_chkcrc32 = {
662
        .name  = "debug.chkcrc32",
663
        .init  = xyzzy_chkcrc32_init,
664
        .bytes = xyzzy_chkcrc32_bytes,
665
        .fini  = xyzzy_chkcrc32_fini,
666
};
667
668
static const struct vdp xyzzy_vdp_chklen = {
669
        .name  = "debug.chklen",
670
        .init  = xyzzy_chklen_init,
671
        .bytes = xyzzy_chklen_bytes,
672
        .fini  = xyzzy_chklen_fini,
673
};
674
675
#define chkcfg(ws, cfg, magic, id, mode_e) do {                                                 \
676
        struct vmod_priv *p = VRT_priv_task(ctx, id);                                           \
677
                                                                                                \
678
        XXXAN(p);                                                                               \
679
        if (p->priv == NULL) {                                                                  \
680
                p->priv = WS_Alloc(ws, sizeof *cfg);                                            \
681
                p->len = sizeof *cfg;                                                           \
682
        }                                                                                       \
683
        AN(p->priv);                                                                            \
684
        cfg = p->priv;                                                                          \
685
        INIT_OBJ(cfg, magic);                                                                   \
686
        if (mode_e == VENUM(log))                                                               \
687
                cfg->mode = VDP_CHK_LOG;                                                        \
688
        else if (mode_e == VENUM(panic))                                                        \
689
                cfg->mode = VDP_CHK_PANIC;                                                      \
690
        else if (mode_e == VENUM(panic_unless_error))                                           \
691
                cfg->mode = VDP_CHK_PANIC_UNLESS_ERROR;                                         \
692
        else                                                                                    \
693
                WRONG("mode");                                                                  \
694
} while(0)
695
696
VCL_VOID v_matchproto_(td_xyzzy_debug_chksha256)
697 6
xyzzy_chksha256(VRT_CTX, VCL_BLOB blob, VCL_ENUM mode_e)
698
{
699
        struct vdp_chksha256_cfg_s *cfg;
700
        size_t l;
701
702 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
703 6
        CHECK_OBJ_NOTNULL(blob, VRT_BLOB_MAGIC);
704 6
        XXXAN(blob->blob);
705 6
        XXXAN(blob->len);
706
707 6
        chkcfg(ctx->ws, cfg, VDP_CHKSHA256_CFG_MAGIC, chksha256_priv_id, mode_e);
708
709 6
        l = blob->len;
710 6
        if (l > sizeof cfg->expected)
711 0
                l = sizeof cfg->expected;
712 6
        memcpy(cfg->expected, blob->blob, l);
713
714 6
}
715
716
VCL_VOID v_matchproto_(td_xyzzy_debug_chkcrc32)
717 6
xyzzy_chkcrc32(VRT_CTX, VCL_INT expected, VCL_ENUM mode_e)
718
{
719
        struct vdp_chkcrc32_cfg_s *cfg;
720
721 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
722
723 6
        chkcfg(ctx->ws, cfg, VDP_CHKCRC32_CFG_MAGIC, chkcrc32_priv_id, mode_e);
724
725 6
        if (expected < 0)
726 0
                expected = 0;
727 6
        cfg->expected = (uintmax_t)expected % UINT32_MAX;
728 6
}
729
730
VCL_VOID v_matchproto_(td_xyzzy_debug_chklen)
731 6
xyzzy_chklen(VRT_CTX, VCL_BYTES expected, VCL_ENUM mode_e)
732
{
733
        struct vdp_chklen_cfg_s *cfg;
734
735 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
736
737 6
        chkcfg(ctx->ws, cfg, VDP_CHKLEN_CFG_MAGIC, chklen_priv_id, mode_e);
738
739 6
        cfg->expected = expected;
740 6
}
741
742
/**********************************************************************
743
 * reserve thread_workspace
744
 */
745
746
static int v_matchproto_(vdp_init_f)
747 3
xyzzy_awshog_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
748
{
749
        struct ws *aws;
750
        unsigned u;
751
752 3
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
753 3
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
754 3
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
755 3
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
756 3
        AN(vdc->clen);
757 3
        AN(priv);
758
759 3
        if (ctx->req != NULL)
760 0
                aws = ctx->req->wrk->aws;
761 3
        else if (ctx->bo != NULL)
762 3
                aws = ctx->bo->wrk->aws;
763
        else
764 0
                WRONG("neither req nor bo");
765
766 3
        u = WS_ReserveAll(aws);
767 3
        WS_Release(aws, 0);
768 3
        (void) WS_Alloc(aws, u);
769 3
        return (1);
770
}
771
772
static const struct vdp xyzzy_vdp_awshog = {
773
        .name  = "debug.awshog",
774
        .init  = xyzzy_awshog_init
775
};
776
777
/**********************************************************************
778
 * send a fixed string
779
 */
780
781
static const void * const string_priv_id = &string_priv_id;
782
783
static int v_matchproto_(vdp_init_f)
784 24
xyzzy_string_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
785
{
786
        struct vmod_priv *p;
787
788 24
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
789 24
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
790 24
        CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC);
791 24
        CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC);
792 24
        AN(vdc->clen);
793
794 24
        AN(priv);
795 24
        p = VRT_priv_task_get(ctx, string_priv_id);
796 24
        if (p == NULL || p->priv == NULL) {
797 12
                *priv = TRUST_ME("");
798 12
                *vdc->clen = 0;
799 12
                return (0);
800
        }
801 12
        AN(p->priv);
802 12
        *priv = p->priv;
803 12
        *vdc->clen = vstrlen(*priv);
804 12
        return (0);
805 24
}
806
807
static int v_matchproto_(vdp_bytes_f)
808 18
xyzzy_string_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
809
    const void *ptr, ssize_t len)
810
{
811
        int r;
812
813 18
        (void)act;
814 18
        AN(priv);
815 18
        (void)ptr;
816 18
        (void)len;
817
818 18
        r = VDP_bytes(vdc, VDP_END, *priv, vstrlen(*priv));
819 18
        if (r != 0)
820 0
                return (r);
821
        // only to be called once
822 18
        return (1);
823 18
}
824
825
static int v_matchproto_(vdp_fini_f)
826 24
xyzzy_string_fini(struct vdp_ctx *vdc, void **priv)
827
{
828 24
        (void)vdc;
829 24
        AN(priv);
830 24
        *priv = NULL;
831 24
        return (0);
832
}
833
834
static const struct vdp xyzzy_vdp_string = {
835
        .name  = "debug.string",
836
        .init  = xyzzy_string_init,
837
        .bytes = xyzzy_string_bytes,
838
        .fini = xyzzy_string_fini,
839
};
840
841
VCL_VOID v_matchproto_(td_xyzzy_debug_body_string)
842 12
xyzzy_body_string(VRT_CTX, VCL_STRING s)
843
{
844
        struct vmod_priv *p;
845
846 12
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
847 12
        p = VRT_priv_task(ctx, string_priv_id);
848 12
        if (p == NULL)
849 0
                return;
850 12
        p->priv = TRUST_ME(s);
851 12
}
852
853
/**********************************************************************/
854
855
static int v_matchproto_(vdp_init_f)
856 6
xyzzy_vdp_body_prefix_init(VRT_CTX, struct vdp_ctx *vdc, void **priv)
857
{
858
        struct xyzzy_bp_string *bps;
859
        struct xyzzy_bp *bp;
860
        struct vmod_priv *task;
861
        intmax_t l;
862
863 6
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
864 6
        CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC);
865 6
        AN(vdc->clen);
866
867 6
        task = VRT_priv_task_get(ctx, priv_task_id_bp);
868 6
        if (task == NULL)
869 0
                return (1);
870 6
        CAST_OBJ_NOTNULL(bp, task->priv, XYZZY_BP_MAGIC);
871 6
        AN(priv);
872 6
        AZ(*priv);
873 6
        *priv = bp;
874
875 6
        if (*vdc->clen < 0)
876 0
                return (0);
877
878 6
        l = 0;
879 18
        VSTAILQ_FOREACH(bps, &bp->head, list)
880 12
                l += vstrlen(bps->s);
881 6
        *vdc->clen += l;
882
883 6
        return (0);
884 6
}
885
886
static int v_matchproto_(vdp_bytes_f)
887 12
xyzzy_vdp_body_prefix_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv,
888
    const void *ptr, ssize_t len)
889
{
890
        struct xyzzy_bp_string *bps;
891
        struct xyzzy_bp *bp;
892
893 12
        AN(priv);
894 12
        CAST_OBJ_NOTNULL(bp, *priv, XYZZY_BP_MAGIC);
895
896 24
        while ((bps = VSTAILQ_FIRST(&bp->head)) != NULL) {
897 12
                VSTAILQ_REMOVE_HEAD(&bp->head, list);
898 12
                if (VDP_bytes(vdc, VDP_NULL, bps->s, vstrlen(bps->s)))
899 0
                        return (vdc->retval);
900
        }
901
902 12
        return (VDP_bytes(vdc, act, ptr, len));
903 12
}
904
905
static int v_matchproto_(vdp_fini_f)
906 6
xyzzy_vdp_body_prefix_fini(struct vdp_ctx *vdc, void **priv)
907
{
908 6
        (void)vdc;
909 6
        AN(priv);
910 6
        *priv = NULL;
911 6
        return (0);
912
}
913
914
static const struct vdp xyzzy_vdp_body_prefix = {
915
        .name  = "debug.body_prefix",
916
        .init  = xyzzy_vdp_body_prefix_init,
917
        .bytes = xyzzy_vdp_body_prefix_bytes,
918
        .fini = xyzzy_vdp_body_prefix_fini
919
};
920
921
void
922 312
debug_add_filters(VRT_CTX)
923
{
924 312
        AZ(VRT_AddFilter(ctx, &xyzzy_vfp_slow, &xyzzy_vdp_slow));
925 312
        AZ(VRT_AddFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13));
926 312
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_pedantic));
927 312
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_chunked));
928 312
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_chksha256));
929 312
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_chkcrc32));
930 312
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_chklen));
931 312
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_awshog));
932 312
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_string));
933 312
        AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_body_prefix));
934 312
}
935
936
void
937 69
debug_remove_filters(VRT_CTX)
938
{
939 69
        VRT_RemoveFilter(ctx, &xyzzy_vfp_slow, &xyzzy_vdp_slow);
940 69
        VRT_RemoveFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13);
941 69
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_pedantic);
942 69
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_chunked);
943 69
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_chksha256);
944 69
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_chkcrc32);
945 69
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_chklen);
946 69
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_awshog);
947 69
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_string);
948 69
        VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_body_prefix);
949 69
}