Skip to content

Commit 4734569

Browse files
committed
Websocket upgrade directive implementation
Contributes to tempesta-tech#755 Signed-off-by: Aleksey Mikhaylov <[email protected]>
1 parent 5f2851d commit 4734569

File tree

5 files changed

+315
-21
lines changed

5 files changed

+315
-21
lines changed

fw/http.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,11 @@ typedef struct {
170170
* Http headers table.
171171
*
172172
* Singular headers (in terms of RFC 7230 3.2.2) go first to protect header
173-
* repetition attacks. See __hdr_is_singular() and don't forget to
174-
* update the static headers array when add a new singular header here.
175-
* If the new header is hop-by-hop (must not be forwarded and cached by Tempesta)
176-
* it must be listed in tfw_http_init_parser_req()/tfw_http_init_parser_resp()
177-
* for unconditionally hop-by-hop header or in __parse_connection() otherwize.
173+
* repetition attacks. See __hdr_is_singular() and don't forget to update the
174+
* static headers array when add a new singular header here. If the new header
175+
* is hop-by-hop (must not be forwarded and cached by Tempesta) it must be
176+
* listed in tfw_http_init_parser_req()/tfw_http_init_parser_resp()
177+
* for unconditionally hop-by-hop header or in __parse_connection() otherwise.
178178
* If the header is end-to-end it must be listed in __hbh_parser_add_data().
179179
*
180180
* Note: don't forget to update __http_msg_hdr_val() and
@@ -212,6 +212,7 @@ typedef enum {
212212
TFW_HTTP_HDR_X_FORWARDED_FOR,
213213
TFW_HTTP_HDR_KEEP_ALIVE,
214214
TFW_HTTP_HDR_TRANSFER_ENCODING,
215+
TFW_HTTP_HDR_UPGRADE,
215216

216217
/* Start of list of generic (raw) headers. */
217218
TFW_HTTP_HDR_RAW,
@@ -239,7 +240,10 @@ enum {
239240
*/
240241
TFW_HTTP_B_CONN_CLOSE = TFW_HTTP_FLAGS_COMMON,
241242
TFW_HTTP_B_CONN_KA,
243+
TFW_HTTP_B_CONN_UPGRADE,
242244
TFW_HTTP_B_CONN_EXTRA,
245+
/* Request is a websocket upgrade request */
246+
TFW_HTTP_B_UPGRADE_WEBSOCKET,
243247
/* Chunked is last transfer encoding. */
244248
TFW_HTTP_B_CHUNKED,
245249
/* Chunked in the middle of applied transfer encodings. */

fw/http_limits.c

+50
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,49 @@ frang_http_methods_override(const TfwHttpReq *req, FrangAcc *ra,
564564
return TFW_PASS;
565565
}
566566

567+
static int
568+
frang_http_upgrade_websocket(const TfwHttpReq *req, FrangAcc *ra,
569+
FrangVhostCfg *f_cfg)
570+
{
571+
BUG_ON(!req);
572+
573+
switch (req->version) {
574+
/*
575+
* TODO upgrade websocket checks for h2 as described in RFC8441
576+
*/
577+
case TFW_HTTP_VER_20:
578+
break;
579+
/*
580+
* Tempesta FW MUST block requests with Upgrade header but without
581+
* upgrade option in Connection header. Tempesta FW MUST ignore
582+
* Upgrade header for HTTP version less then HTTP/1.1.
583+
* See RFC7230#section-6.1.
584+
*/
585+
case TFW_HTTP_VER_11:
586+
case TFW_HTTP_VER_10:
587+
case TFW_HTTP_VER_09:
588+
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, req->flags)
589+
&& !test_bit(TFW_HTTP_B_CONN_UPGRADE, req->flags))
590+
{
591+
frang_msg("upgrade request without connection option",
592+
&FRANG_ACC2CLI(ra)->addr, ": protocol: %s\n",
593+
"websocket");
594+
return TFW_BLOCK;
595+
}
596+
if (req->version == TFW_HTTP_VER_10
597+
|| req->version == TFW_HTTP_VER_09)
598+
{
599+
clear_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET,
600+
((TfwHttpReq *)req)->flags);
601+
}
602+
break;
603+
default:
604+
return TFW_BLOCK;
605+
}
606+
607+
return TFW_PASS;
608+
}
609+
567610
static int
568611
frang_http_ct_check(const TfwHttpReq *req, FrangAcc *ra, FrangCtVals *ct_vals)
569612
{
@@ -1189,6 +1232,13 @@ frang_http_req_process(FrangAcc *ra, TfwConn *conn, TfwFsmData *data,
11891232
if (f_cfg->http_ct_required || f_cfg->http_ct_vals)
11901233
r = frang_http_ct_check(req, ra, f_cfg->http_ct_vals);
11911234

1235+
/* Do checks for websocket upgrade */
1236+
if (test_bit(TFW_HTTP_B_UPGRADE_WEBSOCKET, req->flags)
1237+
&& (r = frang_http_upgrade_websocket(req, ra, f_cfg)))
1238+
{
1239+
T_FSM_EXIT();
1240+
}
1241+
11921242
__FRANG_FSM_MOVE(Frang_Req_Body_Start);
11931243
}
11941244

fw/http_msg.c

+4
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ tfw_http_msg_resp_spec_hid(const TfwStr *hdr)
155155
TfwStrDefV("transfer-encoding:",TFW_HTTP_HDR_TRANSFER_ENCODING),
156156
TfwStrDefV("x-forwarded-for:", TFW_HTTP_HDR_X_FORWARDED_FOR),
157157
TfwStrDefV("x-tempesta-cache:", TFW_HTTP_HDR_X_TEMPESTA_CACHE),
158+
TfwStrDefV("upgrade:", TFW_HTTP_HDR_UPGRADE),
158159
};
159160

160161
BUILD_BUG_ON(ARRAY_SIZE(resp_hdrs) !=
@@ -182,6 +183,7 @@ tfw_http_msg_req_spec_hid(const TfwStr *hdr)
182183
TfwStrDefV("user-agent:", TFW_HTTP_HDR_USER_AGENT),
183184
TfwStrDefV("x-forwarded-for:", TFW_HTTP_HDR_X_FORWARDED_FOR),
184185
TfwStrDefV("x-tempesta-cache:", TFW_HTTP_HDR_X_TEMPESTA_CACHE),
186+
TfwStrDefV("upgrade:", TFW_HTTP_HDR_UPGRADE),
185187
};
186188

187189
BUILD_BUG_ON(ARRAY_SIZE(req_hdrs) !=
@@ -215,6 +217,7 @@ __http_msg_hdr_val(TfwStr *hdr, unsigned id, TfwStr *val, bool client)
215217
[TFW_HTTP_HDR_SET_COOKIE] = SLEN("Set-Cookie:"),
216218
[TFW_HTTP_HDR_ETAG] = SLEN("ETag:"),
217219
[TFW_HTTP_HDR_REFERER] = SLEN("Referer:"),
220+
[TFW_HTTP_HDR_UPGRADE] = SLEN("Upgrade:"),
218221
},
219222
(unsigned char []) {
220223
[TFW_HTTP_HDR_HOST] = SLEN("Host:"),
@@ -229,6 +232,7 @@ __http_msg_hdr_val(TfwStr *hdr, unsigned id, TfwStr *val, bool client)
229232
[TFW_HTTP_HDR_COOKIE] = SLEN("Cookie:"),
230233
[TFW_HTTP_HDR_IF_NONE_MATCH] = SLEN("If-None-Match:"),
231234
[TFW_HTTP_HDR_REFERER] = SLEN("Referer:"),
235+
[TFW_HTTP_HDR_UPGRADE] = SLEN("Upgrade:"),
232236
},
233237
};
234238
TfwStr *c, *end;

0 commit comments

Comments
 (0)