varnish-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 50
vmod_set_ip_tos(VRT_CTX, VCL_INT tos)
55
{
56
        struct suckaddr *sa;
57 50
        int fam, itos = tos;
58
59 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
60 50
        AZ(SES_Get_local_addr(ctx->req->sp, &sa));
61
        /* Silently ignore for non-IP addresses. */
62 50
        if (VSA_Compare(sa, bogo_ip) == 0)
63 25
                return;
64 25
        fam = VSA_Get_Proto(sa);
65 25
        switch (fam) {
66
        case PF_INET:
67 25
                VTCP_Assert(setsockopt(ctx->req->sp->fd,
68
                    IPPROTO_IP, IP_TOS, &itos, sizeof(itos)));
69 25
                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 50
}
78
79
static const char *
80 300
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 300
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
88 300
        u = WS_ReserveAll(ctx->ws);
89 300
        e = b = WS_Reservation(ctx->ws);
90 300
        e += u;
91 600
        for (i = 0; i < s->n && b < e; i++) {
92 300
                p = s->p[i];
93 54850
                while (p != NULL && *p != '\0' && b < e) {
94 54550
                        if (up)
95 27050
                                *b++ = (char)toupper(*p++);
96
                        else
97 27500
                                *b++ = (char)tolower(*p++);
98
                }
99 300
        }
100 300
        if (b < e)
101 300
                *b = '\0';
102 300
        b++;
103 300
        if (b > e) {
104 0
                WS_MarkOverflow(ctx->ws);
105 0
                WS_Release(ctx->ws, 0);
106 0
                return (NULL);
107
        } else {
108 300
                e = b;
109 300
                b = WS_Reservation(ctx->ws);
110 300
                WS_Release(ctx->ws, e - b);
111 300
                return (b);
112
        }
113 300
}
114
115
VCL_STRING v_matchproto_(td_std_toupper)
116 100
vmod_toupper(VRT_CTX, VCL_STRANDS s)
117
{
118
119 100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
120 100
        return (vmod_updown(ctx, 1, s));
121
}
122
123
VCL_STRING v_matchproto_(td_std_tolower)
124 200
vmod_tolower(VRT_CTX, VCL_STRANDS s)
125
{
126
127 200
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
128 200
        return (vmod_updown(ctx, 0, s));
129
}
130
131
VCL_REAL v_matchproto_(td_std_random)
132 125
vmod_random(VRT_CTX, VCL_REAL lo, VCL_REAL hi)
133
{
134
        double a;
135
136 125
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
137 125
        a = VRND_RandomTestableDouble();
138 125
        a *= hi - lo;
139 125
        a += lo;
140 125
        return (a);
141
}
142
143
VCL_VOID v_matchproto_(td_std_log)
144 3699
vmod_log(VRT_CTX, VCL_STRANDS s)
145
{
146 3699
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
147
148 3699
        if (ctx->vsl != NULL)
149 2899
                VSLbs(ctx->vsl, SLT_VCL_Log, s);
150
        else
151 800
                VSLs(SLT_VCL_Log, NO_VXID, s);
152 3699
}
153
154
/* XXX use vsyslog() ? */
155
VCL_VOID v_matchproto_(td_std_syslog)
156 125
vmod_syslog(VRT_CTX, VCL_INT fac, VCL_STRANDS s)
157
{
158
        const char *p;
159
        uintptr_t sn;
160
161 125
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
162 125
        sn = WS_Snapshot(ctx->ws);
163 125
        p = VRT_StrandsWS(ctx->ws, NULL, s);
164 125
        if (p != NULL)
165 100
                syslog((int)fac, "%s", p);
166 125
        WS_Reset(ctx->ws, sn);
167 125
}
168
169
VCL_BOOL v_matchproto_(td_std_file_exists)
170 50
vmod_file_exists(VRT_CTX, VCL_STRING file_name)
171
{
172
        struct stat st;
173
174 50
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
175 50
        return (stat(file_name, &st) == 0);
176
}
177
178
VCL_VOID v_matchproto_(td_std_collect)
179 325
vmod_collect(VRT_CTX, VCL_HEADER hdr, VCL_STRING sep)
180
{
181
        struct http *hp;
182
183 325
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
184 325
        if (hdr == NULL) {
185 0
                VRT_fail(ctx, "std.collect(): header argument is NULL");
186 0
                return;
187
        }
188 325
        hp = VRT_selecthttp(ctx, hdr->where);
189 325
        if (hp == NULL) {
190 25
                VRT_fail(ctx, "std.collect(): header argument "
191
                    "can not be used here");
192 25
                return;
193
        }
194 300
        http_CollectHdrSep(hp, hdr->what, sep);
195 325
}
196
197
VCL_BOOL v_matchproto_(td_std_healthy)
198 925
vmod_healthy(VRT_CTX, VCL_BACKEND be)
199
{
200 925
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
201 925
        CHECK_OBJ_ORNULL(be, DIRECTOR_MAGIC);
202 925
        return (VRT_Healthy(ctx, be, NULL));
203
}
204
205
VCL_INT v_matchproto_(td_std_port)
206 2100
vmod_port(VRT_CTX, VCL_IP ip)
207
{
208 2100
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
209 2100
        if (ip == NULL)
210 0
                return (0);
211 2100
        return (VSA_Port(ip));
212 2100
}
213
214
VCL_VOID v_matchproto_(td_std_rollback)
215 550
vmod_rollback(VRT_CTX, VCL_HTTP hp)
216
{
217 550
        VRT_Rollback(ctx, hp);
218 550
}
219
220
VCL_VOID v_matchproto_(td_std_timestamp)
221 525
vmod_timestamp(VRT_CTX, VCL_STRING label)
222
{
223
224 525
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
225 525
        if (label == NULL)
226 0
                return;
227 525
        if (*label == '\0')
228 0
                return;
229 525
        if (ctx->bo != NULL && ctx->req == NULL) {
230
                /* Called from backend vcl methods */
231 25
                CHECK_OBJ_NOTNULL(ctx->bo, BUSYOBJ_MAGIC);
232 25
                VSLb_ts_busyobj(ctx->bo, label, VTIM_real());
233 525
        } else if (ctx->req != NULL) {
234
                /* Called from request vcl methods */
235 475
                CHECK_OBJ(ctx->req, REQ_MAGIC);
236 475
                VSLb_ts_req(ctx->req, label, VTIM_real());
237 475
        }
238 525
}
239
240
VCL_BOOL v_matchproto_(td_std_cache_req_body)
241 650
vmod_cache_req_body(VRT_CTX, VCL_BYTES size)
242
{
243 650
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
244 650
        size = vmax_t(VCL_BYTES, size, 0);
245 650
        if (VRT_CacheReqBody(ctx, (size_t)size) < 0)
246 100
                return (0);
247 550
        return (1);
248 650
}
249
250
VCL_STRING v_matchproto_(td_std_strstr)
251 75
vmod_strstr(VRT_CTX, VCL_STRING s1, VCL_STRING s2)
252
{
253 75
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
254 75
        if (s1 == NULL || s2 == NULL)
255 25
                return (NULL);
256 50
        return (strstr(s1, s2));
257 75
}
258
259
VCL_STRING v_matchproto_(td_std_getenv)
260 75
vmod_getenv(VRT_CTX, VCL_STRING name)
261
{
262 75
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
263 75
        if (name == NULL || *name == '\0')
264 25
                return (NULL);
265 50
        return (getenv(name));
266 75
}
267
268
VCL_VOID v_matchproto_(td_std_late_100_continue)
269 125
vmod_late_100_continue(VRT_CTX, VCL_BOOL late)
270
{
271 125
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
272 125
        assert(ctx->method == VCL_MET_RECV);
273 125
        CHECK_OBJ_NOTNULL(ctx->req, REQ_MAGIC);
274 125
        if (ctx->req->want100cont)
275 125
                ctx->req->late100cont = late;
276 125
}
277
278
VCL_BOOL v_matchproto_(td_std_syntax)
279 150
vmod_syntax(VRT_CTX, VCL_REAL r)
280
{
281
282 150
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
283 150
        assert(ctx->syntax == 40 || ctx->syntax == 41);
284
        /*
285
         * We need to be careful because non-integer numbers have imprecise
286
         * IEE754 representation (4.1 is 0x1.0666666666666p+2 = 4.09999...)
287
         * By scaling up and rounding, this is taken care of.
288
         */
289 150
        return (round(r * 10) <= ctx->syntax);
290
}
291
292
VCL_BOOL v_matchproto_(td_std_fnmatch)
293 1550
vmod_fnmatch(VRT_CTX, VCL_STRING pattern, VCL_STRING subject,
294
             VCL_BOOL pathname, VCL_BOOL noescape, VCL_BOOL period)
295
{
296 1550
        int flags = 0;
297
298 1550
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
299 1550
        if (pattern == NULL) {
300 25
                VRT_fail(ctx, "std.fnmatch(): pattern is NULL");
301 25
                return (0);
302
        }
303 1525
        if (subject == NULL) {
304 25
                VRT_fail(ctx, "std.fnmatch(): subject is NULL");
305 25
                return (0);
306
        }
307
308 1500
        if (pathname)
309 1125
                flags |= FNM_PATHNAME;
310 1500
        if (noescape)
311 375
                flags |= FNM_NOESCAPE;
312 1500
        if (period)
313 375
                flags |= FNM_PERIOD;
314 1500
        return (fnmatch(pattern, subject, flags) != FNM_NOMATCH);
315 1550
}
316
317
static const void * const priv_task_id_ban = &priv_task_id_ban;
318
319
VCL_BOOL v_matchproto_(td_std_ban)
320 550
vmod_ban(VRT_CTX, VCL_STRING s)
321
{
322
        struct vmod_priv *priv_task;
323
        VCL_STRING r;
324
325 550
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
326
327 550
        r = VRT_ban_string(ctx, s);
328 550
        priv_task = VRT_priv_task_get(ctx, priv_task_id_ban);
329
330 550
        if (r == NULL && priv_task == NULL)
331 250
                return (1);
332
333 300
        if (priv_task == NULL)
334 50
                priv_task = VRT_priv_task(ctx, priv_task_id_ban);
335
336 300
        if (priv_task == NULL) {
337 0
                VRT_fail(ctx, "std.ban(): no priv_task (out of workspace?)");
338 0
                return (0);
339
        }
340
341
        /*
342
         * TRUST_ME: the ban error is const. We save it in the un-const priv
343
         * pointer, but promise to only ever return it as a (const) VCL_STRING
344
         */
345 300
        priv_task->priv = TRUST_ME(r);
346
347 300
        return (r == NULL);
348 550
}
349
350
VCL_STRING v_matchproto_(td_std_ban_error)
351 300
vmod_ban_error(VRT_CTX)
352
{
353
        struct vmod_priv *priv_task;
354
        VCL_STRING r;
355
356 300
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
357
358 300
        priv_task = VRT_priv_task_get(ctx, priv_task_id_ban);
359 300
        if (priv_task == NULL)
360 0
                return ("");
361
362 300
        r = priv_task->priv;
363 300
        if (r == NULL)
364 25
                r = "";
365 300
        return (r);
366 300
}
367
368
VCL_TIME v_matchproto_(td_std_now)
369 50
vmod_now(VRT_CTX)
370
{
371
372 50
        (void) ctx;
373 50
        return (VTIM_real());
374
}
375
376
VCL_DURATION v_matchproto_(td_std_timed_call)
377 25
vmod_timed_call(VRT_CTX, VCL_SUB sub)
378
{
379
        vtim_mono b;
380
381 25
        CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
382 25
        b = VTIM_mono();
383 25
        VRT_call(ctx, sub);
384 25
        return (VTIM_mono() - b);
385
}