| | varnish-cache/bin/varnishd/cache/cache_ban_build.c |
0 |
|
/*- |
1 |
|
* Copyright (c) 2006 Verdens Gang AS |
2 |
|
* Copyright (c) 2006-2015 Varnish Software AS |
3 |
|
* All rights reserved. |
4 |
|
* |
5 |
|
* Author: Poul-Henning Kamp <phk@phk.freebsd.dk> |
6 |
|
* |
7 |
|
* SPDX-License-Identifier: BSD-2-Clause |
8 |
|
* |
9 |
|
* Redistribution and use in source and binary forms, with or without |
10 |
|
* modification, are permitted provided that the following conditions |
11 |
|
* are met: |
12 |
|
* 1. Redistributions of source code must retain the above copyright |
13 |
|
* notice, this list of conditions and the following disclaimer. |
14 |
|
* 2. Redistributions in binary form must reproduce the above copyright |
15 |
|
* notice, this list of conditions and the following disclaimer in the |
16 |
|
* documentation and/or other materials provided with the distribution. |
17 |
|
* |
18 |
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND |
19 |
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
20 |
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
21 |
|
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE |
22 |
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
23 |
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
24 |
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
25 |
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
26 |
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
27 |
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
28 |
|
* SUCH DAMAGE. |
29 |
|
* |
30 |
|
*/ |
31 |
|
|
32 |
|
#include "config.h" |
33 |
|
|
34 |
|
#include <stdlib.h> |
35 |
|
|
36 |
|
#include "cache_varnishd.h" |
37 |
|
#include "cache_ban.h" |
38 |
|
|
39 |
|
#include "vend.h" |
40 |
|
#include "vtim.h" |
41 |
|
#include "vnum.h" |
42 |
|
|
43 |
|
void BAN_Build_Init(void); |
44 |
|
void BAN_Build_Fini(void); |
45 |
|
|
46 |
|
struct ban_proto { |
47 |
|
unsigned magic; |
48 |
|
#define BAN_PROTO_MAGIC 0xd8adc494 |
49 |
|
unsigned flags; /* BANS_FLAG_* */ |
50 |
|
|
51 |
|
struct vsb *vsb; |
52 |
|
char *err; |
53 |
|
}; |
54 |
|
|
55 |
|
/*-------------------------------------------------------------------- |
56 |
|
* Variables we can ban on |
57 |
|
*/ |
58 |
|
|
59 |
|
static const struct pvar { |
60 |
|
const char *name; |
61 |
|
unsigned flag; |
62 |
|
uint8_t tag; |
63 |
|
} pvars[] = { |
64 |
|
#define PVAR(a, b, c) { (a), (b), (c) }, |
65 |
|
#include "tbl/ban_vars.h" |
66 |
|
{ 0, 0, 0} |
67 |
|
}; |
68 |
|
|
69 |
|
/* operators allowed per argument (pvar.tag) */ |
70 |
|
static const unsigned arg_opervalid[BAN_ARGARRSZ + 1] = { |
71 |
|
#define ARGOPER(arg, mask) [BAN_ARGIDX(arg)] = (mask), |
72 |
|
#include "tbl/ban_arg_oper.h" |
73 |
|
[BAN_ARGARRSZ] = 0 |
74 |
|
}; |
75 |
|
|
76 |
|
// init'ed in _Init |
77 |
|
static const char *arg_operhelp[BAN_ARGARRSZ + 1]; |
78 |
|
|
79 |
|
// operators |
80 |
|
const char * const ban_oper[BAN_OPERARRSZ + 1] = { |
81 |
|
#define OPER(op, str) [BAN_OPERIDX(op)] = (str), |
82 |
|
#include "tbl/ban_oper.h" |
83 |
|
[BAN_OPERARRSZ] = NULL |
84 |
|
}; |
85 |
|
|
86 |
|
|
87 |
|
/*-------------------------------------------------------------------- |
88 |
|
*/ |
89 |
|
|
90 |
|
static char ban_build_err_no_mem[] = "No Memory"; |
91 |
|
|
92 |
|
/*-------------------------------------------------------------------- |
93 |
|
*/ |
94 |
|
|
95 |
|
struct ban_proto * |
96 |
41461 |
BAN_Build(void) |
97 |
|
{ |
98 |
|
struct ban_proto *bp; |
99 |
|
|
100 |
41461 |
ALLOC_OBJ(bp, BAN_PROTO_MAGIC); |
101 |
41461 |
if (bp == NULL) |
102 |
0 |
return (bp); |
103 |
41461 |
bp->vsb = VSB_new_auto(); |
104 |
41461 |
if (bp->vsb == NULL) { |
105 |
0 |
FREE_OBJ(bp); |
106 |
0 |
return (NULL); |
107 |
|
} |
108 |
41461 |
return (bp); |
109 |
41461 |
} |
110 |
|
|
111 |
|
// TODO: change to (struct ban_proto **) |
112 |
|
void |
113 |
41461 |
BAN_Abandon(struct ban_proto *bp) |
114 |
|
{ |
115 |
|
|
116 |
41461 |
CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); |
117 |
41461 |
VSB_destroy(&bp->vsb); |
118 |
41461 |
FREE_OBJ(bp); |
119 |
41461 |
} |
120 |
|
|
121 |
|
/*-------------------------------------------------------------------- |
122 |
|
*/ |
123 |
|
|
124 |
|
static void |
125 |
5480 |
ban_add_lump(const struct ban_proto *bp, const void *p, uint32_t len) |
126 |
|
{ |
127 |
5480 |
uint8_t buf[PRNDUP(sizeof len)] = { 0xff }; |
128 |
|
|
129 |
32080 |
while (VSB_len(bp->vsb) & PALGN) |
130 |
26600 |
VSB_putc(bp->vsb, buf[0]); |
131 |
5480 |
vbe32enc(buf, len); |
132 |
5480 |
VSB_bcat(bp->vsb, buf, sizeof buf); |
133 |
5480 |
VSB_bcat(bp->vsb, p, len); |
134 |
5480 |
} |
135 |
|
|
136 |
|
/*-------------------------------------------------------------------- |
137 |
|
*/ |
138 |
|
|
139 |
|
static const char * |
140 |
720 |
ban_error(struct ban_proto *bp, const char *fmt, ...) |
141 |
|
{ |
142 |
|
va_list ap; |
143 |
|
|
144 |
720 |
CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); |
145 |
720 |
AN(bp->vsb); |
146 |
|
|
147 |
|
/* First error is sticky */ |
148 |
720 |
if (bp->err == NULL) { |
149 |
720 |
if (fmt == ban_build_err_no_mem) { |
150 |
0 |
bp->err = ban_build_err_no_mem; |
151 |
0 |
} else { |
152 |
|
/* Record the error message in the vsb */ |
153 |
720 |
VSB_clear(bp->vsb); |
154 |
720 |
va_start(ap, fmt); |
155 |
720 |
VSB_vprintf(bp->vsb, fmt, ap); |
156 |
720 |
va_end(ap); |
157 |
720 |
AZ(VSB_finish(bp->vsb)); |
158 |
720 |
bp->err = VSB_data(bp->vsb); |
159 |
|
} |
160 |
720 |
} |
161 |
720 |
return (bp->err); |
162 |
|
} |
163 |
|
|
164 |
|
/*-------------------------------------------------------------------- |
165 |
|
* Parse and add a http argument specification |
166 |
|
* Output something which HTTP_GetHdr understands |
167 |
|
*/ |
168 |
|
|
169 |
|
static void |
170 |
1760 |
ban_parse_http(const struct ban_proto *bp, const char *a1) |
171 |
|
{ |
172 |
|
int l; |
173 |
|
|
174 |
1760 |
l = strlen(a1) + 1; |
175 |
1760 |
assert(l <= 127); |
176 |
1760 |
VSB_putc(bp->vsb, (char)l); |
177 |
1760 |
VSB_cat(bp->vsb, a1); |
178 |
1760 |
VSB_putc(bp->vsb, ':'); |
179 |
1760 |
VSB_putc(bp->vsb, '\0'); |
180 |
1760 |
} |
181 |
|
|
182 |
|
/*-------------------------------------------------------------------- |
183 |
|
* Parse and add a ban test specification |
184 |
|
*/ |
185 |
|
|
186 |
|
static const char * |
187 |
1200 |
ban_parse_regexp(struct ban_proto *bp, const char *a3) |
188 |
|
{ |
189 |
|
struct vsb vsb[1]; |
190 |
|
char errbuf[VRE_ERROR_LEN]; |
191 |
|
int errorcode, erroroffset; |
192 |
|
size_t sz; |
193 |
|
vre_t *re, *rex; |
194 |
|
|
195 |
1200 |
re = VRE_compile(a3, 0, &errorcode, &erroroffset, 0); |
196 |
1200 |
if (re == NULL) { |
197 |
40 |
AN(VSB_init(vsb, errbuf, sizeof errbuf)); |
198 |
40 |
AZ(VRE_error(vsb, errorcode)); |
199 |
40 |
AZ(VSB_finish(vsb)); |
200 |
40 |
VSB_fini(vsb); |
201 |
40 |
return (ban_error(bp, "Regex compile error: %s", errbuf)); |
202 |
|
} |
203 |
|
|
204 |
1160 |
rex = VRE_export(re, &sz); |
205 |
1160 |
AN(rex); |
206 |
1160 |
ban_add_lump(bp, rex, sz); |
207 |
1160 |
VRE_free(&rex); |
208 |
1160 |
VRE_free(&re); |
209 |
1160 |
return (0); |
210 |
1200 |
} |
211 |
|
|
212 |
|
static int |
213 |
4640 |
ban_parse_oper(const char *p) |
214 |
|
{ |
215 |
|
int i; |
216 |
|
|
217 |
10240 |
for (i = 0; i < BAN_OPERARRSZ; i++) { |
218 |
10080 |
if (!strcmp(p, ban_oper[i])) |
219 |
4480 |
return (BANS_OPER_OFF_ + i); |
220 |
5600 |
} |
221 |
160 |
return (-1); |
222 |
4640 |
} |
223 |
|
|
224 |
|
/*-------------------------------------------------------------------- |
225 |
|
* Add a (and'ed) test-condition to a ban |
226 |
|
*/ |
227 |
|
|
228 |
|
const char * |
229 |
5000 |
BAN_AddTest(struct ban_proto *bp, |
230 |
|
const char *a1, const char *a2, const char *a3) |
231 |
|
{ |
232 |
|
const struct pvar *pv; |
233 |
|
double darg; |
234 |
|
uint64_t dtmp; |
235 |
|
uint8_t denc[sizeof darg]; |
236 |
|
int op; |
237 |
|
|
238 |
5000 |
CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); |
239 |
5000 |
AN(bp->vsb); |
240 |
5000 |
AN(a1); |
241 |
5000 |
AN(a2); |
242 |
5000 |
AN(a3); |
243 |
|
|
244 |
5000 |
if (bp->err != NULL) |
245 |
0 |
return (bp->err); |
246 |
|
|
247 |
19960 |
for (pv = pvars; pv->name != NULL; pv++) { |
248 |
19640 |
if (!(pv->flag & BANS_FLAG_HTTP) && !strcmp(a1, pv->name)) |
249 |
2880 |
break; |
250 |
16760 |
if ((pv->flag & BANS_FLAG_HTTP) && !strncmp(a1, pv->name, strlen(pv->name))) |
251 |
1800 |
break; |
252 |
14960 |
} |
253 |
|
|
254 |
5000 |
if (pv->name == NULL) |
255 |
640 |
return (ban_error(bp, |
256 |
320 |
"Unknown or unsupported field \"%s\"", a1)); |
257 |
|
|
258 |
4680 |
bp->flags |= pv->flag; |
259 |
|
|
260 |
4680 |
VSB_putc(bp->vsb, pv->tag); |
261 |
4680 |
if (pv->flag & BANS_FLAG_HTTP) { |
262 |
1800 |
if (strlen(a1 + strlen(pv->name)) < 1) |
263 |
80 |
return (ban_error(bp, |
264 |
40 |
"Missing header name: \"%s\"", pv->name)); |
265 |
1760 |
assert(BANS_HAS_ARG1_SPEC(pv->tag)); |
266 |
1760 |
ban_parse_http(bp, a1 + strlen(pv->name)); |
267 |
1760 |
} |
268 |
|
|
269 |
4640 |
op = ban_parse_oper(a2); |
270 |
4640 |
if (op < BANS_OPER_OFF_ || |
271 |
4480 |
((1U << BAN_OPERIDX(op)) & arg_opervalid[BAN_ARGIDX(pv->tag)]) == 0) |
272 |
480 |
return (ban_error(bp, |
273 |
|
"expected conditional (%s) got \"%s\"", |
274 |
240 |
arg_operhelp[BAN_ARGIDX(pv->tag)], a2)); |
275 |
|
|
276 |
4400 |
if ((pv->flag & BANS_FLAG_DURATION) == 0) { |
277 |
3240 |
assert(! BANS_HAS_ARG2_DOUBLE(pv->tag)); |
278 |
|
|
279 |
3240 |
ban_add_lump(bp, a3, strlen(a3) + 1); |
280 |
3240 |
VSB_putc(bp->vsb, op); |
281 |
|
|
282 |
3240 |
if (! BANS_HAS_ARG2_SPEC(op)) |
283 |
2040 |
return (NULL); |
284 |
|
|
285 |
1200 |
return (ban_parse_regexp(bp, a3)); |
286 |
|
} |
287 |
|
|
288 |
1160 |
assert(pv->flag & BANS_FLAG_DURATION); |
289 |
1160 |
assert(BANS_HAS_ARG2_DOUBLE(pv->tag)); |
290 |
1160 |
darg = VNUM_duration(a3); |
291 |
1160 |
if (isnan(darg)) { |
292 |
160 |
return (ban_error(bp, |
293 |
80 |
"expected duration <n.nn>[ms|s|m|h|d|w|y] got \"%s\"", a3)); |
294 |
|
} |
295 |
|
|
296 |
1080 |
assert(sizeof darg == sizeof dtmp); |
297 |
1080 |
assert(sizeof dtmp == sizeof denc); |
298 |
1080 |
memcpy(&dtmp, &darg, sizeof dtmp); |
299 |
1080 |
vbe64enc(denc, dtmp); |
300 |
|
|
301 |
1080 |
ban_add_lump(bp, denc, sizeof denc); |
302 |
1080 |
VSB_putc(bp->vsb, op); |
303 |
1080 |
return (NULL); |
304 |
5000 |
} |
305 |
|
|
306 |
|
/*-------------------------------------------------------------------- |
307 |
|
* We maintain ban_start as a pointer to the first element of the list |
308 |
|
* as a separate variable from the VTAILQ, to avoid depending on the |
309 |
|
* internals of the VTAILQ macros. We tacitly assume that a pointer |
310 |
|
* write is always atomic in doing so. |
311 |
|
* |
312 |
|
* Returns: |
313 |
|
* 0: Ban successfully inserted |
314 |
|
* -1: Ban not inserted due to shutdown in progress. The ban has been |
315 |
|
* deleted. |
316 |
|
*/ |
317 |
|
|
318 |
|
const char * |
319 |
40421 |
BAN_Commit(struct ban_proto *bp) |
320 |
|
{ |
321 |
|
struct ban *b, *bi; |
322 |
|
ssize_t ln; |
323 |
|
vtim_real t0; |
324 |
|
uint64_t u; |
325 |
|
|
326 |
40421 |
CHECK_OBJ_NOTNULL(bp, BAN_PROTO_MAGIC); |
327 |
40421 |
AN(bp->vsb); |
328 |
40421 |
assert(sizeof u == sizeof t0); |
329 |
|
|
330 |
40421 |
if (ban_shutdown) |
331 |
0 |
return (ban_error(bp, "Shutting down")); |
332 |
|
|
333 |
40421 |
AZ(VSB_finish(bp->vsb)); |
334 |
40421 |
ln = VSB_len(bp->vsb); |
335 |
40421 |
assert(ln >= 0); |
336 |
|
|
337 |
40421 |
ALLOC_OBJ(b, BAN_MAGIC); |
338 |
40421 |
if (b == NULL) |
339 |
0 |
return (ban_error(bp, ban_build_err_no_mem)); |
340 |
40421 |
VTAILQ_INIT(&b->objcore); |
341 |
|
|
342 |
40421 |
b->spec = malloc(ln + BANS_HEAD_LEN); |
343 |
40421 |
if (b->spec == NULL) { |
344 |
0 |
free(b); |
345 |
0 |
return (ban_error(bp, ban_build_err_no_mem)); |
346 |
|
} |
347 |
|
|
348 |
40421 |
b->flags = bp->flags; |
349 |
|
|
350 |
40421 |
memset(b->spec, 0, BANS_HEAD_LEN); |
351 |
40421 |
t0 = VTIM_real(); |
352 |
40421 |
memcpy(&u, &t0, sizeof u); |
353 |
40421 |
vbe64enc(b->spec + BANS_TIMESTAMP, u); |
354 |
40421 |
b->spec[BANS_FLAGS] = b->flags & 0xff; |
355 |
40421 |
memcpy(b->spec + BANS_HEAD_LEN, VSB_data(bp->vsb), ln); |
356 |
40421 |
ln += BANS_HEAD_LEN; |
357 |
40421 |
vbe32enc(b->spec + BANS_LENGTH, ln); |
358 |
|
|
359 |
40421 |
Lck_Lock(&ban_mtx); |
360 |
40421 |
if (ban_shutdown) { |
361 |
|
/* We could have raced a shutdown */ |
362 |
0 |
Lck_Unlock(&ban_mtx); |
363 |
0 |
BAN_Free(b); |
364 |
0 |
return (ban_error(bp, "Shutting down")); |
365 |
|
} |
366 |
40421 |
bi = VTAILQ_FIRST(&ban_head); |
367 |
40421 |
VTAILQ_INSERT_HEAD(&ban_head, b, list); |
368 |
40421 |
ban_start = b; |
369 |
|
|
370 |
40421 |
VSC_C_main->bans++; |
371 |
40421 |
VSC_C_main->bans_added++; |
372 |
40421 |
bans_persisted_bytes += ln; |
373 |
40421 |
VSC_C_main->bans_persisted_bytes = bans_persisted_bytes; |
374 |
|
|
375 |
40421 |
if (b->flags & BANS_FLAG_OBJ) |
376 |
2320 |
VSC_C_main->bans_obj++; |
377 |
40421 |
if (b->flags & BANS_FLAG_REQ) |
378 |
1640 |
VSC_C_main->bans_req++; |
379 |
|
|
380 |
40421 |
if (bi != NULL) |
381 |
3800 |
ban_info_new(b->spec, ln); /* Notify stevedores */ |
382 |
|
|
383 |
40421 |
if (cache_param->ban_dups) { |
384 |
|
/* Hunt down duplicates, and mark them as completed */ |
385 |
50020 |
for (bi = VTAILQ_NEXT(b, list); bi != NULL; |
386 |
9599 |
bi = VTAILQ_NEXT(bi, list)) { |
387 |
9599 |
if (!(bi->flags & BANS_FLAG_COMPLETED) && |
388 |
7200 |
ban_equal(b->spec, bi->spec)) { |
389 |
520 |
ban_mark_completed(bi); |
390 |
520 |
VSC_C_main->bans_dups++; |
391 |
520 |
} |
392 |
9599 |
} |
393 |
40421 |
} |
394 |
40421 |
if (!(b->flags & BANS_FLAG_REQ)) |
395 |
38781 |
ban_kick_lurker(); |
396 |
40421 |
Lck_Unlock(&ban_mtx); |
397 |
|
|
398 |
40421 |
BAN_Abandon(bp); |
399 |
40421 |
return (NULL); |
400 |
40421 |
} |
401 |
|
|
402 |
|
static void |
403 |
292968 |
ban_build_arg_operhelp(struct vsb *vsb, int arg) |
404 |
|
{ |
405 |
|
unsigned mask; |
406 |
292968 |
const char *p = NULL, *n = NULL; |
407 |
|
int i; |
408 |
|
|
409 |
292968 |
ASSERT_BAN_ARG(arg); |
410 |
292968 |
mask = arg_opervalid[BAN_ARGIDX(arg)]; |
411 |
|
|
412 |
2636712 |
for (i = 0; i < BAN_OPERARRSZ; i++) { |
413 |
2343744 |
if ((mask & (1U << i)) == 0) |
414 |
878904 |
continue; |
415 |
1464840 |
if (p == NULL) |
416 |
292968 |
p = ban_oper[i]; |
417 |
1171872 |
else if (n == NULL) |
418 |
292968 |
n = ban_oper[i]; |
419 |
|
else { |
420 |
878904 |
VSB_cat(vsb, p); |
421 |
878904 |
VSB_cat(vsb, ", "); |
422 |
878904 |
p = n; |
423 |
878904 |
n = ban_oper[i]; |
424 |
|
} |
425 |
1464840 |
} |
426 |
|
|
427 |
292968 |
if (n) { |
428 |
292968 |
AN(p); |
429 |
292968 |
VSB_cat(vsb, p); |
430 |
292968 |
VSB_cat(vsb, " or "); |
431 |
292968 |
VSB_cat(vsb, n); |
432 |
292968 |
return; |
433 |
|
} |
434 |
|
|
435 |
0 |
AN(p); |
436 |
0 |
VSB_cat(vsb, p); |
437 |
292968 |
} |
438 |
|
|
439 |
|
void |
440 |
36621 |
BAN_Build_Init(void) { |
441 |
|
struct vsb *vsb; |
442 |
|
int i; |
443 |
|
|
444 |
36621 |
vsb = VSB_new_auto(); |
445 |
36621 |
AN(vsb); |
446 |
329589 |
for (i = BANS_ARG_OFF_; i < BANS_ARG_LIM; i ++) { |
447 |
292968 |
VSB_clear(vsb); |
448 |
292968 |
ban_build_arg_operhelp(vsb, i); |
449 |
292968 |
AZ(VSB_finish(vsb)); |
450 |
|
|
451 |
292968 |
arg_operhelp[BAN_ARGIDX(i)] = strdup(VSB_data(vsb)); |
452 |
292968 |
AN(arg_operhelp[BAN_ARGIDX(i)]); |
453 |
292968 |
} |
454 |
36621 |
arg_operhelp[BAN_ARGIDX(i)] = NULL; |
455 |
36621 |
VSB_destroy(&vsb); |
456 |
36621 |
} |
457 |
|
|
458 |
|
void |
459 |
36120 |
BAN_Build_Fini(void) { |
460 |
|
int i; |
461 |
|
|
462 |
325080 |
for (i = 0; i < BAN_ARGARRSZ; i++) |
463 |
288960 |
free(TRUST_ME(arg_operhelp[i])); |
464 |
36120 |
} |