Skip to content

Commit b2257e3

Browse files
authored
Merge pull request #8 from xdecock/fix/dont-reusebuffers
Fix: correct header and request body handling, allowing the binding to be fully working
2 parents 096d5d6 + 74382f7 commit b2257e3

File tree

4 files changed

+85
-40
lines changed

4 files changed

+85
-40
lines changed

CHANGELOG.MD

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
2.0.0 - Make the binding functional - before updating, make sure you test your rules
2+
1.0.1 - Update to compile with different modsecurity version, and different varnish versions
3+
1.0.0 - Initial Proof of concept binding, some important problems occurs on this version, mostly not able to effectively act.

TODO.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Handle Varnish requests on stream (request / deliver)
2+
VRT_AddFilter(ctx, &td_sec_vfp_modsec, &td_sec_vdp_modsec);

src/vmod_sec.c

Lines changed: 69 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ typedef struct Rules_t RulesSet;
99
#endif
1010
#include <modsecurity/transaction.h>
1111

12-
1312
#include <sys/socket.h>
1413
#include <unistd.h>
1514
#include <string.h>
@@ -136,12 +135,15 @@ VCL_VOID v_matchproto_(td_sec_sec__init)
136135
int error;
137136
(void)vcl_name;
138137

138+
if (ctx->method != VCL_MET_INIT) {
139+
VRT_fail(ctx, "[vmodsec] - init can only be called from vcl_init{}");
140+
}
139141
/* Sanity check */
140142
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
141143
AN(vpp);
142144
AZ(*vpp);
143145

144-
VSL(SLT_Error, 0, "[vmodsec] - object [%s] initialized using modsecurity %s",
146+
VSL(SLT_Debug, 0, "[vmodsec] - object [%s] initialized using modsecurity %s",
145147
vcl_name, MODSECURITY_VERSION);
146148

147149
modsec = msc_init();
@@ -188,6 +190,11 @@ VCL_INT v_matchproto_(td_sec_sec_add_rule)
188190
const char *error = NULL;
189191
VSL(SLT_Debug, 0, "[vmodsec] - [%s] - VCL provided rule", rule);
190192
CHECK_OBJ_NOTNULL(vp, VMOD_SEC_SEC_MAGIC_BITS);
193+
194+
if (ctx->method != VCL_MET_INIT) {
195+
VRT_fail(ctx, "[vmodsec] - .add_rule can only be called from vcl_init{}");
196+
}
197+
191198
ret = msc_rules_add(vp->rules_set, rule, &error);
192199
if (ret < 0)
193200
{
@@ -208,6 +215,10 @@ VCL_INT v_matchproto_(td_sec_sec_add_rules)
208215
{
209216
int ret;
210217
const char *error = NULL;
218+
if (ctx->method != VCL_MET_INIT) {
219+
VRT_fail(ctx, "[vmodsec] - .add_rules can only be called from vcl_init{}");
220+
}
221+
211222

212223
VSL(SLT_Debug, 0, "[vmodsec] - [%s] - Try to load the rules", args->rules_path);
213224
CHECK_OBJ_NOTNULL(vp, VMOD_SEC_SEC_MAGIC_BITS);
@@ -271,6 +282,10 @@ VCL_INT v_matchproto_(td_sec_sec_new_conn)
271282
CHECK_OBJ_NOTNULL(ctx, VRT_CTX_MAGIC);
272283
CHECK_OBJ_NOTNULL(vp, VMOD_SEC_SEC_MAGIC_BITS);
273284

285+
if (ctx->method != VCL_MET_RECV) {
286+
VRT_fail(ctx, "[vmodsec] - new_conn can only be called from vcl_recv{}");
287+
}
288+
274289
struct vmod_priv *p;
275290
if (args->arg1 == NULL) {
276291
return 0;
@@ -337,6 +352,7 @@ VCL_INT v_matchproto_(td_sec_sec_process_url)
337352
VSL(SLT_Error, ctx->sp->vxid, "[vmodsec] - connection has not been started, closing");
338353
return -1;
339354
}
355+
340356
struct vmod_sec_struct_trans_int *transInt = (struct vmod_sec_struct_trans_int *)priv->priv;
341357
/* This will be used to Initialise the original URL */
342358
msc_process_uri(transInt->trans, req_url, protocol, http_version);
@@ -352,16 +368,17 @@ VCL_INT v_matchproto_(td_sec_sec_process_url)
352368

353369
/* Handling headers */
354370
unsigned u;
355-
const struct http *hp = ctx->req->http;
371+
const struct http *hp = ctx->http_req;
356372
#ifdef VMOD_SEC_DEBUG
357373
VSL(SLT_Debug, ctx->sp->vxid, "[vmodsec] - Found %d headers, Start at %d, need to ingest %d headers", hp->nhd, HTTP_HDR_FIRST, hp->nhd - HTTP_HDR_FIRST);
358374
#endif
359-
// Freed after loop
360-
char *headerName = malloc(8192);
361-
char *headerValue = malloc(8192);
375+
int headerCount = hp->nhd - HTTP_HDR_FIRST;
376+
char **headersNames = (char **)malloc(sizeof(char *) * headerCount);
377+
char **headersValues = (char **)malloc(sizeof(char *) * headerCount);
362378

363379
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++)
364380
{
381+
int headerPos = u-HTTP_HDR_FIRST;
365382
Tcheck(hp->hd[u]);
366383
const char *header = hp->hd[u].b;
367384
long int hlen = strlen(header);
@@ -372,24 +389,32 @@ VCL_INT v_matchproto_(td_sec_sec_process_url)
372389
continue;
373390
}
374391
/* Copy headers */
375-
strncpy(headerName, header, pos);
376-
headerName[pos] = '\0';
392+
headersNames[headerPos] = (char *)malloc(pos+1);
393+
strncpy(headersNames[headerPos], header, pos);
394+
headersNames[headerPos][pos] = '\0';
377395
// Find spaces
378396
pos += 1 /* : */ + strspn(&header[pos + 1], " \r\n\t"); // LWS = [CRLF] 1*( SP | HT ) chr(9,10,13,32)
379-
strncpy(headerValue, &header[pos], hlen - pos);
380-
headerValue[hlen - pos] = '\0';
381-
msc_add_request_header(transInt->trans, headerName, headerValue);
397+
// Copy value
398+
headersValues[headerPos] = (char *)malloc(hlen - pos +1);
399+
strncpy(headersValues[headerPos], &header[pos], hlen - pos);
400+
headersValues[headerPos][hlen - pos] = '\0';
401+
// FIXME : use msc_add_n_request_header
402+
msc_add_request_header(transInt->trans, headersNames[headerPos], headersValues[headerPos]);
382403
#ifdef VMOD_SEC_DEBUG
383404
VSL(SLT_Debug, ctx->sp->vxid,
384-
"[vmodsec] - Additional header provided %s: %s", headerName, headerValue);
405+
"[vmodsec] - Additional header provided %s: %s", headersNames[headerPos], headersValues[headerPos]);
385406
#endif
386407
}
387-
free(headerName);
388-
free(headerValue);
389408
#ifdef VMOD_SEC_DEBUG
390409
VSL(SLT_Debug, ctx->sp->vxid, "[vmodsec] - Processing Request Headers");
391410
#endif
392411
msc_process_request_headers(transInt->trans);
412+
for (u = 0; u<headerCount; ++u) {
413+
free(headersNames[u]);
414+
free(headersValues[u]);
415+
}
416+
free(headersNames);
417+
free(headersValues);
393418
return process_intervention(transInt);
394419
}
395420

@@ -431,10 +456,16 @@ VCL_INT v_matchproto_(td_sec_sec_do_process_request_body)
431456
if (capture_body == 1)
432457
{
433458
const struct http *hp = ctx->req->http;
459+
if (ctx->req->req_body_status == BS_NONE)
460+
{
461+
msc_process_request_body(transInt->trans);
462+
return process_intervention(transInt);
463+
}
434464
if (ctx->req->req_body_status != BS_CACHED)
435465
{
436466
VSL(SLT_Debug, ctx->sp->vxid, "[vmodsec] - Unbuffered req.body");
437-
return -1;
467+
msc_process_request_body(transInt->trans);
468+
return process_intervention(transInt);
438469
}
439470

440471
int ret;
@@ -447,8 +478,8 @@ VCL_INT v_matchproto_(td_sec_sec_do_process_request_body)
447478
{
448479
VSL(SLT_Error, ctx->sp->vxid,
449480
"[vmodsec] - Iteration on req.body didn't succeed. %d", ret);
450-
451-
return -1;
481+
msc_process_request_body(transInt->trans);
482+
return process_intervention(transInt);
452483
}
453484

454485
VSL(SLT_Debug, ctx->sp->vxid, "[vmodsec] - Processing Request Body");
@@ -475,18 +506,20 @@ VCL_INT v_matchproto_(td_sec_sec_process_response)
475506

476507
/* Handling headers */
477508
unsigned u;
478-
const struct http *hp = ctx->req->resp;
509+
const struct http *hp = ctx->http_resp;
479510
#ifdef VMOD_SEC_DEBUG
480511
VSL(SLT_Debug, ctx->sp->vxid, "[vmodsec] - Processing Response Headers");
481512
VSL(SLT_Debug, ctx->sp->vxid, "[vmodsec] - Found %d headers, Start at %d, need to ingest %d headers",
482513
hp->nhd, HTTP_HDR_FIRST, hp->nhd - HTTP_HDR_FIRST);
483514
#endif
515+
int headerCount = hp->nhd - HTTP_HDR_FIRST;
484516
// freed after loop
485-
char *headerName = malloc(8192);
486-
char *headerValue = malloc(8192);
517+
char **headersNames = (char **)malloc(sizeof(char *) * headerCount);
518+
char **headersValues = (char **)malloc(sizeof(char *) * headerCount);;
487519

488520
for (u = HTTP_HDR_FIRST; u < hp->nhd; u++)
489521
{
522+
int headerPos = u-HTTP_HDR_FIRST;
490523
Tcheck(hp->hd[u]);
491524
const char *header = hp->hd[u].b;
492525
long int hlen = strlen(header);
@@ -497,21 +530,27 @@ VCL_INT v_matchproto_(td_sec_sec_process_response)
497530
continue;
498531
}
499532
/* Copy headers */
500-
strncpy(headerName, header, pos);
501-
headerName[pos] = '\0';
533+
headersNames[headerPos] = malloc(pos+1);
534+
strncpy(headersNames[headerPos], header, pos);
535+
headersNames[headerPos][pos] = '\0';
502536
// Find spaces
503537
pos += 1 /* : */ + strspn(&header[pos + 1], " \r\n\t"); // LWS = [CRLF] 1*( SP | HT ) chr(9,10,13,32)
504-
strncpy(headerValue, &header[pos], hlen - pos);
505-
headerValue[hlen - pos] = '\0';
506-
msc_add_response_header(transInt->trans, headerName, headerValue);
538+
headersValues[headerPos] = (char *)malloc(hlen - pos +1);
539+
strncpy(headersValues[headerPos], &header[pos], hlen - pos);
540+
headersValues[headerPos][hlen - pos] = '\0';
541+
msc_add_response_header(transInt->trans, headersNames[headerPos], headersValues[headerPos]);
507542
#ifdef VMOD_SEC_DEBUG
508543
VSL(SLT_Debug, ctx->sp->vxid, "[vmodsec] - Additional response header provided %s: %s",
509-
headerName, headerValue);
544+
headersNames[headerPos], headersValues[headerPos]);
510545
#endif
511546
}
512-
free(headerName);
513-
free(headerValue);
514547
msc_process_response_headers(transInt->trans, ctx->req->resp->status, protocol);
548+
for (u = 0; u<headerCount; ++u) {
549+
free(headersNames[u]);
550+
free(headersValues[u]);
551+
}
552+
free(headersNames);
553+
free(headersValues);
515554
return process_intervention(transInt);
516555
}
517556

@@ -562,7 +601,8 @@ VCL_INT v_matchproto_(td_sec_sec_do_process_response_body)
562601
VSL(SLT_Error, ctx->sp->vxid,
563602
"[vmodsec] - Iteration on resp.body didn't succeed. %d", ret);
564603

565-
return -1;
604+
msc_process_response_body(transInt->trans);
605+
return process_intervention(transInt);
566606
}
567607

568608
VSL(SLT_Debug, ctx->sp->vxid, "[vmodsec] - Processing Response Body");

src/vtc/vmod_sec_load_remote_rule.vtc

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,25 @@
11
varnishtest "Check if we got the version string"
22

33
server s1 {
4-
rxreq
5-
txresp
4+
rxreq
5+
txresp
66
} -start
77

88
varnish v1 -vcl+backend {
99
import sec;
1010

11-
sub vcl_init {
12-
new xsec = sec.sec();
13-
14-
}
11+
sub vcl_init {
12+
new xsec = sec.sec();
13+
xsec.add_rules("https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt", "test");
14+
}
1515
sub vcl_deliver {
16-
set resp.http.X-ModSec-RulesCouns = xsec.add_rules("https://www.modsecurity.org/modsecurity-regression-test-secremoterules.txt", "test");
16+
set resp.http.X-ModSec-RulesCount = 50;
1717
}
1818
} -start
1919

2020
client c1 {
21-
txreq
22-
rxresp
23-
expect resp.status == 200
24-
expect resp.http.X-ModSec-RulesCouns ~ ^[0-9]+$
21+
txreq
22+
rxresp
23+
expect resp.status == 200
24+
expect resp.http.X-ModSec-RulesCount ~ ^[0-9]+$
2525
} -run

0 commit comments

Comments
 (0)