| | varnish-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_varnishd.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 |
360 |
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 |
360 |
(void)vfe; |
| 59 |
360 |
vp = VFP_Suck(vc, p, lp); |
| 60 |
360 |
if (vp == VFP_ERROR) |
| 61 |
0 |
return (vp); |
| 62 |
360 |
q = p; |
| 63 |
10440 |
for (l = 0; l < *lp; l++, q++) { |
| 64 |
10080 |
if (*q >= 'A' && *q <= 'Z') |
| 65 |
1440 |
*q = (((*q - 'A') + 13) % 26) + 'A'; |
| 66 |
10080 |
if (*q >= 'a' && *q <= 'z') |
| 67 |
6840 |
*q = (((*q - 'a') + 13) % 26) + 'a'; |
| 68 |
10080 |
} |
| 69 |
360 |
return (vp); |
| 70 |
360 |
} |
| 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 |
920 |
xyzzy_vdp_rot13_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
| 84 |
|
{ |
| 85 |
|
|
| 86 |
920 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 87 |
920 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
| 88 |
920 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
| 89 |
920 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
| 90 |
920 |
AN(vdc->clen); |
| 91 |
|
|
| 92 |
920 |
AN(priv); |
| 93 |
|
|
| 94 |
920 |
*priv = malloc(ROT13_BUFSZ); |
| 95 |
920 |
if (*priv == NULL) |
| 96 |
0 |
return (-1); |
| 97 |
|
|
| 98 |
920 |
return (0); |
| 99 |
920 |
} |
| 100 |
|
|
| 101 |
|
static int v_matchproto_(vdp_bytes_f) |
| 102 |
1440 |
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 |
1440 |
int i, j, retval = 0; |
| 108 |
|
|
| 109 |
1440 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
| 110 |
1440 |
AN(priv); |
| 111 |
1440 |
AN(*priv); |
| 112 |
1440 |
if (len <= 0) |
| 113 |
240 |
return (VDP_bytes(vdc, act, ptr, len)); |
| 114 |
1200 |
AN(ptr); |
| 115 |
1200 |
if (act != VDP_END) |
| 116 |
400 |
act = VDP_FLUSH; |
| 117 |
1200 |
q = *priv; |
| 118 |
1200 |
pp = ptr; |
| 119 |
|
|
| 120 |
4217840 |
for (i = 0, j = 0; j < len; i++, j++) { |
| 121 |
4216640 |
if (pp[j] >= 'A' && pp[j] <= 'Z') |
| 122 |
1136896 |
q[i] = (((pp[j] - 'A') + 13) % 26) + 'A'; |
| 123 |
3079744 |
else if (pp[j] >= 'a' && pp[j] <= 'z') |
| 124 |
1140168 |
q[i] = (((pp[j] - 'a') + 13) % 26) + 'a'; |
| 125 |
|
else |
| 126 |
1939576 |
q[i] = pp[j]; |
| 127 |
4216640 |
if (i == ROT13_BUFSZ - 1 && j < len - 1) { |
| 128 |
526480 |
retval = VDP_bytes(vdc, VDP_FLUSH, q, ROT13_BUFSZ); |
| 129 |
526480 |
if (retval != 0) |
| 130 |
0 |
return (retval); |
| 131 |
526480 |
i = -1; |
| 132 |
526480 |
} |
| 133 |
4216640 |
} |
| 134 |
1200 |
if (i >= 0) |
| 135 |
1200 |
retval = VDP_bytes(vdc, act, q, i); |
| 136 |
1200 |
return (retval); |
| 137 |
1440 |
} |
| 138 |
|
|
| 139 |
|
static int v_matchproto_(vdp_fini_f) |
| 140 |
920 |
xyzzy_vdp_rot13_fini(struct vdp_ctx *vdc, void **priv) |
| 141 |
|
{ |
| 142 |
920 |
(void)vdc; |
| 143 |
920 |
AN(priv); |
| 144 |
920 |
free(*priv); |
| 145 |
920 |
*priv = NULL; |
| 146 |
920 |
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 |
40 |
xyzzy_rot104(VRT_CTX) |
| 158 |
|
{ |
| 159 |
|
|
| 160 |
40 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 161 |
|
// This should fail |
| 162 |
40 |
AN(VRT_AddFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13)); |
| 163 |
40 |
} |
| 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 |
1080 |
xyzzy_vdp_chunked_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
| 175 |
|
{ |
| 176 |
|
|
| 177 |
1080 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 178 |
1080 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
| 179 |
1080 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
| 180 |
1080 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
| 181 |
1080 |
AN(vdc->clen); |
| 182 |
1080 |
AN(priv); |
| 183 |
|
|
| 184 |
1080 |
http_Unset(vdc->hp, H_Content_Length); |
| 185 |
1080 |
*vdc->clen = -1; |
| 186 |
|
|
| 187 |
1080 |
return (1); |
| 188 |
|
} |
| 189 |
|
|
| 190 |
|
static const struct vdp xyzzy_vdp_chunked = { |
| 191 |
|
.name = "debug.chunked", |
| 192 |
|
.init = xyzzy_vdp_chunked_init, |
| 193 |
|
}; |
| 194 |
|
|
| 195 |
|
/********************************************************************** |
| 196 |
|
* pedantic tests of the VDP API: |
| 197 |
|
* - assert that we see a VDP_END |
| 198 |
|
* - assert that _fini gets called before the task ends |
| 199 |
|
* |
| 200 |
|
* note: |
| 201 |
|
* we could lookup our own vdpe in _fini and check for vdpe->end == VDP_END |
| 202 |
|
* yet that would cross the API |
| 203 |
|
*/ |
| 204 |
|
|
| 205 |
|
enum vdp_state_e { |
| 206 |
|
VDPS_NULL = 0, |
| 207 |
|
VDPS_INIT, // _init called |
| 208 |
|
VDPS_BYTES, // _bytes called act != VDP_END |
| 209 |
|
VDPS_END, // _bytes called act == VDP_END |
| 210 |
|
VDPS_FINI // _fini called |
| 211 |
|
}; |
| 212 |
|
|
| 213 |
|
struct vdp_state_s { |
| 214 |
|
unsigned magic; |
| 215 |
|
#define VDP_STATE_MAGIC 0x57c8d309 |
| 216 |
|
enum vdp_state_e state; |
| 217 |
|
}; |
| 218 |
|
|
| 219 |
|
static void v_matchproto_(vmod_priv_fini_f) |
| 220 |
7600 |
priv_pedantic_fini(VRT_CTX, void *priv) |
| 221 |
|
{ |
| 222 |
|
struct vdp_state_s *vdps; |
| 223 |
|
|
| 224 |
7600 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 225 |
7600 |
CAST_OBJ_NOTNULL(vdps, priv, VDP_STATE_MAGIC); |
| 226 |
|
|
| 227 |
7600 |
assert(vdps->state == VDPS_FINI); |
| 228 |
7600 |
} |
| 229 |
|
|
| 230 |
|
static const struct vmod_priv_methods priv_pedantic_methods[1] = {{ |
| 231 |
|
.magic = VMOD_PRIV_METHODS_MAGIC, |
| 232 |
|
.type = "debug_vdp_pedantic", |
| 233 |
|
.fini = priv_pedantic_fini |
| 234 |
|
}}; |
| 235 |
|
|
| 236 |
|
static int v_matchproto_(vdp_init_f) |
| 237 |
7920 |
xyzzy_pedantic_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
| 238 |
|
{ |
| 239 |
|
struct vdp_state_s *vdps; |
| 240 |
|
struct vmod_priv *p; |
| 241 |
|
|
| 242 |
7920 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 243 |
7920 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
| 244 |
7920 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
| 245 |
7920 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
| 246 |
7920 |
AN(vdc->clen); |
| 247 |
7920 |
AN(priv); |
| 248 |
|
|
| 249 |
15520 |
WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_STATE_MAGIC); |
| 250 |
7920 |
if (vdps == NULL) |
| 251 |
320 |
return (-1); |
| 252 |
7600 |
assert(vdps->state == VDPS_NULL); |
| 253 |
|
|
| 254 |
7600 |
p = VRT_priv_task(ctx, (void *)vdc); |
| 255 |
7600 |
if (p == NULL) |
| 256 |
0 |
return (-1); |
| 257 |
7600 |
p->priv = vdps; |
| 258 |
7600 |
p->methods = priv_pedantic_methods; |
| 259 |
|
|
| 260 |
7600 |
*priv = vdps; |
| 261 |
|
|
| 262 |
7600 |
vdps->state = VDPS_INIT; |
| 263 |
|
|
| 264 |
7600 |
return (0); |
| 265 |
7920 |
} |
| 266 |
|
|
| 267 |
|
static int v_matchproto_(vdp_bytes_f) |
| 268 |
9558 |
xyzzy_pedantic_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
| 269 |
|
const void *ptr, ssize_t len) |
| 270 |
|
{ |
| 271 |
|
struct vdp_state_s *vdps; |
| 272 |
|
|
| 273 |
9558 |
CAST_OBJ_NOTNULL(vdps, *priv, VDP_STATE_MAGIC); |
| 274 |
9558 |
assert(vdps->state >= VDPS_INIT); |
| 275 |
9558 |
assert(vdps->state < VDPS_END); |
| 276 |
|
|
| 277 |
9558 |
if (act == VDP_END) |
| 278 |
2480 |
vdps->state = VDPS_END; |
| 279 |
|
else |
| 280 |
7078 |
vdps->state = VDPS_BYTES; |
| 281 |
|
|
| 282 |
9558 |
return (VDP_bytes(vdc, act, ptr, len)); |
| 283 |
|
} |
| 284 |
|
|
| 285 |
|
static int v_matchproto_(vdp_fini_f) |
| 286 |
7920 |
xyzzy_pedantic_fini(struct vdp_ctx *vdc, void **priv) |
| 287 |
|
{ |
| 288 |
|
struct vdp_state_s *vdps; |
| 289 |
|
|
| 290 |
7920 |
(void) vdc; |
| 291 |
7920 |
AN(priv); |
| 292 |
7920 |
if (*priv == NULL) |
| 293 |
320 |
return (0); |
| 294 |
7600 |
TAKE_OBJ_NOTNULL(vdps, priv, VDP_STATE_MAGIC); |
| 295 |
7600 |
assert(vdps->state == VDPS_INIT || vdps->state == VDPS_END); |
| 296 |
7600 |
vdps->state = VDPS_FINI; |
| 297 |
|
|
| 298 |
7600 |
return (0); |
| 299 |
7920 |
} |
| 300 |
|
|
| 301 |
|
static const struct vdp xyzzy_vdp_pedantic = { |
| 302 |
|
.name = "debug.pedantic", |
| 303 |
|
.init = xyzzy_pedantic_init, |
| 304 |
|
.bytes = xyzzy_pedantic_bytes, |
| 305 |
|
.fini = xyzzy_pedantic_fini, |
| 306 |
|
}; |
| 307 |
|
|
| 308 |
|
/********************************************************************** |
| 309 |
|
* |
| 310 |
|
* this trivial copy/paste/edit filter (of rot13) was specifically made for |
| 311 |
|
* someone who added a DBG_SLOW_BEREQ debug flag. It should actually be turned |
| 312 |
|
* in a proper "bandwidth control" filter, but that exceeds an evening's work, |
| 313 |
|
* so it's kept for later |
| 314 |
|
*/ |
| 315 |
|
|
| 316 |
|
static enum vfp_status v_matchproto_(vfp_pull_f) |
| 317 |
0 |
xyzzy_vfp_slow_pull(struct vfp_ctx *vc, struct vfp_entry *vfe, void *p, |
| 318 |
|
ssize_t *lp) |
| 319 |
|
{ |
| 320 |
|
|
| 321 |
0 |
(void)vfe; |
| 322 |
0 |
VTIM_sleep(1.0); |
| 323 |
0 |
return (VFP_Suck(vc, p, lp)); |
| 324 |
|
} |
| 325 |
|
|
| 326 |
|
static const struct vfp xyzzy_vfp_slow = { |
| 327 |
|
.name = "debug.slow", |
| 328 |
|
.pull = xyzzy_vfp_slow_pull, |
| 329 |
|
}; |
| 330 |
|
|
| 331 |
|
/**********************************************************************/ |
| 332 |
|
|
| 333 |
|
static int v_matchproto_(vdp_bytes_f) |
| 334 |
160 |
xyzzy_vdp_slow_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
| 335 |
|
const void *ptr, ssize_t len) |
| 336 |
|
{ |
| 337 |
|
|
| 338 |
160 |
(void)priv; |
| 339 |
160 |
VTIM_sleep(1.0); |
| 340 |
160 |
return (VDP_bytes(vdc, act, ptr, len)); |
| 341 |
|
} |
| 342 |
|
|
| 343 |
|
static const struct vdp xyzzy_vdp_slow = { |
| 344 |
|
.name = "debug.slow", |
| 345 |
|
.bytes = xyzzy_vdp_slow_bytes |
| 346 |
|
}; |
| 347 |
|
|
| 348 |
|
/* |
| 349 |
|
* check VDPs: |
| 350 |
|
* |
| 351 |
|
* test that the stream of bytes has a certain checksum or length and either log |
| 352 |
|
* or panic |
| 353 |
|
* |
| 354 |
|
* The sha256 and crc32 variants are basically identical, but the amount of |
| 355 |
|
* code does not justify generalizing. (slink) |
| 356 |
|
*/ |
| 357 |
|
|
| 358 |
|
enum vdp_chk_mode_e { |
| 359 |
|
//lint -esym(749, vdp_chk_mode_e::VDP_CHK_INVAL) deliberately not referenced |
| 360 |
|
VDP_CHK_INVAL = 0, |
| 361 |
|
VDP_CHK_LOG, |
| 362 |
|
VDP_CHK_PANIC, |
| 363 |
|
VDP_CHK_PANIC_UNLESS_ERROR |
| 364 |
|
}; |
| 365 |
|
|
| 366 |
|
struct vdp_chksha256_cfg_s { |
| 367 |
|
unsigned magic; |
| 368 |
|
#define VDP_CHKSHA256_CFG_MAGIC 0x624f5b32 |
| 369 |
|
enum vdp_chk_mode_e mode; |
| 370 |
|
unsigned char expected[VSHA256_DIGEST_LENGTH]; |
| 371 |
|
}; |
| 372 |
|
|
| 373 |
|
struct vdp_chkcrc32_cfg_s { |
| 374 |
|
unsigned magic; |
| 375 |
|
#define VDP_CHKCRC32_CFG_MAGIC 0x5a7a835c |
| 376 |
|
enum vdp_chk_mode_e mode; |
| 377 |
|
uint32_t expected; |
| 378 |
|
}; |
| 379 |
|
|
| 380 |
|
struct vdp_chklen_cfg_s { |
| 381 |
|
unsigned magic; |
| 382 |
|
#define VDP_CHKLEN_CFG_MAGIC 0x08cf3426 |
| 383 |
|
enum vdp_chk_mode_e mode; |
| 384 |
|
size_t expected; |
| 385 |
|
}; |
| 386 |
|
|
| 387 |
|
struct vdp_chksha256_s { |
| 388 |
|
unsigned magic; |
| 389 |
|
#define VDP_CHKSHA256_MAGIC 0x6856e913 |
| 390 |
|
unsigned called; |
| 391 |
|
size_t bytes; |
| 392 |
|
struct VSHA256Context cx[1]; |
| 393 |
|
struct vdp_chksha256_cfg_s *cfg; |
| 394 |
|
}; |
| 395 |
|
|
| 396 |
|
struct vdp_chkcrc32_s { |
| 397 |
|
unsigned magic; |
| 398 |
|
#define VDP_CHKCRC32_MAGIC 0x15c03d3c |
| 399 |
|
unsigned called; |
| 400 |
|
size_t bytes; |
| 401 |
|
uint32_t crc; |
| 402 |
|
struct vdp_chkcrc32_cfg_s *cfg; |
| 403 |
|
}; |
| 404 |
|
|
| 405 |
|
struct vdp_chklen_s { |
| 406 |
|
unsigned magic; |
| 407 |
|
#define VDP_CHKLEN_MAGIC 0x029811f5 |
| 408 |
|
unsigned called; |
| 409 |
|
size_t bytes; |
| 410 |
|
struct vdp_chklen_cfg_s *cfg; |
| 411 |
|
}; |
| 412 |
|
|
| 413 |
|
static const void * const chksha256_priv_id = &chksha256_priv_id; |
| 414 |
|
static const void * const chkcrc32_priv_id = &chkcrc32_priv_id; |
| 415 |
|
static const void * const chklen_priv_id = &chklen_priv_id; |
| 416 |
|
|
| 417 |
|
static int v_matchproto_(vdp_init_f) |
| 418 |
80 |
xyzzy_chksha256_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
| 419 |
|
{ |
| 420 |
|
struct vdp_chksha256_s *vdps; |
| 421 |
|
struct vmod_priv *p; |
| 422 |
|
|
| 423 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 424 |
80 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
| 425 |
80 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
| 426 |
80 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
| 427 |
80 |
AN(vdc->clen); |
| 428 |
80 |
AN(priv); |
| 429 |
|
|
| 430 |
160 |
WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_CHKSHA256_MAGIC); |
| 431 |
80 |
if (vdps == NULL) |
| 432 |
0 |
return (-1); |
| 433 |
80 |
VSHA256_Init(vdps->cx); |
| 434 |
|
|
| 435 |
80 |
p = VRT_priv_task_get(ctx, chksha256_priv_id); |
| 436 |
80 |
if (p == NULL) |
| 437 |
0 |
return (-1); |
| 438 |
|
|
| 439 |
80 |
assert(p->len == sizeof(struct vdp_chksha256_cfg_s)); |
| 440 |
80 |
CAST_OBJ_NOTNULL(vdps->cfg, p->priv, VDP_CHKSHA256_CFG_MAGIC); |
| 441 |
80 |
*priv = vdps; |
| 442 |
|
|
| 443 |
80 |
return (0); |
| 444 |
80 |
} |
| 445 |
|
|
| 446 |
|
static int v_matchproto_(vdp_init_f) |
| 447 |
80 |
xyzzy_chkcrc32_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
| 448 |
|
{ |
| 449 |
|
struct vdp_chkcrc32_s *vdps; |
| 450 |
|
struct vmod_priv *p; |
| 451 |
|
|
| 452 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 453 |
80 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
| 454 |
80 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
| 455 |
80 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
| 456 |
80 |
AN(vdc->clen); |
| 457 |
80 |
AN(priv); |
| 458 |
|
|
| 459 |
160 |
WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_CHKCRC32_MAGIC); |
| 460 |
80 |
if (vdps == NULL) |
| 461 |
0 |
return (-1); |
| 462 |
80 |
vdps->crc = crc32(0L, Z_NULL, 0); |
| 463 |
|
|
| 464 |
80 |
p = VRT_priv_task_get(ctx, chkcrc32_priv_id); |
| 465 |
80 |
if (p == NULL) |
| 466 |
0 |
return (-1); |
| 467 |
|
|
| 468 |
80 |
assert(p->len == sizeof(struct vdp_chkcrc32_cfg_s)); |
| 469 |
80 |
CAST_OBJ_NOTNULL(vdps->cfg, p->priv, VDP_CHKCRC32_CFG_MAGIC); |
| 470 |
80 |
*priv = vdps; |
| 471 |
|
|
| 472 |
80 |
return (0); |
| 473 |
80 |
} |
| 474 |
|
|
| 475 |
|
static int v_matchproto_(vdp_init_f) |
| 476 |
80 |
xyzzy_chklen_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
| 477 |
|
{ |
| 478 |
|
struct vdp_chklen_s *vdps; |
| 479 |
|
struct vmod_priv *p; |
| 480 |
|
|
| 481 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 482 |
80 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
| 483 |
80 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
| 484 |
80 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
| 485 |
80 |
AN(vdc->clen); |
| 486 |
80 |
AN(priv); |
| 487 |
|
|
| 488 |
160 |
WS_TASK_ALLOC_OBJ(ctx, vdps, VDP_CHKLEN_MAGIC); |
| 489 |
80 |
if (vdps == NULL) |
| 490 |
0 |
return (-1); |
| 491 |
80 |
AZ(vdps->bytes); |
| 492 |
|
|
| 493 |
80 |
p = VRT_priv_task_get(ctx, chklen_priv_id); |
| 494 |
80 |
if (p == NULL) |
| 495 |
0 |
return (-1); |
| 496 |
|
|
| 497 |
80 |
assert(p->len == sizeof(struct vdp_chklen_cfg_s)); |
| 498 |
80 |
CAST_OBJ_NOTNULL(vdps->cfg, p->priv, VDP_CHKLEN_CFG_MAGIC); |
| 499 |
80 |
*priv = vdps; |
| 500 |
|
|
| 501 |
80 |
return (0); |
| 502 |
80 |
} |
| 503 |
|
|
| 504 |
|
static int v_matchproto_(vdp_bytes_f) |
| 505 |
240 |
xyzzy_chksha256_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
| 506 |
|
const void *ptr, ssize_t len) |
| 507 |
|
{ |
| 508 |
|
struct vdp_chksha256_s *vdps; |
| 509 |
|
|
| 510 |
240 |
CAST_OBJ_NOTNULL(vdps, *priv, VDP_CHKSHA256_MAGIC); |
| 511 |
240 |
if (len != 0) |
| 512 |
120 |
VSHA256_Update(vdps->cx, ptr, len); |
| 513 |
240 |
vdps->called++; |
| 514 |
240 |
vdps->bytes += len; |
| 515 |
240 |
return (VDP_bytes(vdc, act, ptr, len)); |
| 516 |
|
} |
| 517 |
|
|
| 518 |
|
static int v_matchproto_(vdp_bytes_f) |
| 519 |
240 |
xyzzy_chkcrc32_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
| 520 |
|
const void *ptr, ssize_t len) |
| 521 |
|
{ |
| 522 |
|
struct vdp_chkcrc32_s *vdps; |
| 523 |
|
|
| 524 |
240 |
CAST_OBJ_NOTNULL(vdps, *priv, VDP_CHKCRC32_MAGIC); |
| 525 |
240 |
if (len > 0) |
| 526 |
120 |
vdps->crc = crc32(vdps->crc, ptr, len); |
| 527 |
240 |
vdps->called++; |
| 528 |
240 |
vdps->bytes += len; |
| 529 |
240 |
return (VDP_bytes(vdc, act, ptr, len)); |
| 530 |
|
} |
| 531 |
|
|
| 532 |
|
static int v_matchproto_(vdp_bytes_f) |
| 533 |
240 |
xyzzy_chklen_bytes(struct vdp_ctx *vdc, enum vdp_action act, void **priv, |
| 534 |
|
const void *ptr, ssize_t len) |
| 535 |
|
{ |
| 536 |
|
struct vdp_chklen_s *vdps; |
| 537 |
|
|
| 538 |
240 |
CAST_OBJ_NOTNULL(vdps, *priv, VDP_CHKLEN_MAGIC); |
| 539 |
240 |
vdps->called++; |
| 540 |
240 |
vdps->bytes += len; |
| 541 |
240 |
return (VDP_bytes(vdc, act, ptr, len)); |
| 542 |
|
} |
| 543 |
|
|
| 544 |
|
static int v_matchproto_(vdp_fini_f) |
| 545 |
80 |
xyzzy_chksha256_fini(struct vdp_ctx *vdc, void **priv) |
| 546 |
|
{ |
| 547 |
|
unsigned char digest[VSHA256_DIGEST_LENGTH]; |
| 548 |
|
enum vdp_chk_mode_e mode; |
| 549 |
|
struct vdp_chksha256_s *vdps; |
| 550 |
|
struct vsb *vsb; |
| 551 |
|
int r; |
| 552 |
|
|
| 553 |
80 |
(void) vdc; |
| 554 |
80 |
AN(priv); |
| 555 |
80 |
if (*priv == NULL) |
| 556 |
0 |
return (0); |
| 557 |
80 |
TAKE_OBJ_NOTNULL(vdps, priv, VDP_CHKSHA256_MAGIC); |
| 558 |
|
|
| 559 |
80 |
VSHA256_Final(digest, vdps->cx); |
| 560 |
80 |
r = memcmp(digest, vdps->cfg->expected, sizeof digest); |
| 561 |
80 |
if (r == 0) |
| 562 |
40 |
return (0); |
| 563 |
|
|
| 564 |
40 |
mode = vdps->cfg->mode; |
| 565 |
40 |
if (mode == VDP_CHK_PANIC_UNLESS_ERROR) |
| 566 |
0 |
mode = (vdps->called == 0 || vdc->retval != 0) ? VDP_CHK_LOG : VDP_CHK_PANIC; |
| 567 |
|
|
| 568 |
40 |
if (mode == VDP_CHK_LOG) { |
| 569 |
40 |
VSLb(vdc->vsl, SLT_Debug, "sha256 checksum mismatch"); |
| 570 |
|
|
| 571 |
40 |
vsb = VSB_new_auto(); |
| 572 |
40 |
AN(vsb); |
| 573 |
40 |
VSB_quote(vsb, digest, sizeof digest, VSB_QUOTE_HEX); |
| 574 |
40 |
AZ(VSB_finish(vsb)); |
| 575 |
40 |
VSLb(vdc->vsl, SLT_Debug, "got: %s", VSB_data(vsb)); |
| 576 |
|
|
| 577 |
40 |
VSB_clear(vsb); |
| 578 |
40 |
VSB_quote(vsb, vdps->cfg->expected, sizeof digest, VSB_QUOTE_HEX); |
| 579 |
40 |
AZ(VSB_finish(vsb)); |
| 580 |
40 |
VSLb(vdc->vsl, SLT_Debug, "exp: %s", VSB_data(vsb)); |
| 581 |
40 |
VSB_destroy(&vsb); |
| 582 |
40 |
} |
| 583 |
0 |
else if (mode == VDP_CHK_PANIC) |
| 584 |
0 |
WRONG("body checksum"); |
| 585 |
|
else |
| 586 |
0 |
WRONG("mode"); |
| 587 |
|
|
| 588 |
40 |
return (0); |
| 589 |
80 |
} |
| 590 |
|
|
| 591 |
|
static int v_matchproto_(vdp_fini_f) |
| 592 |
80 |
xyzzy_chkcrc32_fini(struct vdp_ctx *vdc, void **priv) |
| 593 |
|
{ |
| 594 |
|
enum vdp_chk_mode_e mode; |
| 595 |
|
struct vdp_chkcrc32_s *vdps; |
| 596 |
|
|
| 597 |
80 |
(void) vdc; |
| 598 |
80 |
AN(priv); |
| 599 |
80 |
if (*priv == NULL) |
| 600 |
0 |
return (0); |
| 601 |
80 |
TAKE_OBJ_NOTNULL(vdps, priv, VDP_CHKCRC32_MAGIC); |
| 602 |
|
|
| 603 |
80 |
if (vdps->crc == vdps->cfg->expected) |
| 604 |
40 |
return (0); |
| 605 |
|
|
| 606 |
40 |
mode = vdps->cfg->mode; |
| 607 |
40 |
if (mode == VDP_CHK_PANIC_UNLESS_ERROR) |
| 608 |
0 |
mode = (vdps->called == 0 || vdc->retval != 0) ? VDP_CHK_LOG : VDP_CHK_PANIC; |
| 609 |
|
|
| 610 |
40 |
if (mode == VDP_CHK_LOG) { |
| 611 |
40 |
VSLb(vdc->vsl, SLT_Debug, "crc32 checksum mismatch"); |
| 612 |
40 |
VSLb(vdc->vsl, SLT_Debug, "got: %08x", vdps->crc); |
| 613 |
40 |
VSLb(vdc->vsl, SLT_Debug, "exp: %08x", vdps->cfg->expected); |
| 614 |
40 |
} |
| 615 |
0 |
else if (mode == VDP_CHK_PANIC) |
| 616 |
0 |
WRONG("body checksum"); |
| 617 |
|
else |
| 618 |
0 |
WRONG("mode"); |
| 619 |
|
|
| 620 |
40 |
return (0); |
| 621 |
80 |
} |
| 622 |
|
|
| 623 |
|
static int v_matchproto_(vdp_fini_f) |
| 624 |
80 |
xyzzy_chklen_fini(struct vdp_ctx *vdc, void **priv) |
| 625 |
|
{ |
| 626 |
|
enum vdp_chk_mode_e mode; |
| 627 |
|
struct vdp_chklen_s *vdps; |
| 628 |
|
|
| 629 |
80 |
(void) vdc; |
| 630 |
80 |
AN(priv); |
| 631 |
80 |
if (*priv == NULL) |
| 632 |
0 |
return (0); |
| 633 |
80 |
TAKE_OBJ_NOTNULL(vdps, priv, VDP_CHKLEN_MAGIC); |
| 634 |
|
|
| 635 |
80 |
if (vdps->bytes == vdps->cfg->expected) |
| 636 |
40 |
return (0); |
| 637 |
|
|
| 638 |
40 |
mode = vdps->cfg->mode; |
| 639 |
40 |
if (mode == VDP_CHK_PANIC_UNLESS_ERROR) |
| 640 |
0 |
mode = (vdps->called == 0 || vdc->retval != 0) ? VDP_CHK_LOG : VDP_CHK_PANIC; |
| 641 |
|
|
| 642 |
40 |
if (mode == VDP_CHK_LOG) { |
| 643 |
40 |
VSLb(vdc->vsl, SLT_Debug, "length mismatch"); |
| 644 |
40 |
VSLb(vdc->vsl, SLT_Debug, "got: %zd", vdps->bytes); |
| 645 |
40 |
VSLb(vdc->vsl, SLT_Debug, "exp: %zd", vdps->cfg->expected); |
| 646 |
40 |
} |
| 647 |
0 |
else if (mode == VDP_CHK_PANIC) |
| 648 |
0 |
WRONG("body length"); |
| 649 |
|
else |
| 650 |
0 |
WRONG("mode"); |
| 651 |
|
|
| 652 |
40 |
return (0); |
| 653 |
80 |
} |
| 654 |
|
|
| 655 |
|
static const struct vdp xyzzy_vdp_chksha256 = { |
| 656 |
|
.name = "debug.chksha256", |
| 657 |
|
.init = xyzzy_chksha256_init, |
| 658 |
|
.bytes = xyzzy_chksha256_bytes, |
| 659 |
|
.fini = xyzzy_chksha256_fini, |
| 660 |
|
}; |
| 661 |
|
|
| 662 |
|
static const struct vdp xyzzy_vdp_chkcrc32 = { |
| 663 |
|
.name = "debug.chkcrc32", |
| 664 |
|
.init = xyzzy_chkcrc32_init, |
| 665 |
|
.bytes = xyzzy_chkcrc32_bytes, |
| 666 |
|
.fini = xyzzy_chkcrc32_fini, |
| 667 |
|
}; |
| 668 |
|
|
| 669 |
|
static const struct vdp xyzzy_vdp_chklen = { |
| 670 |
|
.name = "debug.chklen", |
| 671 |
|
.init = xyzzy_chklen_init, |
| 672 |
|
.bytes = xyzzy_chklen_bytes, |
| 673 |
|
.fini = xyzzy_chklen_fini, |
| 674 |
|
}; |
| 675 |
|
|
| 676 |
|
#define chkcfg(ws, cfg, magic, id, mode_e) do { \ |
| 677 |
|
struct vmod_priv *p = VRT_priv_task(ctx, id); \ |
| 678 |
|
\ |
| 679 |
|
XXXAN(p); \ |
| 680 |
|
if (p->priv == NULL) { \ |
| 681 |
|
p->priv = WS_Alloc(ws, sizeof *cfg); \ |
| 682 |
|
p->len = sizeof *cfg; \ |
| 683 |
|
} \ |
| 684 |
|
AN(p->priv); \ |
| 685 |
|
cfg = p->priv; \ |
| 686 |
|
INIT_OBJ(cfg, magic); \ |
| 687 |
|
if (mode_e == VENUM(log)) \ |
| 688 |
|
cfg->mode = VDP_CHK_LOG; \ |
| 689 |
|
else if (mode_e == VENUM(panic)) \ |
| 690 |
|
cfg->mode = VDP_CHK_PANIC; \ |
| 691 |
|
else if (mode_e == VENUM(panic_unless_error)) \ |
| 692 |
|
cfg->mode = VDP_CHK_PANIC_UNLESS_ERROR; \ |
| 693 |
|
else \ |
| 694 |
|
WRONG("mode"); \ |
| 695 |
|
} while(0) |
| 696 |
|
|
| 697 |
|
VCL_VOID v_matchproto_(td_xyzzy_debug_chksha256) |
| 698 |
80 |
xyzzy_chksha256(VRT_CTX, VCL_BLOB blob, VCL_ENUM mode_e) |
| 699 |
|
{ |
| 700 |
|
struct vdp_chksha256_cfg_s *cfg; |
| 701 |
|
size_t l; |
| 702 |
|
|
| 703 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 704 |
80 |
CHECK_OBJ_NOTNULL(blob, VRT_BLOB_MAGIC); |
| 705 |
80 |
XXXAN(blob->blob); |
| 706 |
80 |
XXXAN(blob->len); |
| 707 |
|
|
| 708 |
80 |
chkcfg(ctx->ws, cfg, VDP_CHKSHA256_CFG_MAGIC, chksha256_priv_id, mode_e); |
| 709 |
|
|
| 710 |
80 |
l = blob->len; |
| 711 |
80 |
if (l > sizeof cfg->expected) |
| 712 |
0 |
l = sizeof cfg->expected; |
| 713 |
80 |
memcpy(cfg->expected, blob->blob, l); |
| 714 |
|
|
| 715 |
80 |
} |
| 716 |
|
|
| 717 |
|
VCL_VOID v_matchproto_(td_xyzzy_debug_chkcrc32) |
| 718 |
80 |
xyzzy_chkcrc32(VRT_CTX, VCL_INT expected, VCL_ENUM mode_e) |
| 719 |
|
{ |
| 720 |
|
struct vdp_chkcrc32_cfg_s *cfg; |
| 721 |
|
|
| 722 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 723 |
|
|
| 724 |
80 |
chkcfg(ctx->ws, cfg, VDP_CHKCRC32_CFG_MAGIC, chkcrc32_priv_id, mode_e); |
| 725 |
|
|
| 726 |
80 |
if (expected < 0) |
| 727 |
0 |
expected = 0; |
| 728 |
80 |
cfg->expected = (uintmax_t)expected % UINT32_MAX; |
| 729 |
80 |
} |
| 730 |
|
|
| 731 |
|
VCL_VOID v_matchproto_(td_xyzzy_debug_chklen) |
| 732 |
80 |
xyzzy_chklen(VRT_CTX, VCL_BYTES expected, VCL_ENUM mode_e) |
| 733 |
|
{ |
| 734 |
|
struct vdp_chklen_cfg_s *cfg; |
| 735 |
|
|
| 736 |
80 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 737 |
|
|
| 738 |
80 |
chkcfg(ctx->ws, cfg, VDP_CHKLEN_CFG_MAGIC, chklen_priv_id, mode_e); |
| 739 |
|
|
| 740 |
80 |
cfg->expected = expected; |
| 741 |
80 |
} |
| 742 |
|
|
| 743 |
|
/********************************************************************** |
| 744 |
|
* reserve thread_workspace |
| 745 |
|
*/ |
| 746 |
|
|
| 747 |
|
static int v_matchproto_(vdp_init_f) |
| 748 |
40 |
xyzzy_awshog_init(VRT_CTX, struct vdp_ctx *vdc, void **priv) |
| 749 |
|
{ |
| 750 |
|
struct ws *aws; |
| 751 |
|
unsigned u; |
| 752 |
|
|
| 753 |
40 |
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC); |
| 754 |
40 |
CHECK_OBJ_NOTNULL(vdc, VDP_CTX_MAGIC); |
| 755 |
40 |
CHECK_OBJ_ORNULL(vdc->oc, OBJCORE_MAGIC); |
| 756 |
40 |
CHECK_OBJ_NOTNULL(vdc->hp, HTTP_MAGIC); |
| 757 |
40 |
AN(vdc->clen); |
| 758 |
40 |
AN(priv); |
| 759 |
|
|
| 760 |
40 |
if (ctx->req != NULL) |
| 761 |
0 |
aws = ctx->req->wrk->aws; |
| 762 |
40 |
else if (ctx->bo != NULL) |
| 763 |
40 |
aws = ctx->bo->wrk->aws; |
| 764 |
|
else |
| 765 |
0 |
WRONG("neither req nor bo"); |
| 766 |
|
|
| 767 |
40 |
u = WS_ReserveAll(aws); |
| 768 |
40 |
WS_Release(aws, 0); |
| 769 |
40 |
(void) WS_Alloc(aws, u); |
| 770 |
40 |
return (1); |
| 771 |
|
} |
| 772 |
|
|
| 773 |
|
static const struct vdp xyzzy_vdp_awshog = { |
| 774 |
|
.name = "debug.awshog", |
| 775 |
|
.init = xyzzy_awshog_init |
| 776 |
|
}; |
| 777 |
|
|
| 778 |
|
void |
| 779 |
4120 |
debug_add_filters(VRT_CTX) |
| 780 |
|
{ |
| 781 |
4120 |
AZ(VRT_AddFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13)); |
| 782 |
4120 |
AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_pedantic)); |
| 783 |
4120 |
AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_chunked)); |
| 784 |
4120 |
AZ(VRT_AddFilter(ctx, &xyzzy_vfp_slow, &xyzzy_vdp_slow)); |
| 785 |
4120 |
AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_chksha256)); |
| 786 |
4120 |
AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_chkcrc32)); |
| 787 |
4120 |
AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_chklen)); |
| 788 |
4120 |
AZ(VRT_AddFilter(ctx, NULL, &xyzzy_vdp_awshog)); |
| 789 |
4120 |
} |
| 790 |
|
|
| 791 |
|
void |
| 792 |
920 |
debug_remove_filters(VRT_CTX) |
| 793 |
|
{ |
| 794 |
920 |
VRT_RemoveFilter(ctx, &xyzzy_vfp_slow, &xyzzy_vdp_slow); |
| 795 |
920 |
VRT_RemoveFilter(ctx, &xyzzy_vfp_rot13, &xyzzy_vdp_rot13); |
| 796 |
920 |
VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_pedantic); |
| 797 |
920 |
VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_chunked); |
| 798 |
920 |
VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_chksha256); |
| 799 |
920 |
VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_chkcrc32); |
| 800 |
920 |
VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_chklen); |
| 801 |
920 |
VRT_RemoveFilter(ctx, NULL, &xyzzy_vdp_awshog); |
| 802 |
920 |
} |