varnish-cache/bin/varnishd/cache/cache_vrt.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
 * Runtime support for compiled VCL programs
31
 */
32
33
#include "config.h"
34
35
#include <stdlib.h>
36
37
#include "cache_varnishd.h"
38
39
#include "cache_objhead.h"
40
#include "vav.h"
41
#include "vcl.h"
42
#include "vct.h"
43
#include "venc.h"
44
#include "vend.h"
45
#include "vrt_obj.h"
46
#include "vsa.h"
47
#include "vsha256.h"
48
#include "vtcp.h"
49
#include "vtim.h"
50
#include "vcc_interface.h"
51
52
#include "common/heritage.h"
53
#include "common/vsmw.h"
54
#include "proxy/cache_proxy.h"
55
56
// NOT using TOSTRANDS() to create a NULL pointer element despite n == 0
57
const struct strands *const vrt_null_strands = &(struct strands){
58
        .magic = STRANDS_MAGIC,
59
        .n = 0,
60
        .p = (const char *[1]){NULL}
61
};
62
const struct vrt_blob *const vrt_null_blob = &(struct vrt_blob){
63
        .magic = VRT_BLOB_MAGIC,
64
        .type = VRT_NULL_BLOB_TYPE,
65
        .len = 0,
66
        .blob = "\0"
67
};
68
69
/*--------------------------------------------------------------------*/
70
71
VCL_VOID
72 371
VRT_synth(VRT_CTX, VCL_INT code, VCL_STRING reason)
73
{
74
        const char *ret;
75
76 371
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
77 371
        assert(ctx->req != NULL || ctx->bo != NULL);
78
79 371
        ret = ctx->req == NULL ? "error" : "synth";
80 371
        if (code < 0) {
81 0
                VRT_fail(ctx, "return(%s()) status code (%jd) is negative",
82 0
                    ret, (intmax_t)code);
83 0
                return;
84
        }
85 371
        if (code > 65535) {
86 0
                VRT_fail(ctx, "return(%s()) status code (%jd) > 65535",
87 0
                    ret, (intmax_t)code);
88 0
                return;
89
        }
90 371
        if ((code % 1000) < 100) {
91 8
                VRT_fail(ctx,
92
                    "illegal return(%s()) status code (%jd) (..0##)",
93 4
                    ret, (intmax_t)code);
94 4
                return;
95
        }
96
97 367
        if (reason && !WS_Allocated(ctx->ws, reason, -1)) {
98 44
                reason = WS_Copy(ctx->ws, reason, -1);
99 44
                if (!reason) {
100 0
                        VRT_fail(ctx, "Workspace overflow");
101 0
                        return;
102
                }
103 44
        }
104
105 367
        if (ctx->req == NULL) {
106 12
                CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
107 12
                ctx->bo->err_code = (uint16_t)code;
108 12
                ctx->bo->err_reason = reason ? reason
109 9
                    : http_Status2Reason(ctx->bo->err_code % 1000, NULL);
110 12
                return;
111
        }
112
113 355
        ctx->req->err_code = (uint16_t)code;
114 355
        ctx->req->err_reason = reason ? reason
115 255
            : http_Status2Reason(ctx->req->err_code % 1000, NULL);
116 371
}
117
118
/*--------------------------------------------------------------------*/
119
120
void
121 117
VPI_acl_log(VRT_CTX, const char *msg)
122
{
123
124 117
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
125 117
        AN(msg);
126 117
        if (ctx->vsl != NULL)
127 117
                VSLbs(ctx->vsl, SLT_VCL_acl, TOSTRAND(msg));
128
        else
129 0
                VSL(SLT_VCL_acl, NO_VXID, "%s", msg);
130 117
}
131
132
int
133 96492
VRT_acl_match(VRT_CTX, VCL_ACL acl, VCL_IP ip)
134
{
135
136 96492
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
137 96492
        if (acl == NULL || ip == NULL) {
138 6
                VRT_fail(ctx, "Cannot match a null %s",
139 3
                         acl == NULL ? "ACL" : "IP address");
140 3
                return (0);
141
        }
142 96489
        CHECK_OBJ(acl, VRT_ACL_MAGIC);
143 96489
        assert(VSA_Sane(ip));
144 96489
        return (acl->match(ctx, ip));
145 96492
}
146
147
static int
148 208
acl_tbl_cmp(int fam, const uint8_t *key, const uint8_t *b)
149
{
150
        int rv;
151
152 208
        rv = fam - (int)b[3];
153 208
        if (rv == 0 && b[1] > 0)
154 144
                rv = memcmp(key, b + 4, b[1]);
155 208
        if (rv == 0 && b[2])
156 118
                rv = (int)(key[b[1]] & b[2]) - (int)b[4 + b[1]];
157 208
        return (rv);
158
}
159
160
static const uint8_t *
161 96
bbsearch(int fam, const uint8_t *key, const uint8_t *base0,
162
    size_t nmemb, size_t size)
163
{
164 96
        const uint8_t *base = base0;
165
        size_t lim;
166
        int cmp;
167
        const uint8_t *p;
168
169 276
        for (lim = nmemb; lim != 0; lim >>= 1) {
170 208
                p = base + (lim >> 1) * size;
171 208
                cmp = acl_tbl_cmp(fam, key, p);
172 208
                if (cmp == 0)
173 28
                        return (p);
174 180
                if (cmp > 0) {
175
                        /* key > p: move right */
176 76
                        base = p + size;
177 76
                        lim--;
178 76
                } /* else move left */
179 180
        }
180 68
        return (NULL);
181 96
}
182
183
int
184 96
VPI_acl_table(VRT_CTX, VCL_IP p, unsigned n, unsigned m, const uint8_t *tbl,
185
    const char * const *str, const char *fin)
186
{
187
        int fam;
188
        const uint8_t *key;
189
        const uint8_t *ptr;
190
        size_t sz;
191
192 96
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
193 96
        AN(p);
194 96
        AN(n);
195 96
        assert(m == 20);
196 96
        AN(tbl);
197 96
        AN(fin);
198
199 96
        fam = VRT_VSA_GetPtr(ctx, p, &key);
200 96
        ptr = bbsearch(fam, key, tbl, n, m);
201
202 96
        if (ptr != NULL) {
203 28
                sz = ptr - tbl;
204 28
                AZ(sz % m);
205 28
                sz /= m;
206 28
                if (str != NULL)
207 14
                        VPI_acl_log(ctx, str[sz]);
208 28
                return (*ptr);
209
        }
210 68
        if (str != NULL)
211 34
                VPI_acl_log(ctx, fin);
212 68
        return (0);
213 96
}
214
215
/*--------------------------------------------------------------------*/
216
217
VCL_VOID
218 22
VRT_hit_for_pass(VRT_CTX, VCL_DURATION d)
219
{
220
        struct objcore *oc;
221
222 22
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
223 22
        if (ctx->bo == NULL) {
224 0
                VSLb(ctx->vsl, SLT_Error,
225
                    "Note: Ignoring DURATION argument to return(pass);");
226 0
                return;
227
        }
228 22
        CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
229 22
        oc = ctx->bo->fetch_objcore;
230 22
        oc->ttl = d;
231 22
        oc->grace = 0.0;
232 22
        oc->keep = 0.0;
233 44
        VSLb(ctx->vsl, SLT_TTL, "HFP %.0f %.0f %.0f %.0f uncacheable",
234 22
            oc->ttl, oc->grace, oc->keep, oc->t_origin);
235 22
}
236
237
/*--------------------------------------------------------------------*/
238
239
VCL_HTTP
240 32702
VRT_selecthttp(VRT_CTX, enum gethdr_e where)
241
{
242
        VCL_HTTP hp;
243
244 32702
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
245 32702
        switch (where) {
246
        case HDR_REQ:
247 19698
                hp = ctx->http_req;
248 19698
                break;
249
        case HDR_REQ_TOP:
250 7
                hp = ctx->http_req_top;
251 7
                break;
252
        case HDR_BEREQ:
253 509
                hp = ctx->http_bereq;
254 509
                break;
255
        case HDR_BERESP:
256 9095
                hp = ctx->http_beresp;
257 9095
                break;
258
        case HDR_RESP:
259 3392
                hp = ctx->http_resp;
260 3392
                break;
261
        case HDR_OBJ:
262 1
                hp = NULL;
263 1
                break;
264
        default:
265 0
                WRONG("VRT_selecthttp 'where' invalid");
266 0
        }
267 32702
        return (hp);
268
}
269
270
/*--------------------------------------------------------------------*/
271
272
VCL_STRING
273 25754
VRT_GetHdr(VRT_CTX, VCL_HEADER hs)
274
{
275
        VCL_HTTP hp;
276
        const char *p;
277
278 25754
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
279 25754
        if (hs->where == HDR_OBJ) {
280 14
                CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
281 14
                CHECK_OBJ_NOTNULL(ctx->req->objcore, OBJCORE_MAGIC);
282 28
                return (HTTP_GetHdrPack(ctx->req->wrk, ctx->req->objcore,
283 14
                    hs->what));
284
        }
285 25740
        hp = VRT_selecthttp(ctx, hs->where);
286 25740
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
287 25740
        if (!http_GetHdr(hp, hs->what, &p))
288 11911
                return (NULL);
289 13829
        return (p);
290 25754
}
291
292
/*--------------------------------------------------------------------
293
 * Alloc Strands with space for n elements on workspace
294
 *
295
 * Error handling is deliberately left to the caller
296
 */
297
298
struct strands *
299 0
VRT_AllocStrandsWS(struct ws *ws, int n)
300
{
301
        struct strands *s;
302
        const char **p;
303
304 0
        s = WS_Alloc(ws, sizeof *s);
305 0
        p = WS_Alloc(ws, n * sizeof *p);
306
307 0
        if (s == NULL || p == NULL)
308 0
                return (NULL);
309
310 0
        s->magic = STRANDS_MAGIC;
311 0
        s->n = n;
312 0
        s->p = p;
313
314 0
        return (s);
315 0
}
316
317
/*--------------------------------------------------------------------
318
 * Compare two STRANDS
319
 */
320
321
int
322 185
VRT_CompareStrands(VCL_STRANDS a, VCL_STRANDS b)
323
{
324 185
        const char *pa = NULL, *pb = NULL;
325 185
        int na = 0, nb = 0;
326
327 185
        CHECK_OBJ_NOTNULL(a, STRANDS_MAGIC);
328 185
        CHECK_OBJ_NOTNULL(b, STRANDS_MAGIC);
329
330 1231
        while (1) {
331 1231
                if (pa != NULL && *pa == '\0')
332 110
                        pa = NULL;
333 1231
                if (pb != NULL && *pb == '\0')
334 147
                        pb = NULL;
335 1231
                if (pa == NULL && na < a->n)
336 252
                        pa = a->p[na++];
337 979
                else if (pb == NULL && nb < b->n)
338 295
                        pb = b->p[nb++];
339 684
                else if (pa == NULL && pb == NULL)
340 62
                        return (0);
341 622
                else if (pa == NULL)
342 44
                        return (-1);
343 578
                else if (pb == NULL)
344 12
                        return (1);
345 566
                else if (*pa == '\0')
346 0
                        pa = NULL;
347 566
                else if (*pb == '\0')
348 0
                        pb = NULL;
349 566
                else if (*pa != *pb)
350 67
                        return (*pa - *pb);
351
                else {
352 499
                        pa++;
353 499
                        pb++;
354
                }
355
        }
356 185
}
357
358
/*--------------------------------------------------------------------
359
 * STRANDS to BOOL
360
 */
361
362
VCL_BOOL
363 13861
VRT_Strands2Bool(VCL_STRANDS s)
364
{
365
        int i;
366
367 13861
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
368 21681
        for (i = 0; i < s->n; i++)
369 13861
                if (s->p[i] != NULL)
370 6041
                        return (1);
371 7820
        return (0);
372 13861
}
373
374
/*--------------------------------------------------------------------
375
 * Hash a STRANDS
376
 */
377
378
uint32_t
379 1726
VRT_HashStrands32(VCL_STRANDS s)
380
{
381
        struct VSHA256Context sha_ctx;
382
        unsigned char sha256[VSHA256_LEN];
383
        const char *p;
384
        int i;
385
386 1726
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
387 1726
        VSHA256_Init(&sha_ctx);
388 5138
        for (i = 0; i < s->n; i++) {
389 3412
                p = s->p[i];
390 3412
                if (p != NULL && *p != '\0')
391 3408
                        VSHA256_Update(&sha_ctx, p, strlen(p));
392 3412
        }
393 1726
        VSHA256_Final(sha256, &sha_ctx);
394
395
        /* NB: for some reason vmod_director's shard director specifically
396
         * relied on little-endian decoding of the last 4 octets. In order
397
         * to maintain a stable hash function to share across consumers we
398
         * need to stick to that.
399
         */
400 1726
        return (vle32dec(sha256 + VSHA256_LEN - 4));
401
}
402
403
404
/*--------------------------------------------------------------------
405
 * Collapse STRANDS into the space provided, or return NULL
406
 */
407
408
char *
409 4822
VRT_Strands(char *d, size_t dl, VCL_STRANDS s)
410
{
411
        char *b;
412
        const char *e;
413
        unsigned x;
414
415 4822
        AN(d);
416 4822
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
417 4822
        b = d;
418 4822
        e = b + dl;
419 9680
        for (int i = 0; i < s->n; i++)
420 9556
                if (s->p[i] != NULL && *s->p[i] != '\0') {
421 4698
                        x = strlen(s->p[i]);
422 4698
                        if (b + x >= e)
423 56
                                return (NULL);
424 4642
                        memcpy(b, s->p[i], x);
425 4642
                        b += x;
426 4642
                }
427 4766
        assert(b < e);
428 4766
        *b++ = '\0';
429 4766
        return (b);
430 4822
}
431
432
/*--------------------------------------------------------------------
433
 * Copy and merge STRANDS into a workspace.
434
 */
435
436
VCL_STRING
437 487
VRT_StrandsWS(struct ws *ws, const char *h, VCL_STRANDS s)
438
{
439 487
        const char *q = NULL;
440
        struct vsb vsb[1];
441
        int i;
442
443 487
        WS_Assert(ws);
444 487
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
445
446 514
        for (i = 0; i < s->n; i++) {
447 505
                if (s->p[i] != NULL && *s->p[i] != '\0') {
448 478
                        q = s->p[i];
449 478
                        break;
450
                }
451 27
        }
452
453 487
        if (q == NULL) {
454 9
                if (h == NULL)
455 8
                        return ("");
456 1
                if (WS_Allocated(ws, h, -1))
457 0
                        return (h);
458 479
        } else if (h == NULL && WS_Allocated(ws, q, -1)) {
459 46
                for (i++; i < s->n; i++)
460 29
                        if (s->p[i] != NULL && *s->p[i] != '\0')
461 19
                                break;
462 36
                if (i == s->n)
463 17
                        return (q);
464 19
        }
465
466 462
        WS_VSB_new(vsb, ws);
467 462
        if (h != NULL)
468 283
                VSB_cat(vsb, h);
469 1055
        for (i = 0; i < s->n; i++) {
470 593
                if (s->p[i] != NULL && *s->p[i] != '\0')
471 558
                        VSB_cat(vsb, s->p[i]);
472 593
        }
473 462
        return (WS_VSB_finish(vsb, ws, NULL));
474 487
}
475
476
/*--------------------------------------------------------------------
477
 * Copy and merge STRANDS on the current workspace
478
 */
479
480
VCL_STRING
481 77
VRT_STRANDS_string(VRT_CTX, VCL_STRANDS s)
482
{
483
        const char *b;
484
485 77
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
486 77
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
487 77
        b = VRT_StrandsWS(ctx->ws, NULL, s);
488 77
        if (b == NULL)
489 1
                VRT_fail(ctx, "Workspace overflow");
490 77
        return (b);
491
}
492
493
/*--------------------------------------------------------------------
494
 * upper/lower-case STRANDS (onto workspace)
495
 */
496
497
#include <stdio.h>
498
499
VCL_STRING
500 11
VRT_UpperLowerStrands(VRT_CTX, VCL_STRANDS s, int up)
501
{
502
        unsigned u;
503
        char *b, *e, *r;
504 11
        const char *p, *q = NULL;
505 11
        int i, copy = 0;
506
507 11
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
508 11
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
509 11
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
510 11
        u = WS_ReserveAll(ctx->ws);
511 11
        r = b = WS_Reservation(ctx->ws);
512 11
        e = b + u;
513 26
        for (i = 0; i < s->n; i++) {
514 15
                if (s->p[i] == NULL || s->p[i][0] == '\0')
515 0
                        continue;
516 15
                if (q != NULL)
517 4
                        copy = 1;
518 84
                for(p = q = s->p[i]; *p != '\0'; p++) {
519 95
                        if ((up && vct_islower(*p)) ||
520 61
                            (!up && vct_isupper(*p))) {
521 34
                                *b++ = *p ^ 0x20;
522 34
                                copy = 1;
523 69
                        } else if (b < e) {
524 35
                                *b++ = *p;
525 35
                        }
526 69
                        if (copy && b == e)
527 0
                                break;
528 69
                }
529 15
                if (copy && b == e) {
530 0
                        WS_Release(ctx->ws, 0);
531 0
                        VRT_fail(ctx, "Workspace overflow");
532 0
                        return (NULL);
533
                }
534 15
        }
535 11
        assert(b <= e);
536 11
        if (!copy) {
537 3
                WS_Release(ctx->ws, 0);
538 3
                return (q);
539
        }
540 8
        assert(b < e);
541 8
        *b++ = '\0';
542 8
        assert(b <= e);
543 8
        WS_ReleaseP(ctx->ws, b);
544 8
        return (r);
545 11
}
546
547
548
// rfc9110,l,1585,1589
549
//     field-content  = field-vchar
550
//                      [ 1*( SP / HTAB / field-vchar ) field-vchar ]
551
//     field-vchar    = VCHAR / obs-text
552
//     obs-text       = %x80-FF
553
//
554
// This implementation is less strict, see #4221
555
static inline VCL_BOOL
556 4767
validhdr(const char *p)
557
{
558 4767
        AN(p);
559 188661
        for(;*p != '\0'; p++)
560 183896
                if (! vct_ishdrval(*p))
561 2
                        return (0);
562 4765
        return (1);
563 4767
}
564
565
/*--------------------------------------------------------------------*/
566
VCL_BOOL
567 2
VRT_ValidHdr(VRT_CTX, VCL_STRANDS s)
568
{
569
        int i;
570
571 2
        (void) ctx;
572
573 2
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
574 3
        for (i = 0; i < s->n; i++) {
575 2
                if (s->p[i] == NULL || s->p[i][0] == '\0')
576 0
                        continue;
577 2
                if (! validhdr(s->p[i]))
578 1
                        return (0);
579 1
        }
580
581 1
        return (1);
582 2
}
583
/*--------------------------------------------------------------------*/
584
585
VCL_VOID
586 1992
VRT_UnsetHdr(VRT_CTX, VCL_HEADER hs)
587
{
588
        VCL_HTTP hp;
589
590 1992
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
591 1992
        AN(hs);
592 1992
        AN(hs->what);
593 1992
        hp = VRT_selecthttp(ctx, hs->where);
594 1992
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
595 1992
        http_Unset(hp, hs->what);
596 1992
}
597
598
VCL_VOID
599 4951
VRT_SetHdr(VRT_CTX, VCL_HEADER hs, const char *pfx, VCL_STRANDS s)
600
{
601
        VCL_HTTP hp;
602
        unsigned u, l, pl;
603
        char *p, *b;
604
605 4951
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
606 4951
        AN(hs);
607 4951
        AN(hs->what);
608 4951
        hp = VRT_selecthttp(ctx, hs->where);
609 4951
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
610
611 4951
        u = WS_ReserveAll(hp->ws);
612 4951
        pl = (pfx == NULL) ? 0 : strlen(pfx);
613 4951
        l = hs->what->len + 1 + pl;
614 4951
        if (u <= l) {
615 127
                WS_Release(hp->ws, 0);
616 127
                WS_MarkOverflow(hp->ws);
617 127
                VSLbs(ctx->vsl, SLT_LostHeader, TOSTRAND(hs->what->str));
618 127
                return;
619
        }
620 4824
        b = WS_Reservation(hp->ws);
621 4824
        if (s != NULL) {
622 4816
                p = VRT_Strands(b + l, u - l, s);
623 4816
                if (p == NULL) {
624 56
                        WS_Release(hp->ws, 0);
625 56
                        WS_MarkOverflow(hp->ws);
626 112
                        VSLbs(ctx->vsl, SLT_LostHeader,
627 56
                            TOSTRAND(hs->what->str));
628 56
                        return;
629
                }
630 4760
        } else {
631 8
                b[l] = '\0';
632
        }
633 4768
        p = b;
634 4768
        memcpy(p, hs->what->str, hs->what->len);
635 4768
        p += hs->what->len;
636 4768
        *p++ = ' ';
637 4768
        if (pfx != NULL)
638 10
                memcpy(p, pfx, pl);
639 4768
        p += pl;
640 4768
        if (FEATURE(FEATURE_VALIDATE_HEADERS) && !validhdr(b)) {
641 1
                VRT_fail(ctx, "Bad header %s", b);
642 1
                WS_Release(hp->ws, 0);
643 1
                return;
644
        }
645 4767
        WS_ReleaseP(hp->ws, strchr(p, '\0') + 1);
646 4767
        http_Unset(hp, hs->what);
647 4767
        http_SetHeader(hp, b);
648 4951
}
649
650
/*--------------------------------------------------------------------*/
651
652
VCL_VOID
653 20412
VRT_handling(VRT_CTX, unsigned hand)
654
{
655
656 20412
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
657 20412
        assert(hand != VCL_RET_FAIL);
658 20412
        AN(ctx->vpi);
659 20412
        AZ(ctx->vpi->handling);
660 20412
        assert(hand > 0);
661 20412
        assert(hand < VCL_RET_MAX);
662 20412
        ctx->vpi->handling = hand;
663 20412
}
664
665
unsigned
666 15
VRT_handled(VRT_CTX)
667
{
668 15
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
669 15
        AN(ctx->vpi);
670 15
        return (ctx->vpi->handling);
671
}
672
673
/* the trace value is cached in the VPI for efficiency */
674
VCL_VOID
675 1
VRT_trace(VRT_CTX, VCL_BOOL a)
676
{
677 1
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
678 1
        AN(ctx->vpi);
679 1
        ctx->vpi->trace = a;
680 1
}
681
682
/*--------------------------------------------------------------------*/
683
684
VCL_VOID
685 203
VRT_fail(VRT_CTX, const char *fmt, ...)
686
{
687
        va_list ap;
688
689 203
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
690 203
        assert(ctx->vsl != NULL || ctx->msg != NULL);
691 203
        AN(ctx->vpi);
692 203
        if (ctx->vpi->handling == VCL_RET_FAIL)
693 3
                return;
694 200
        AZ(ctx->vpi->handling);
695 200
        AN(fmt);
696 200
        AZ(strchr(fmt, '\n'));
697 200
        va_start(ap, fmt);
698 200
        if (ctx->vsl != NULL) {
699 159
                VSLbv(ctx->vsl, SLT_VCL_Error, fmt, ap);
700 159
        } else {
701 41
                AN(ctx->msg);
702 41
                VSB_vprintf(ctx->msg, fmt, ap);
703 41
                VSB_putc(ctx->msg, '\n');
704
        }
705 200
        va_end(ap);
706 200
        ctx->vpi->handling = VCL_RET_FAIL;
707 203
}
708
709
/*--------------------------------------------------------------------
710
 * Feed data into the hash calculation
711
 */
712
713
VCL_VOID
714 7328
VRT_hashdata(VRT_CTX, VCL_STRANDS s)
715
{
716
        int i;
717
718 7328
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
719 7328
        CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
720 7328
        AN(ctx->specific);
721 7328
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
722 14659
        for (i = 0; i < s->n; i++)
723 7331
                HSH_AddString(ctx->req, ctx->specific, s->p[i]);
724
        /*
725
         * Add a 'field-separator' to make it more difficult to
726
         * manipulate the hash.
727
         */
728 7328
        HSH_AddString(ctx->req, ctx->specific, NULL);
729 7328
}
730
731
/*--------------------------------------------------------------------*/
732
733
VCL_TIME
734 160
VRT_r_now(VRT_CTX)
735
{
736 160
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
737 160
        return (ctx->now);
738
}
739
740
/*--------------------------------------------------------------------*/
741
742
VCL_STRING v_matchproto_()
743 248
VRT_IP_string(VRT_CTX, VCL_IP ip)
744
{
745
        char buf[VTCP_ADDRBUFSIZE];
746
747 248
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
748 248
        if (ip == NULL) {
749 0
                VRT_fail(ctx, "%s: Illegal IP", __func__);
750 0
                return (NULL);
751
        }
752 248
        VTCP_name(ip, buf, sizeof buf, NULL, 0);
753 248
        return (WS_Copy(ctx->ws, buf, -1));
754 248
}
755
756
int
757 2831
VRT_INT_is_valid(VCL_INT arg)
758
{
759 2831
        return (arg >= VRT_INTEGER_MIN && arg <= VRT_INTEGER_MAX);
760
}
761
762
763
VCL_STRING v_matchproto_()
764 2831
VRT_INT_string(VRT_CTX, VCL_INT num)
765
{
766
767 2831
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
768 2831
        if (!VRT_INT_is_valid(num))
769 2
                VRT_fail(ctx, "INT overflow converting to string (0x%jx)",
770 1
                    (intmax_t)num);
771 2831
        return (WS_Printf(ctx->ws, "%jd", (intmax_t)num));
772
}
773
774
int
775 226
VRT_REAL_is_valid(VCL_REAL arg)
776
{
777 226
        return (!isnan(arg) && arg >= VRT_DECIMAL_MIN && arg <= VRT_DECIMAL_MAX);
778
}
779
780
VCL_STRING v_matchproto_()
781 226
VRT_REAL_string(VRT_CTX, VCL_REAL num)
782
{
783
784 226
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
785 226
        if (!VRT_REAL_is_valid(num))
786 1
                VRT_fail(ctx, "REAL overflow converting to string (%e)", num);
787 226
        return (WS_Printf(ctx->ws, "%.3f", num));
788
}
789
790
VCL_STRING v_matchproto_()
791 76
VRT_TIME_string(VRT_CTX, VCL_TIME t)
792
{
793
        char *p;
794
795 76
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
796 76
        p = WS_Alloc(ctx->ws, VTIM_FORMAT_SIZE);
797 76
        if (p == NULL) {
798 0
                VRT_fail(ctx, "Workspace overflow");
799 0
                return (NULL);
800
        }
801 76
        VTIM_format(t, p);
802 76
        if (*p == '\0') {
803 1
                VRT_fail(ctx, "Unformattable VCL_TIME");
804 1
                return (NULL);
805
        }
806 75
        return (p);
807 76
}
808
809
VCL_STRING v_matchproto_()
810 4543
VRT_BACKEND_string(VCL_BACKEND d)
811
{
812 4543
        if (d == NULL)
813 0
                return (NULL);
814 4543
        CHECK_OBJ_NOTNULL(d, DIRECTOR_MAGIC);
815 4543
        return (d->vcl_name);
816 4543
}
817
818
VCL_STRING v_matchproto_()
819 541
VRT_BOOL_string(VCL_BOOL val)
820
{
821
822 541
        return (val ? "true" : "false");
823
}
824
825
VCL_STRING v_matchproto_()
826 16
VRT_BLOB_string(VRT_CTX, VCL_BLOB val)
827
{
828
        struct vsb vsb[1];
829
        const char *s;
830
831 16
        if (val == NULL)
832 0
                return (NULL);
833 16
        WS_VSB_new(vsb, ctx->ws);
834 16
        VSB_putc(vsb, ':');
835 16
        VENC_Encode_Base64(vsb, val->blob, val->len);
836 16
        VSB_putc(vsb, ':');
837 16
        s = WS_VSB_finish(vsb, ctx->ws, NULL);
838 16
        return (s);
839 16
}
840
841
/*--------------------------------------------------------------------*/
842
843
VCL_VOID
844 23
VRT_Rollback(VRT_CTX, VCL_HTTP hp)
845
{
846
847 23
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
848 23
        CHECK_OBJ_NOTNULL(hp, HTTP_MAGIC);
849 23
        if (ctx->method & VCL_MET_PIPE) {
850 0
                VRT_fail(ctx, "Cannot rollback in vcl_pipe {}");
851 0
                return;
852
        }
853 23
        if (hp == ctx->http_req) {
854 14
                CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
855 14
                Req_Rollback(ctx);
856 14
                if (ctx->method & VCL_MET_DELIVER)
857 9
                        XXXAZ(Resp_Setup_Deliver(ctx->req));
858 14
                if (ctx->method & VCL_MET_SYNTH)
859 2
                        Resp_Setup_Synth(ctx->req);
860 23
        } else if (hp == ctx->http_bereq) {
861 9
                Bereq_Rollback(ctx);
862 9
        } else
863 0
                WRONG("VRT_Rollback 'hp' invalid");
864 23
}
865
866
/*--------------------------------------------------------------------*/
867
868
VCL_VOID
869 5
VRT_synth_strands(VRT_CTX, VCL_STRANDS s)
870
{
871
        struct vsb *vsb;
872
        int i;
873
874 5
        CAST_OBJ_NOTNULL(vsb, ctx->specific, VSB_MAGIC);
875 5
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
876 10
        for (i = 0; i < s->n; i++) {
877 5
                if (s->p[i] != NULL)
878 4
                        VSB_cat(vsb, s->p[i]);
879
                else
880 1
                        VSB_cat(vsb, "(null)");
881 5
        }
882 5
}
883
884
VCL_VOID
885 0
VRT_synth_blob(VRT_CTX, VCL_BLOB b)
886
{
887
        struct vsb *vsb;
888 0
        CAST_OBJ_NOTNULL(vsb, ctx->specific, VSB_MAGIC);
889
890 0
        CHECK_OBJ_NOTNULL(b, VRT_BLOB_MAGIC);
891 0
        if (b->len > 0 && b->blob != NULL)
892 0
                VSB_bcat(vsb, b->blob, b->len);
893 0
}
894
895
VCL_VOID
896 0
VRT_synth_page(VRT_CTX, VCL_STRANDS s)
897
{
898 0
        VRT_synth_strands(ctx, s);
899 0
}
900
901
/*--------------------------------------------------------------------*/
902
903
static VCL_STRING
904 21
vrt_ban_error(VRT_CTX, VCL_STRING err)
905
{
906 21
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
907 21
        AN(ctx->vsl);
908 21
        AN(err);
909
910 21
        VSLb(ctx->vsl, SLT_VCL_Error, "ban(): %s", err);
911 21
        return (err);
912
}
913
914
VCL_STRING
915 39
VRT_ban_string(VRT_CTX, VCL_STRING str)
916
{
917
        char *a1, *a2, *a3;
918
        char **av;
919
        struct ban_proto *bp;
920 39
        const char *err = NULL, *berr = NULL;
921
        int i;
922
923 39
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
924
925 39
        if (str == NULL)
926 2
                return (vrt_ban_error(ctx, "Null argument"));
927
928 37
        bp = BAN_Build();
929 37
        if (bp == NULL)
930 0
                return (vrt_ban_error(ctx, "Out of Memory"));
931
932 37
        av = VAV_Parse(str, NULL, ARGV_NOESC);
933 37
        AN(av);
934 37
        if (av[0] != NULL) {
935 0
                err = av[0];
936 0
                VAV_Free(av);
937 0
                BAN_Abandon(bp);
938 0
                return (vrt_ban_error(ctx, err));
939
        }
940 42
        for (i = 0; ;) {
941 42
                a1 = av[++i];
942 42
                if (a1 == NULL) {
943 2
                        err = "No ban conditions found.";
944 2
                        break;
945
                }
946 40
                a2 = av[++i];
947 40
                if (a2 == NULL) {
948 2
                        err = "Expected comparison operator.";
949 2
                        break;
950
                }
951 38
                a3 = av[++i];
952 38
                if (a3 == NULL) {
953 2
                        err = "Expected second operand.";
954 2
                        break;
955
                }
956 36
                berr = BAN_AddTest(bp, a1, a2, a3);
957 36
                if (berr != NULL)
958 11
                        break;
959
960 25
                if (av[++i] == NULL) {
961 18
                        berr = BAN_Commit(bp);
962 18
                        if (berr == NULL)
963 18
                                bp = NULL;
964 18
                        break;
965
                }
966 7
                if (strcmp(av[i], "&&")) {
967 4
                        err = WS_Printf(ctx->ws, "Expected && between "
968 2
                            "conditions, found \"%s\"", av[i]);
969 2
                        if (err == NULL)
970 0
                                err = "Expected && between conditions "
971
                                    "(workspace overflow)";
972 2
                        break;
973
                }
974
        }
975 37
        if (berr != NULL) {
976 11
                AZ(err);
977 11
                err = WS_Copy(ctx->ws, berr, -1);
978 11
                if (err == NULL)
979 0
                        err = "Unknown error (workspace overflow)";
980 11
                berr = NULL;
981 11
        }
982 37
        AZ(berr);
983 37
        if (bp != NULL)
984 19
                BAN_Abandon(bp);
985 37
        VAV_Free(av);
986 37
        if (err == NULL)
987 18
                return (NULL);
988 19
        return (vrt_ban_error(ctx, err));
989 39
}
990
991
VCL_BYTES
992 35
VRT_CacheReqBody(VRT_CTX, VCL_BYTES maxsize)
993
{
994 35
        const char * const err = "req.body can only be cached in vcl_recv{}";
995
996 35
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
997 35
        if (ctx->method != VCL_MET_RECV) {
998 0
                if (ctx->vsl != NULL) {
999 0
                        VSLbs(ctx->vsl, SLT_VCL_Error, TOSTRAND(err));
1000 0
                } else {
1001 0
                        AN(ctx->msg);
1002 0
                        VSB_printf(ctx->msg, "%s\n", err);
1003
                };
1004 0
                return (-1);
1005
        }
1006 35
        CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
1007 35
        return (VRB_Cache(ctx->req, maxsize));
1008 35
}
1009
1010
/*--------------------------------------------------------------------
1011
 * purges
1012
 */
1013
1014
VCL_INT
1015 14
VRT_purge(VRT_CTX, VCL_DURATION ttl, VCL_DURATION grace, VCL_DURATION keep)
1016
{
1017
1018 14
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1019
1020 14
        if ((ctx->method & (VCL_MET_HIT|VCL_MET_MISS)) == 0) {
1021 0
                VRT_fail(ctx,
1022
                    "purge can only happen in vcl_hit{} or vcl_miss{}");
1023 0
                return (0);
1024
        }
1025
1026 14
        CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
1027 14
        CHECK_OBJ_NOTNULL(ctx->req->wrk, WORKER_MAGIC);
1028 28
        return (HSH_Purge(ctx->req->wrk, ctx->req->objcore->objhead,
1029 14
            ctx->req->t_req, ttl, grace, keep));
1030 14
}
1031
1032
/*--------------------------------------------------------------------
1033
 */
1034
1035
struct vsmw_cluster * v_matchproto_()
1036 1217
VRT_VSM_Cluster_New(VRT_CTX, size_t sz)
1037
{
1038
        struct vsmw_cluster *vc;
1039
1040 1217
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1041 1217
        assert(sz > 0);
1042 1217
        AN(vsc_lock);
1043 1217
        AN(vsc_unlock);
1044 1217
        AN(heritage.proc_vsmw);
1045 1217
        vsc_lock();
1046 1217
        vc = VSMW_NewCluster(heritage.proc_vsmw, sz, "VSC_cluster");
1047 1217
        vsc_unlock();
1048 1217
        return (vc);
1049
}
1050
1051
void v_matchproto_()
1052 78
VRT_VSM_Cluster_Destroy(VRT_CTX, struct vsmw_cluster **vsmcp)
1053
{
1054
1055 78
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1056 78
        AN(vsmcp);
1057 78
        VSMW_DestroyCluster(heritage.proc_vsmw, vsmcp);
1058 78
}
1059
1060
/*--------------------------------------------------------------------
1061
 * Simple stuff
1062
 */
1063
1064
int
1065 13352
VRT_strcmp(const char *s1, const char *s2)
1066
{
1067 13352
        if (s1 == NULL || s2 == NULL)
1068 1174
                return (1);
1069 12178
        return (strcmp(s1, s2));
1070 13352
}
1071
1072
void
1073 0
VRT_memmove(void *dst, const void *src, unsigned len)
1074
{
1075
1076 0
        (void)memmove(dst, src, len);
1077 0
}
1078
1079
VCL_BOOL
1080 23
VRT_ipcmp(VRT_CTX, VCL_IP sua1, VCL_IP sua2)
1081
{
1082
1083 23
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1084
1085 23
        if (sua1 == NULL || sua2 == NULL) {
1086 0
                VRT_fail(ctx, "%s: Illegal IP", __func__);
1087 0
                return (1);
1088
        }
1089 23
        return (VSA_Compare_IP(sua1, sua2));
1090 23
}
1091
1092
/*
1093
 * the pointer passed as src must have at least VCL_TASK lifetime
1094
 */
1095
VCL_BLOB
1096 247
VRT_blob(VRT_CTX, const char *err, const void *src, size_t len, unsigned type)
1097
{
1098
        struct vrt_blob *p;
1099
1100 247
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1101 247
        CHECK_OBJ_NOTNULL(ctx->ws, WS_MAGIC);
1102
1103 247
        if (src == NULL || len == 0)
1104 2
                return (vrt_null_blob);
1105
1106 245
        p = (void *)WS_Alloc(ctx->ws, sizeof *p);
1107 245
        if (p == NULL) {
1108 6
                VRT_fail(ctx, "Workspace overflow (%s)", err);
1109 6
                return (NULL);
1110
        }
1111
1112 239
        INIT_OBJ(p, VRT_BLOB_MAGIC);
1113 239
        p->type = type;
1114 239
        p->len = len;
1115 239
        p->blob = src;
1116
1117 239
        return (p);
1118 247
}
1119
1120
int
1121 96585
VRT_VSA_GetPtr(VRT_CTX, const struct suckaddr *sua, const unsigned char ** dst)
1122
{
1123
1124 96585
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
1125 96585
        AN(dst);
1126
1127 96585
        if (sua == NULL) {
1128 0
                VRT_fail(ctx, "%s: Illegal IP", __func__);
1129 0
                *dst = NULL;
1130 0
                return (-1);
1131
        }
1132 96585
        return (VSA_GetPtr(sua, dst));
1133 96585
}
1134
1135
void
1136 2
VRT_Format_Proxy(struct vsb *vsb, VCL_INT version, VCL_IP sac, VCL_IP sas,
1137
    VCL_STRING auth)
1138
{
1139 2
        VPX_Format_Proxy(vsb, (int)version, sac, sas, auth);
1140 2
}
1141
1142
/*
1143
 * Clone a struct vrt_endpoint in a single malloc() allocation
1144
 */
1145
1146
//lint -e{662}  Possible of out-of-bounds pointer (___ beyond end of data)
1147
//lint -e{826}  Suspicious pointer-to-pointer conversion (area to o small
1148
struct vrt_endpoint *
1149 2654
VRT_Endpoint_Clone(const struct vrt_endpoint * const vep)
1150
{
1151
        size_t sz;
1152
        struct vrt_endpoint *nvep;
1153 2654
        struct vrt_blob *blob = NULL;
1154
        struct suckaddr *sa;
1155 2654
        size_t uds_len = 0;
1156
        char *p, *e;
1157
1158 2654
        CHECK_OBJ_NOTNULL(vep, VRT_ENDPOINT_MAGIC);
1159 2654
        sz = sizeof *nvep;
1160 2654
        if (vep->ipv4)
1161 2555
                sz += vsa_suckaddr_len;
1162 2654
        if (vep->ipv6)
1163 8
                sz += vsa_suckaddr_len;
1164 2654
        if (vep->uds_path != NULL) {
1165 93
                uds_len = strlen(vep->uds_path) + 1;
1166 93
                sz += uds_len;
1167 93
        }
1168 2654
        if (vep->preamble != NULL && vep->preamble->len) {
1169 18
                sz += sizeof(*blob);
1170 18
                sz += vep->preamble->len;
1171 18
        }
1172 2654
        p = calloc(1, sz);
1173 2654
        AN(p);
1174 2654
        e = p + sz;
1175 2654
        nvep = (void*)p;
1176 2654
        p += sizeof *nvep;
1177 2654
        INIT_OBJ(nvep, VRT_ENDPOINT_MAGIC);
1178 2654
        if (vep->ipv4) {
1179 2555
                sa = (void*)p;
1180 2555
                memcpy(sa, vep->ipv4, vsa_suckaddr_len);
1181 2555
                nvep->ipv4 = sa;
1182 2555
                p += vsa_suckaddr_len;
1183 2555
        }
1184 2654
        if (vep->ipv6) {
1185 8
                sa = (void*)p;
1186 8
                memcpy(sa, vep->ipv6, vsa_suckaddr_len);
1187 8
                nvep->ipv6 = sa;
1188 8
                p += vsa_suckaddr_len;
1189 8
        }
1190 2654
        if (vep->preamble != NULL && vep->preamble->len) {
1191
                /* Before uds because we need p to be aligned still */
1192 18
                blob = (void*)p;
1193 18
                INIT_OBJ(blob, VRT_BLOB_MAGIC);
1194 18
                p += sizeof(*blob);
1195 18
                nvep->preamble = blob;
1196 18
                memcpy(p, vep->preamble->blob, vep->preamble->len);
1197 18
                blob->type = 0x70ea5b1e;
1198 18
                blob->len = vep->preamble->len;
1199 18
                blob->blob = p;
1200 18
                p += vep->preamble->len;
1201 18
        }
1202 2654
        if (uds_len) {
1203 93
                memcpy(p, vep->uds_path, uds_len);
1204 93
                nvep->uds_path = p;
1205 93
                p += uds_len;
1206 93
        }
1207 2654
        assert(p == e);
1208 2654
        return (nvep);
1209
}