Skip to content

Commit

Permalink
Websocket upgrade directive implementation
Browse files Browse the repository at this point in the history
Contributes to tempesta-tech#755

Signed-off-by: Aleksey Mikhaylov <[email protected]>
  • Loading branch information
ttaym committed Mar 4, 2022
1 parent 5f2851d commit 4734569
Show file tree
Hide file tree
Showing 5 changed files with 315 additions and 21 deletions.
14 changes: 9 additions & 5 deletions fw/http.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,11 +170,11 @@ typedef struct {
* Http headers table.
*
* Singular headers (in terms of RFC 7230 3.2.2) go first to protect header
* repetition attacks. See __hdr_is_singular() and don't forget to
* update the static headers array when add a new singular header here.
* If the new header is hop-by-hop (must not be forwarded and cached by Tempesta)
* it must be listed in tfw_http_init_parser_req()/tfw_http_init_parser_resp()
* for unconditionally hop-by-hop header or in __parse_connection() otherwize.
* repetition attacks. See __hdr_is_singular() and don't forget to update the
* static headers array when add a new singular header here. If the new header
* is hop-by-hop (must not be forwarded and cached by Tempesta) it must be
* listed in tfw_http_init_parser_req()/tfw_http_init_parser_resp()
* for unconditionally hop-by-hop header or in __parse_connection() otherwise.
* If the header is end-to-end it must be listed in __hbh_parser_add_data().
*
* Note: don't forget to update __http_msg_hdr_val() and
Expand Down Expand Up @@ -212,6 +212,7 @@ typedef enum {
TFW_HTTP_HDR_X_FORWARDED_FOR,
TFW_HTTP_HDR_KEEP_ALIVE,
TFW_HTTP_HDR_TRANSFER_ENCODING,
TFW_HTTP_HDR_UPGRADE,

/* Start of list of generic (raw) headers. */
TFW_HTTP_HDR_RAW,
Expand Down Expand Up @@ -239,7 +240,10 @@ enum {
*/
TFW_HTTP_B_CONN_CLOSE = TFW_HTTP_FLAGS_COMMON,
TFW_HTTP_B_CONN_KA,
TFW_HTTP_B_CONN_UPGRADE,
TFW_HTTP_B_CONN_EXTRA,
/* Request is a websocket upgrade request */
TFW_HTTP_B_UPGRADE_WEBSOCKET,
/* Chunked is last transfer encoding. */
TFW_HTTP_B_CHUNKED,
/* Chunked in the middle of applied transfer encodings. */
Expand Down
50 changes: 50 additions & 0 deletions fw/http_limits.c
Original file line number Diff line number Diff line change
Expand Up @@ -564,6 +564,49 @@ frang_http_methods_override(const TfwHttpReq *req, FrangAcc *ra,
return TFW_PASS;
}

static int
frang_http_upgrade_websocket(const TfwHttpReq *req, FrangAcc *ra,
FrangVhostCfg *f_cfg)
{
BUG_ON(!req);

switch (req->version) {
/*
* TODO upgrade websocket checks for h2 as described in RFC8441
*/
case TFW_HTTP_VER_20:
break;
/*
* Tempesta FW MUST block requests with Upgrade header but without
* upgrade option in Connection header. Tempesta FW MUST ignore
* Upgrade header for HTTP version less then HTTP/1.1.
* See RFC7230#section-6.1.
*/
case TFW_HTTP_VER_11:
case TFW_HTTP_VER_10:
case TFW_HTTP_VER_09:
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, req->flags)
&& !test_bit(TFW_HTTP_B_CONN_UPGRADE, req->flags))
{
frang_msg("upgrade request without connection option",
&FRANG_ACC2CLI(ra)->addr, ": protocol: %s\n",
"websocket");
return TFW_BLOCK;
}
if (req->version == TFW_HTTP_VER_10
|| req->version == TFW_HTTP_VER_09)
{
clear_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET,
((TfwHttpReq *)req)->flags);
}
break;
default:
return TFW_BLOCK;
}

return TFW_PASS;
}

static int
frang_http_ct_check(const TfwHttpReq *req, FrangAcc *ra, FrangCtVals *ct_vals)
{
Expand Down Expand Up @@ -1189,6 +1232,13 @@ frang_http_req_process(FrangAcc *ra, TfwConn *conn, TfwFsmData *data,
if (f_cfg->http_ct_required || f_cfg->http_ct_vals)
r = frang_http_ct_check(req, ra, f_cfg->http_ct_vals);

/* Do checks for websocket upgrade */
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, req->flags)
&& (r = frang_http_upgrade_websocket(req, ra, f_cfg)))
{
T_FSM_EXIT();
}

__FRANG_FSM_MOVE(Frang_Req_Body_Start);
}

Expand Down
4 changes: 4 additions & 0 deletions fw/http_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ tfw_http_msg_resp_spec_hid(const TfwStr *hdr)
TfwStrDefV("transfer-encoding:",TFW_HTTP_HDR_TRANSFER_ENCODING),
TfwStrDefV("x-forwarded-for:", TFW_HTTP_HDR_X_FORWARDED_FOR),
TfwStrDefV("x-tempesta-cache:", TFW_HTTP_HDR_X_TEMPESTA_CACHE),
TfwStrDefV("upgrade:", TFW_HTTP_HDR_UPGRADE),
};

BUILD_BUG_ON(ARRAY_SIZE(resp_hdrs) !=
Expand Down Expand Up @@ -182,6 +183,7 @@ tfw_http_msg_req_spec_hid(const TfwStr *hdr)
TfwStrDefV("user-agent:", TFW_HTTP_HDR_USER_AGENT),
TfwStrDefV("x-forwarded-for:", TFW_HTTP_HDR_X_FORWARDED_FOR),
TfwStrDefV("x-tempesta-cache:", TFW_HTTP_HDR_X_TEMPESTA_CACHE),
TfwStrDefV("upgrade:", TFW_HTTP_HDR_UPGRADE),
};

BUILD_BUG_ON(ARRAY_SIZE(req_hdrs) !=
Expand Down Expand Up @@ -215,6 +217,7 @@ __http_msg_hdr_val(TfwStr *hdr, unsigned id, TfwStr *val, bool client)
[TFW_HTTP_HDR_SET_COOKIE] = SLEN("Set-Cookie:"),
[TFW_HTTP_HDR_ETAG] = SLEN("ETag:"),
[TFW_HTTP_HDR_REFERER] = SLEN("Referer:"),
[TFW_HTTP_HDR_UPGRADE] = SLEN("Upgrade:"),
},
(unsigned char []) {
[TFW_HTTP_HDR_HOST] = SLEN("Host:"),
Expand All @@ -229,6 +232,7 @@ __http_msg_hdr_val(TfwStr *hdr, unsigned id, TfwStr *val, bool client)
[TFW_HTTP_HDR_COOKIE] = SLEN("Cookie:"),
[TFW_HTTP_HDR_IF_NONE_MATCH] = SLEN("If-None-Match:"),
[TFW_HTTP_HDR_REFERER] = SLEN("Referer:"),
[TFW_HTTP_HDR_UPGRADE] = SLEN("Upgrade:"),
},
};
TfwStr *c, *end;
Expand Down
Loading

0 comments on commit 4734569

Please sign in to comment.