vinyl-cache/vmod/vmod_std.c
0
/*-
1
 * Copyright (c) 2010-2017 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 <sys/stat.h>
33
34
#include <netinet/in.h>
35
36
#include <ctype.h>
37
#include <stdlib.h>
38
#include <string.h>
39
#include <syslog.h>
40
#include <sys/socket.h>
41
#include <fnmatch.h>
42
43
#include "cache/cache.h"
44
45
#include "vrnd.h"
46
#include "vtcp.h"
47
#include "vsa.h"
48
#include "vtim.h"
49
#include "vcl.h"
50
51
#include "vcc_std_if.h"
52
53
VCL_VOID v_matchproto_(td_std_set_ip_tos)
54 42
vmod_set_ip_tos(VRT_CTX, VCL_INT tos)
55
{
56
        struct suckaddr *sa;
57 42
        int fam, itos = tos;
58
59 42
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
60 42
        AZ(SES_Get_local_addr(ctx->req->sp, &sa));
61
        /* Silently ignore for non-IP addresses. */
62 42
        if (VSA_Compare(sa, bogo_ip) == 0)
63 21
                return;
64 21
        fam = VSA_Get_Proto(sa);
65 21
        switch (fam) {
66
        case PF_INET:
67 21
                VTCP_Assert(setsockopt(ctx->req->sp->fd,
68
                    IPPROTO_IP, IP_TOS, &itos, sizeof(itos)));
69 21
                break;
70
        case PF_INET6:
71 0
                VTCP_Assert(setsockopt(ctx->req->sp->fd,
72
                    IPPROTO_IPV6, IPV6_TCLASS, &itos, sizeof(itos)));
73 0
                break;
74
        default:
75 0
                INCOMPL();
76 0
        }
77 42
}
78
79
static const char *
80 252
vmod_updown(VRT_CTX, int up, VCL_STRANDS s)
81
{
82
        unsigned u;
83
        char *b, *e;
84
        const char *p;
85
        int i;
86
87 252
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
88 252
        CHECK_OBJ_NOTNULL(s, STRANDS_MAGIC);
89 252
        u = WS_ReserveAll(ctx->ws);
90 252
        e = b = WS_Reservation(ctx->ws);
91 252
        e += u;
92 504
        for (i = 0; i < s->n && b < e; i++) {
93 252
                p = s->p[i];
94 46074
                while (p != NULL && *p != '\0' && b < e) {
95 45822
                        if (up)
96 22722
                                *b++ = (char)toupper(*p++);
97
                        else
98 23100
                                *b++ = (char)tolower(*p++);
99
                }
100 252
        }
101 252
        if (b < e)
102 252
                *b = '\0';
103 252
        b++;
104 252
        if (b > e) {
105 0
                WS_MarkOverflow(ctx->ws);
106 0
                WS_Release(ctx->ws, 0);
107 0
                return (NULL);
108
        } else {
109 252
                e = b;
110 252
                b = WS_Reservation(ctx->ws);
111 252
                WS_Release(ctx->ws, e - b);
112 252
                return (b);
113
        }
114 252
}
115
116
VCL_STRING v_matchproto_(td_std_toupper)
117 84
vmod_toupper(VRT_CTX, VCL_STRANDS s)
118
{
119
120 84
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
121 84
        return (vmod_updown(ctx, 1, s));
122
}
123
124
VCL_STRING v_matchproto_(td_std_tolower)
125 168
vmod_tolower(VRT_CTX, VCL_STRANDS s)
126
{
127
128 168
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
129 168
        return (vmod_updown(ctx, 0, s));
130
}
131
132
VCL_REAL v_matchproto_(td_std_random)
133 126
vmod_random(VRT_CTX, VCL_REAL lo, VCL_REAL hi)
134
{
135
        double a;
136
137 126
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
138 126
        a = VRND_RandomTestableDouble();
139 126
        a *= hi - lo;
140 126
        a += lo;
141 126
        return (a);
142
}
143
144
VCL_VOID v_matchproto_(td_std_log)
145 3129
vmod_log(VRT_CTX, VCL_STRANDS s)
146
{
147 3129
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
148
149 3129
        if (ctx->vsl != NULL)
150 2436
                VSLbs(ctx->vsl, SLT_VCL_Log, s);
151
        else
152 693
                VSLs(SLT_VCL_Log, NO_VXID, s);
153 3129
}
154
155
/* XXX use vsyslog() ? */
156
VCL_VOID v_matchproto_(td_std_syslog)
157 105
vmod_syslog(VRT_CTX, VCL_INT fac, VCL_STRANDS s)
158
{
159
        const char *p;
160
        uintptr_t sn;
161
162 105
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
163 105
        sn = WS_Snapshot(ctx->ws);
164 105
        p = VRT_StrandsWS(ctx->ws, NULL, s);
165 105
        if (p != NULL)
166 84
                syslog((int)fac, "%s", p);
167 105
        WS_Reset(ctx->ws, sn);
168 105
}
169
170
VCL_BOOL v_matchproto_(td_std_file_exists)
171 42
vmod_file_exists(VRT_CTX, VCL_STRING file_name)
172
{
173
        struct stat st;
174
175 42
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
176 42
        return (stat(file_name, &st) == 0);
177
}
178
179
VCL_VOID v_matchproto_(td_std_collect)
180 273
vmod_collect(VRT_CTX, VCL_HEADER hdr, VCL_STRING sep)
181
{
182
        struct http *hp;
183
184 273
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
185 273
        if (hdr == NULL) {
186 0
                VRT_fail(ctx, "std.collect(): header argument is NULL");
187 0
                return;
188
        }
189 273
        hp = VRT_selecthttp(ctx, hdr->where);
190 273
        if (hp == NULL) {
191 21
                VRT_fail(ctx, "std.collect(): header argument "
192
                    "cannot be used here");
193 21
                return;
194
        }
195 252
        http_CollectHdrSep(hp, hdr->what, sep);
196 273
}
197
198
VCL_VOID v_matchproto_(td_std_collect_all)
199 42
vmod_collect_all(VRT_CTX, VCL_HTTP hp)
200
{
201
202 42
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
203 42
        if (hp == NULL) {
204 0
                VRT_fail(ctx, "std.collect_all(): header argument "
205
                    "cannot be used here");
206 0
                return;
207
        }
208 42
        http_CollectAllHdrs(hp);
209 42
}
210
211
VCL_BOOL v_matchproto_(td_std_healthy)
212 777
vmod_healthy(VRT_CTX, VCL_BACKEND be)
213
{
214 777
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
215 777
        CHECK_OBJ_ORNULL(be, DIRECTOR_MAGIC);
216 777
        return (VRT_Healthy(ctx, be, NULL));
217
}
218
219
VCL_INT v_matchproto_(td_std_port)
220 2352
vmod_port(VRT_CTX, VCL_IP ip)
221
{
222 2352
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
223 2352
        if (ip == NULL)
224 0
                return (0);
225 2352
        return (VSA_Port(ip));
226 2352
}
227
228
VCL_VOID v_matchproto_(td_std_rollback)
229 525
vmod_rollback(VRT_CTX, VCL_HTTP hp)
230
{
231
232 525
        (void)hp;
233 525
        VRT_Rollback(ctx);
234 525
}
235
236
VCL_VOID v_matchproto_(td_std_timestamp)
237 441
vmod_timestamp(VRT_CTX, VCL_STRING label)
238
{
239
240 441
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
241 441
        if (label == NULL)
242 0
                return;
243 441
        if (*label == '\0')
244 0
                return;
245 441
        if (ctx->bo != NULL && ctx->req == NULL) {
246
                /* Called from backend vcl methods */
247 21
                CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
248 21
                VSLb_ts_busyobj(ctx->bo, label, VTIM_real());
249 441
        } else if (ctx->req != NULL) {
250
                /* Called from request vcl methods */
251 399
                CHECK_OBJ(ctx->req, REQ_MAGIC);
252 399
                VSLb_ts_req(ctx->req, label, VTIM_real());
253 399
        }
254 441
}
255
256
VCL_BOOL v_matchproto_(td_std_cache_req_body)
257 882
vmod_cache_req_body(VRT_CTX, VCL_BYTES size)
258
{
259 882
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
260 882
        size = vmax_t(VCL_BYTES, size, 0);
261 882
        if (VRT_CacheReqBody(ctx, (size_t)size) < 0)
262 126
                return (0);
263 756
        return (1);
264 882
}
265
266
VCL_STRING v_matchproto_(td_std_strstr)
267 63
vmod_strstr(VRT_CTX, VCL_STRING s1, VCL_STRING s2)
268
{
269 63
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
270 63
        if (s1 == NULL || s2 == NULL)
271 21
                return (NULL);
272 42
        return (strstr(s1, s2));
273 63
}
274
275
VCL_STRING v_matchproto_(td_std_getenv)
276 105
vmod_getenv(VRT_CTX, VCL_STRING name, VCL_STRING fallback)
277
{
278
        const char *val;
279
280 105
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
281 105
        if (name == NULL || *name == '\0')
282 21
                return (NULL);
283
284 84
        val = getenv(name);
285 84
        if (val == NULL)
286 42
                return (fallback);
287 42
        return (val);
288 105
}
289
290
VCL_VOID v_matchproto_(td_std_late_100_continue)
291 105
vmod_late_100_continue(VRT_CTX, VCL_BOOL late)
292
{
293 105
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
294 105
        assert(ctx->method == VCL_MET_RECV);
295 105
        CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
296 105
        if (ctx->req->want100cont)
297 105
                ctx->req->late100cont = late;
298 105
}
299
300
VCL_BOOL v_matchproto_(td_std_syntax)
301 126
vmod_syntax(VRT_CTX, VCL_REAL r)
302
{
303
304 126
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
305 126
        assert(ctx->syntax == 40 || ctx->syntax == 41);
306
        /*
307
         * We need to be careful because non-integer numbers have imprecise
308
         * IEE754 representation (4.1 is 0x1.0666666666666p+2 = 4.09999...)
309
         * By scaling up and rounding, this is taken care of.
310
         */
311 126
        return (round(r * 10) <= ctx->syntax);
312
}
313
314
VCL_BOOL v_matchproto_(td_std_fnmatch)
315 1302
vmod_fnmatch(VRT_CTX, VCL_STRING pattern, VCL_STRING subject,
316
             VCL_BOOL pathname, VCL_BOOL noescape, VCL_BOOL period)
317
{
318 1302
        int flags = 0;
319
320 1302
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
321 1302
        if (pattern == NULL) {
322 21
                VRT_fail(ctx, "std.fnmatch(): pattern is NULL");
323 21
                return (0);
324
        }
325 1281
        if (subject == NULL) {
326 21
                VRT_fail(ctx, "std.fnmatch(): subject is NULL");
327 21
                return (0);
328
        }
329
330 1260
        if (pathname)
331 945
                flags |= FNM_PATHNAME;
332 1260
        if (noescape)
333 315
                flags |= FNM_NOESCAPE;
334 1260
        if (period)
335 315
                flags |= FNM_PERIOD;
336 1260
        return (fnmatch(pattern, subject, flags) != FNM_NOMATCH);
337 1302
}
338
339
static const void * const priv_task_id_ban = &priv_task_id_ban;
340
341
VCL_BOOL v_matchproto_(td_std_ban)
342 462
vmod_ban(VRT_CTX, VCL_STRING s)
343
{
344
        struct vmod_priv *priv_task;
345
        VCL_STRING r;
346
347 462
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
348
349 462
        r = VRT_ban_string(ctx, s);
350 462
        priv_task = VRT_priv_task_get(ctx, priv_task_id_ban);
351
352 462
        if (r == NULL && priv_task == NULL)
353 210
                return (1);
354
355 252
        if (priv_task == NULL)
356 42
                priv_task = VRT_priv_task(ctx, priv_task_id_ban);
357
358 252
        if (priv_task == NULL) {
359 0
                VRT_fail(ctx, "std.ban(): no priv_task (out of workspace?)");
360 0
                return (0);
361
        }
362
363
        /*
364
         * TRUST_ME: the ban error is const. We save it in the un-const priv
365
         * pointer, but promise to only ever return it as a (const) VCL_STRING
366
         */
367 252
        priv_task->priv = TRUST_ME(r);
368
369 252
        return (r == NULL);
370 462
}
371
372
VCL_STRING v_matchproto_(td_std_ban_error)
373 252
vmod_ban_error(VRT_CTX)
374
{
375
        struct vmod_priv *priv_task;
376
        VCL_STRING r;
377
378 252
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
379
380 252
        priv_task = VRT_priv_task_get(ctx, priv_task_id_ban);
381 252
        if (priv_task == NULL)
382 0
                return ("");
383
384 252
        r = priv_task->priv;
385 252
        if (r == NULL)
386 21
                r = "";
387 252
        return (r);
388 252
}
389
390
VCL_TIME v_matchproto_(td_std_now)
391 42
vmod_now(VRT_CTX)
392
{
393
394 42
        (void) ctx;
395 42
        return (VTIM_real());
396
}
397
398
VCL_DURATION v_matchproto_(td_std_timed_call)
399 21
vmod_timed_call(VRT_CTX, VCL_SUB sub)
400
{
401
        vtim_mono b;
402
403 21
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
404 21
        b = VTIM_mono();
405 21
        VRT_call(ctx, sub);
406 21
        return (VTIM_mono() - b);
407
}
408
409
VCL_VOID v_matchproto_(td_std_rfc_ttl)
410 42
vmod_rfc_ttl(VRT_CTX)
411
{
412
        struct busyobj *bo;
413
        struct objcore *oc;
414
415 42
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
416
        // $Restrict guarantees
417 42
        bo = ctx->bo;
418 42
        CHECK_OBJ_NOTNULL(bo, BUSYOBJ_MAGIC);
419 42
        oc = bo->fetch_objcore;
420 42
        CHECK_OBJ_NOTNULL(oc, OBJCORE_MAGIC);
421
422 84
        RFC2616_Ttl(bo, ctx->now,
423 42
             &oc->t_origin,
424 42
             &oc->ttl,
425 42
             &oc->grace,
426 42
             &oc->keep);
427 42
}