Skip to content

Commit a9d54be

Browse files
authored
Merge pull request #2320 from tempesta-tech/vk-2052-ja5http-filter
Add http ja5 filter and configuration
2 parents d620aa8 + e8100b3 commit a9d54be

14 files changed

+697
-433
lines changed

fw/access_log.c

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Tempesta FW
33
*
4-
* Copyright (C) 2022-2024 Tempesta Technologies, Inc.
4+
* Copyright (C) 2022-2025 Tempesta Technologies, Inc.
55
*
66
* This program is free software; you can redistribute it and/or modify it
77
* under the terms of the GNU General Public License as published by
@@ -39,27 +39,32 @@
3939
! code that fills its value !
4040
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
4141
*/
42-
#define ACCESS_LOG_LINE(FIXED, UNTRUNCATABLE, TRUNCATABLE) \
43-
FIXED(__BNR) \
44-
UNTRUNCATABLE(client_ip) \
45-
FIXED(" \"") \
46-
UNTRUNCATABLE(vhost) \
47-
FIXED("\" \"") \
48-
UNTRUNCATABLE(method) \
49-
FIXED(" ") \
50-
TRUNCATABLE(uri) \
51-
FIXED(" ") \
52-
UNTRUNCATABLE(version) \
53-
FIXED("\" ") \
54-
UNTRUNCATABLE(status) \
55-
FIXED(" ") \
56-
UNTRUNCATABLE(content_length) \
57-
FIXED(" \"") \
58-
TRUNCATABLE(referer) \
59-
FIXED("\" \"") \
60-
TRUNCATABLE(user_agent) \
42+
#define ACCESS_LOG_LINE(FIXED, UNTRUNCATABLE, TRUNCATABLE) \
43+
FIXED(__BNR) \
44+
UNTRUNCATABLE(client_ip) \
45+
FIXED(" \"") \
46+
UNTRUNCATABLE(vhost) \
47+
FIXED("\" \"") \
48+
UNTRUNCATABLE(method) \
49+
FIXED(" ") \
50+
TRUNCATABLE(uri) \
51+
FIXED(" ") \
52+
UNTRUNCATABLE(version) \
53+
FIXED("\" ") \
54+
UNTRUNCATABLE(status) \
55+
FIXED(" ") \
56+
UNTRUNCATABLE(content_length) \
57+
FIXED(" \"") \
58+
TRUNCATABLE(referer) \
59+
FIXED("\" \"") \
60+
TRUNCATABLE(user_agent) \
61+
FIXED("\" \"") \
62+
UNTRUNCATABLE(ja5_tls) \
63+
FIXED("\" \"") \
64+
UNTRUNCATABLE(ja5_http) \
6165
FIXED("\"")
6266

67+
6368
#define ACCESS_LOG_OFF 0
6469
#define ACCESS_LOG_DMESG 1
6570
#define ACCESS_LOG_MMAP 2
@@ -289,6 +294,9 @@ do_access_log_req_mmap(TfwHttpReq *req, u16 resp_status,
289294
char *data, *p;
290295
struct timespec64 ts;
291296
u16 len;
297+
TlsJa5t *tls_ja5t = TFW_CONN_TLS(req->conn) ?
298+
&tfw_tls_context(req->conn)->sess.ja5t : NULL;
299+
292300

293301
room_size = tfw_mmap_buffer_get_room(mmap_buffer, &data);
294302
if (room_size < sizeof(TfwBinLogEvent))
@@ -363,6 +371,12 @@ do_access_log_req_mmap(TfwHttpReq *req, u16 resp_status,
363371
req->h_tbl->tbl + TFW_HTTP_HDR_USER_AGENT);
364372
WRITE_STR_FIELD(ua);
365373

374+
if (tls_ja5t)
375+
WRITE_FIELD(*tls_ja5t);
376+
else
377+
TFW_MMAP_LOG_FIELD_RESET(event, TFW_MMAP_LOG_JA5T);
378+
WRITE_FIELD(req->ja5h);
379+
366380
if (*dropped) {
367381
WRITE_FIELD(*dropped);
368382
*dropped = 0;
@@ -394,10 +408,12 @@ do_access_log_req_dmesg(TfwHttpReq *req, int resp_status, unsigned long resp_con
394408
BasicStr client_ip, vhost, method, version;
395409
/* These fields are only here to hold estimation of appropriate fields
396410
* length in characters */
397-
BasicStr status, content_length;
411+
BasicStr status, content_length, ja5_tls, ja5_http;
398412
BasicStr missing = { "-", 1 };
399413
TfwStr truncated_in[TRUNCATABLE_FIELDS_COUNT];
400414
BasicStr truncated_out[TRUNCATABLE_FIELDS_COUNT];
415+
TlsJa5t *tls_ja5t = TFW_CONN_TLS(req->conn) ?
416+
&tfw_tls_context(req->conn)->sess.ja5t : NULL;
401417

402418
/* client_ip
403419
*
@@ -466,6 +482,15 @@ do_access_log_req_dmesg(TfwHttpReq *req, int resp_status, unsigned long resp_con
466482
ADD_HDR(idx_referer, TFW_HTTP_HDR_REFERER);
467483
ADD_HDR(idx_user_agent, TFW_HTTP_HDR_USER_AGENT);
468484

485+
#define FMT_ja5_tls "ja5t=%llx"
486+
#define ARG_ja5_tls , (tls_ja5t ? *(u64 *)tls_ja5t : 0)
487+
ja5_tls.data = "";
488+
ja5_tls.len = 16;
489+
#define FMT_ja5_http "ja5h=%llx"
490+
#define ARG_ja5_http , (*(u64 *)&req->ja5h)
491+
ja5_http.data = "";
492+
ja5_http.len = 16;
493+
469494
/* Now we calculate first estimation of
470495
* "maximum allowed truncated string length" */
471496
#define ESTIMATE_FIXED(str) + (sizeof(str) - 1)
@@ -519,6 +544,10 @@ do_access_log_req_dmesg(TfwHttpReq *req, int resp_status, unsigned long resp_con
519544
#undef FMT_vhost
520545
#undef ARG_client_ip
521546
#undef FMT_client_ip
547+
#undef FMT_ja5_tls
548+
#undef ARG_ja5_tls
549+
#undef FMT_ja5_http
550+
#undef ARG_ja5_http
522551
}
523552

524553
void

fw/access_log.h

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* Tempesta FW
33
*
4-
* Copyright (C) 2022-2024 Tempesta Technologies, Inc.
4+
* Copyright (C) 2022-2025 Tempesta Technologies, Inc.
55
*
66
* This program is free software; you can redistribute it and/or modify it
77
* under the terms of the GNU General Public License as published by
@@ -65,6 +65,8 @@ typedef enum {
6565
TFW_MMAP_LOG_URI,
6666
TFW_MMAP_LOG_REFERER,
6767
TFW_MMAP_LOG_USER_AGENT,
68+
TFW_MMAP_LOG_JA5T,
69+
TFW_MMAP_LOG_JA5H,
6870
TFW_MMAP_LOG_DROPPED,
6971
TFW_MMAP_LOG_MAX
7072
} TfwBinLogFields;
@@ -90,7 +92,9 @@ static inline int tfw_mmap_log_field_len(TfwBinLogFields field)
9092
[TFW_MMAP_LOG_URI] = 0,
9193
[TFW_MMAP_LOG_REFERER] = 0,
9294
[TFW_MMAP_LOG_USER_AGENT] = 0,
93-
[TFW_MMAP_LOG_DROPPED] = 8,
95+
[TFW_MMAP_LOG_JA5T] = 8,
96+
[TFW_MMAP_LOG_JA5H] = 8,
97+
[TFW_MMAP_LOG_DROPPED] = 8
9498
};
9599
return TfwBinLogFieldsLens[field];
96100
}

fw/http.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@
6666
* created HTTP/1.1-message.
6767
*
6868
* Copyright (C) 2014 NatSys Lab. (info@natsys-lab.com).
69-
* Copyright (C) 2015-2024 Tempesta Technologies, Inc.
69+
* Copyright (C) 2015-2025 Tempesta Technologies, Inc.
7070
*
7171
* This program is free software; you can redistribute it and/or modify it
7272
* under the terms of the GNU General Public License as published by
@@ -114,6 +114,8 @@
114114
#include "access_log.h"
115115
#include "vhost.h"
116116
#include "websocket.h"
117+
#include "ja5_filter.h"
118+
#include "ja5_conf.h"
117119

118120
#include "sync_socket.h"
119121
#include "lib/common.h"
@@ -5997,6 +5999,15 @@ __check_authority_correctness(TfwHttpReq *req)
59975999
return true;
59986000
}
59996001

6002+
static bool
6003+
tfw_http_check_ja5h_req_limit(TfwHttpReq *req)
6004+
{
6005+
u64 limit = http_get_ja5_recs_limit(req->ja5h);
6006+
u64 rate = ja5h_get_records_rate(req->ja5h);
6007+
6008+
return rate > limit;
6009+
}
6010+
60006011
/**
60016012
* @return zero on success and negative value otherwise.
60026013
* TODO enter the function depending on current GFSM state.
@@ -6158,6 +6169,14 @@ tfw_http_req_process(TfwConn *conn, TfwStream *stream, struct sk_buff *skb,
61586169

61596170
req->ja5h.method = req->method;
61606171

6172+
if (tfw_http_check_ja5h_req_limit(req)) {
6173+
TFW_INC_STAT_BH(clnt.msgs_filtout);
6174+
return tfw_http_req_parse_block(req, 403,
6175+
"parsed request exceeded ja5h limit",
6176+
HTTP2_ECODE_PROTO);
6177+
}
6178+
6179+
61616180
/*
61626181
* The message is fully parsed, the rest of the data in the
61636182
* stream may represent another request or its part.
@@ -7303,6 +7322,7 @@ tfw_http_start(void)
73037322
{
73047323
TfwVhost *dflt_vh = tfw_vhost_lookup_default();
73057324
bool misconfiguration;
7325+
u64 storage_size = http_get_ja5_storage_size();
73067326

73077327
if (WARN_ON_ONCE(!dflt_vh))
73087328
return -1;
@@ -7319,9 +7339,18 @@ tfw_http_start(void)
73197339
return -1;
73207340
}
73217341

7342+
if (storage_size && !ja5h_init_filter(storage_size))
7343+
return -ENOMEM;
7344+
73227345
return 0;
73237346
}
73247347

7348+
static void
7349+
tfw_http_stop(void)
7350+
{
7351+
ja5h_close_filter();
7352+
}
7353+
73257354
/*
73267355
* ------------------------------------------------------------------------
73277356
* configuration handling
@@ -7957,12 +7986,27 @@ static TfwCfgSpec tfw_http_specs[] = {
79577986
.allow_none = true,
79587987
.cleanup = tfw_cfgop_cleanup_max_header_list_size,
79597988
},
7989+
{
7990+
.name = "ja5h",
7991+
.deflt = NULL,
7992+
.handler = tfw_cfg_handle_children,
7993+
.cleanup = http_ja5_cfgop_cleanup,
7994+
.dest = ja5_hash_specs,
7995+
.spec_ext = &(TfwCfgSpecChild) {
7996+
.begin_hook = ja5_cfgop_begin,
7997+
.finish_hook = http_ja5_cfgop_finish
7998+
},
7999+
.allow_none = true,
8000+
.allow_repeat = false,
8001+
.allow_reconfig = true,
8002+
},
79608003
{ 0 }
79618004
};
79628005

79638006
TfwMod tfw_http_mod = {
79648007
.name = "http",
79658008
.start = tfw_http_start,
8009+
.stop = tfw_http_stop,
79668010
.specs = tfw_http_specs,
79678011
};
79688012

0 commit comments

Comments
 (0)