Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions etc/tempesta_fw.conf
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,8 @@
# Rule sets netfilter marks into all skbs for all matched requests.
# - 'block'
# Rule blocks all matched requests.
# - 'jsch'
# Rule responds with JS challenage to matched requests.
#
# VAL is possible value for specified action; only 'mark' action is allowed to
# have value (unsigned integer type).
Expand Down
1 change: 0 additions & 1 deletion fw/hpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -1309,7 +1309,6 @@ tfw_hpack_hdr_set(TfwHPack *__restrict hp, TfwHttpReq *__restrict req,
break;
case TFW_TAG_HDR_ACCEPT:
parser->_hdr_tag = TFW_HTTP_HDR_RAW;
h2_set_hdr_accept(req, &entry->cstate);
break;
case TFW_TAG_HDR_CONTENT_ENCODING:
parser->_hdr_tag = TFW_HTTP_HDR_CONTENT_ENCODING;
Expand Down
1 change: 0 additions & 1 deletion fw/hpack.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@ typedef enum {
*/
typedef struct {
union {
unsigned char accept_text_html;
long if_msince_date;
unsigned long authority_port;
unsigned char ifnmatch_etag_any;
Expand Down
30 changes: 0 additions & 30 deletions fw/http_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -2636,7 +2636,6 @@ __req_parse_accept(TfwHttpReq *req, unsigned char *data, size_t len)
}

__FSM_STATE(Req_I_AfterTextSlashToken) {
TRY_STR("html", Req_I_AfterTextSlashToken, Req_I_AcceptHtml);
TRY_STR_INIT();
__FSM_I_JMP(Req_I_Subtype);
}
Expand All @@ -2653,14 +2652,6 @@ __req_parse_accept(TfwHttpReq *req, unsigned char *data, size_t len)
return CSTR_NEQ;
}

__FSM_STATE(Req_I_AcceptHtml) {
if (IS_WS(c) || c == ',' || c == ';' || IS_CRLF(c)) {
__set_bit(TFW_HTTP_B_ACCEPT_HTML, req->flags);
__FSM_I_JMP(I_EoT);
}
__FSM_I_JMP(Req_I_Subtype);
}

__FSM_STATE(Req_I_Type) {
__FSM_I_MATCH_MOVE(token, Req_I_Type);
c = *(p + __fsm_sz);
Expand Down Expand Up @@ -7179,13 +7170,6 @@ __h2_req_parse_authority(TfwHttpReq *req, unsigned char *data, size_t len,
}
STACK_FRAME_NON_STANDARD(__h2_req_parse_authority);

void
h2_set_hdr_accept(TfwHttpReq *req, const TfwCachedHeaderState *cstate)
{
if (cstate->is_set && cstate->accept_text_html)
__set_bit(TFW_HTTP_B_ACCEPT_HTML, req->flags);
}

static int
__h2_req_parse_accept(TfwHttpReq *req, unsigned char *data, size_t len,
bool fin)
Expand Down Expand Up @@ -7236,12 +7220,6 @@ __h2_req_parse_accept(TfwHttpReq *req, unsigned char *data, size_t len,
}

__FSM_STATE(Req_I_AfterTextSlashToken) {
H2_TRY_STR_LAMBDA("html", {
parser->cstate.is_set = 1;
parser->cstate.accept_text_html = 1;
h2_set_hdr_accept(req, &parser->cstate);
__FSM_EXIT(CSTR_EQ);
}, Req_I_AfterTextSlashToken, Req_I_AcceptHtml);
TRY_STR_INIT();
__FSM_I_JMP(Req_I_Subtype);
}
Expand All @@ -7258,14 +7236,6 @@ __h2_req_parse_accept(TfwHttpReq *req, unsigned char *data, size_t len,
return CSTR_NEQ;
}

__FSM_STATE(Req_I_AcceptHtml) {
if (IS_WS(c) || c == ',' || c == ';') {
__set_bit(TFW_HTTP_B_ACCEPT_HTML, req->flags);
__FSM_I_JMP(I_EoT);
}
__FSM_I_JMP(Req_I_Subtype);
}

__FSM_STATE(Req_I_Type) {
__FSM_H2_I_MATCH_MOVE_LAMBDA(token, Req_I_Type, {
__FSM_EXIT(CSTR_NEQ);
Expand Down
1 change: 0 additions & 1 deletion fw/http_parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,6 @@ int tfw_http_parse_terminate(TfwHttpMsg *hm);
bool tfw_http_parse_is_done(TfwHttpMsg *hm);

void tfw_idx_hdr_parse_host_port(TfwHttpReq *req, TfwStr *hdr);
void h2_set_hdr_accept(TfwHttpReq *req, const TfwCachedHeaderState *cstate);
int h2_set_hdr_if_mod_since(TfwHttpReq *req,
const TfwCachedHeaderState *cstate);
void h2_set_hdr_authority(TfwHttpReq *req, const TfwCachedHeaderState *cstate);
Expand Down
12 changes: 5 additions & 7 deletions fw/http_sess.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
* JS challenge client should execute it and send new request with
* appropriate cookie just in time.
*
* Copyright (C) 2015-2024 Tempesta Technologies, Inc.
* Copyright (C) 2015-2025 Tempesta Technologies, Inc.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
Expand Down Expand Up @@ -116,19 +116,17 @@ tfw_http_sess_cookie_enabled(TfwHttpReq *req)
}

/**
* Normal browser must be able to execute the challenge: not all requests
* can be challenged, e.g. images - a browser won't execute the JS code if
* receives the challenge. Send redirect only for requests with
* 'Accept: text/html' and GET method.
* Send JS challenge to a client only if request beign
* matched by http chain "jsch" rule and it is GET request.
*/
static bool
tfw_http_sticky_redirect_applied(TfwHttpReq *req)
{
if (!req->vhost->cookie->js_challenge)
return true;

return (req->method == TFW_HTTP_METH_GET)
&& test_bit(TFW_HTTP_B_ACCEPT_HTML, req->flags);
return req->method == TFW_HTTP_METH_GET &&
test_bit(TFW_HTTP_B_MUST_BE_CHALLENGED, req->flags);
}

static int
Expand Down
5 changes: 5 additions & 0 deletions fw/http_tbl.c
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,11 @@ tfw_cfgop_http_rule(TfwCfgSpec *cs, TfwCfgEntry *e)
rule->act.type = TFW_HTTP_MATCH_ACT_CACHE_TTL;
rule->act.cache_ttl = act_val_parsed;
}
else if (!strcasecmp(action, "jsch")) {
rule->act.type = TFW_HTTP_MATCH_ACT_FLAG;
rule->act.flg.fid = TFW_HTTP_B_MUST_BE_CHALLENGED;
rule->act.flg.set = true;
}
else if (action && action_val &&
!tfw_cfg_parse_uint(action, &rule->act.redir.resp_code))
{
Expand Down
4 changes: 2 additions & 2 deletions fw/http_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,6 @@ enum {
TFW_HTTP_B_CHAIN_NO_CACHE,
/* Request is non-idempotent. */
TFW_HTTP_B_NON_IDEMP,
/* Request stated 'Accept: text/html' header */
TFW_HTTP_B_ACCEPT_HTML,
/* Request is created by HTTP health monitor. */
TFW_HTTP_B_HMONITOR,
/* Client was disconnected, drop the request. */
Expand All @@ -108,6 +106,8 @@ enum {
TFW_HTTP_B_NEED_STRIP_LEADING_CR,
/* Need strip 1 leading LF */
TFW_HTTP_B_NEED_STRIP_LEADING_LF,
/* JS challenge must be applied. */
TFW_HTTP_B_MUST_BE_CHALLENGED,
/*
* Request should be challenged, but requested resourse
* is non-challengeable. Try to service such request
Expand Down
25 changes: 8 additions & 17 deletions fw/t/unit/test_http1_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1660,15 +1660,8 @@ TEST(http1_parser, folding)

TEST(http1_parser, accept)
{
#define __FOR_ACCEPT(accept_val, EXPECT_HTML_MACRO) \
FOR_REQ_SIMPLE("Accept:" accept_val) \
{ \
EXPECT_HTML_MACRO(test_bit(TFW_HTTP_B_ACCEPT_HTML, \
req->flags)); \
}
#define FOR_ACCEPT(accept_val) FOR_REQ_SIMPLE("Accept:" accept_val)

#define FOR_ACCEPT(accept_val) __FOR_ACCEPT(accept_val, EXPECT_FALSE)
#define FOR_ACCEPT_HTML(accept_val) __FOR_ACCEPT(accept_val, EXPECT_TRUE)
#define EXPECT_BLOCK_ACCEPT(header) EXPECT_BLOCK_REQ_SIMPLE("Accept:"header)

#define TEST_ACCEPT_EXT(HEAD) \
Expand Down Expand Up @@ -1768,23 +1761,21 @@ TEST(http1_parser, accept)
EXPECT_BLOCK_ACCEPT("*/,,");

/* HTML validations */
FOR_ACCEPT_HTML(" text/html ");
FOR_ACCEPT_HTML(" text/html, application/xhtml+xml ");
FOR_ACCEPT_HTML(" text/html;q=0.8 ");
FOR_ACCEPT_HTML(" text/html,application/xhtml+xml,application/xml;"
FOR_ACCEPT(" text/html ");
FOR_ACCEPT(" text/html, application/xhtml+xml ");
FOR_ACCEPT(" text/html;q=0.8 ");
FOR_ACCEPT(" text/html,application/xhtml+xml,application/xml;"
"q=0.9,image/webp,image/apng,*/*;q=0.8");
FOR_ACCEPT_HTML(" text/html, */* ");
FOR_ACCEPT_HTML(" text/html, invalid/invalid ; key=val; q=0.5 ");
FOR_ACCEPT_HTML(" invalid/invalid; param=\"value value\", text/html");
FOR_ACCEPT(" text/html, */* ");
FOR_ACCEPT(" text/html, invalid/invalid ; key=val; q=0.5 ");
FOR_ACCEPT(" invalid/invalid; param=\"value value\", text/html");
FOR_ACCEPT(" text/* ");
FOR_ACCEPT(" invalid/invalid; q=0.5; key=val, */* ");
FOR_ACCEPT(" textK/html");

#undef TEST_ACCEPT_EXT
#undef EXPECT_BLOCK_ACCEPT
#undef FOR_ACCEPT_HTML
#undef FOR_ACCEPT
#undef __FOR_ACCEPT
}

TEST(http1_parser, host)
Expand Down
27 changes: 9 additions & 18 deletions fw/t/unit/test_http2_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -1161,22 +1161,15 @@ TEST(http2_parser, ows)
#undef EXPECT_BLOCK_REQ_H2_METHOD
}

#define __FOR_ACCEPT(accept_val, EXPECT_HTML_MACRO) \
#define FOR_ACCEPT(accept_val) \
FOR_REQ_H2( \
HEADERS_FRAME_BEGIN(); \
HEADER(WO_IND(NAME(":method"), VALUE("GET"))); \
HEADER(WO_IND(NAME(":scheme"), VALUE("https"))); \
HEADER(WO_IND(NAME(":path"), VALUE("/"))); \
HEADER(WO_IND(NAME("accept"), VALUE(accept_val))); \
HEADERS_FRAME_END(); \
) \
{ \
EXPECT_HTML_MACRO(test_bit(TFW_HTTP_B_ACCEPT_HTML, \
req->flags)); \
}

#define FOR_ACCEPT(accept_val) __FOR_ACCEPT(accept_val, EXPECT_FALSE)
#define FOR_ACCEPT_HTML(accept_val) __FOR_ACCEPT(accept_val, EXPECT_TRUE)
);

#define EXPECT_BLOCK_REQ_H2_ACCEPT(header) \
EXPECT_BLOCK_REQ_H2( \
Expand Down Expand Up @@ -1301,14 +1294,14 @@ TEST_MPART(http2_parser, accept, 3)
EXPECT_BLOCK_REQ_H2_ACCEPT("*/");

/* HTML validations */
FOR_ACCEPT_HTML(" text/html ");
FOR_ACCEPT_HTML(" text/html, application/xhtml+xml ");
FOR_ACCEPT_HTML(" text/html;q=0.8 ");
FOR_ACCEPT_HTML(" text/html,application/xhtml+xml,application/xml;"
FOR_ACCEPT(" text/html ");
FOR_ACCEPT(" text/html, application/xhtml+xml ");
FOR_ACCEPT(" text/html;q=0.8 ");
FOR_ACCEPT(" text/html,application/xhtml+xml,application/xml;"
"q=0.9,image/webp,image/apng,*/*;q=0.8");
FOR_ACCEPT_HTML(" text/html, */* ");
FOR_ACCEPT_HTML(" text/html, invalid/invalid ; key=val; q=0.5 ");
FOR_ACCEPT_HTML(" invalid/invalid; param=\"value value\", text/html");
FOR_ACCEPT(" text/html, */* ");
FOR_ACCEPT(" text/html, invalid/invalid ; key=val; q=0.5 ");
FOR_ACCEPT(" invalid/invalid; param=\"value value\", text/html");
FOR_ACCEPT(" text/* ");
FOR_ACCEPT(" invalid/invalid; q=0.5; key=val, */* ");
FOR_ACCEPT(" textK/html");
Expand All @@ -1317,9 +1310,7 @@ TEST_MPART(http2_parser, accept, 3)

#undef TEST_ACCEPT_EXT
#undef EXPECT_BLOCK_REQ_H2_ACCEPT
#undef FOR_ACCEPT_HTML
#undef FOR_ACCEPT
#undef __FOR_ACCEPT

TEST_MPART_DEFINE(http2_parser, accept, H2_ACCEPT_TCNT,
TEST_MPART_NAME(http2_parser, accept, 0),
Expand Down