Skip to content

Commit ad2940c

Browse files
authored
Refactor jax_fingerprint plugin for better modularity and fewer allocations (#13072)
Each subdirectory (ja3/, ja4/, ja4h/) now follows a consistent structure: method.cc/.h for the fingerprint method, test.cc for tests, plus algorithm-specific files. Redundant prefixes removed since subdirectories provide context. Tests updated to match. No functional changes.
1 parent ebb5e34 commit ad2940c

25 files changed

Lines changed: 1252 additions & 950 deletions

plugins/experimental/jax_fingerprint/CMakeLists.txt

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -22,30 +22,34 @@ add_atsplugin(
2222
userarg.cc
2323
header.cc
2424
log.cc
25-
ja3/ja3_method.cc
26-
ja3/ja3_utils.cc
27-
ja4/ja4_method.cc
25+
ja3/method.cc
26+
ja3/utils.cc
27+
ja4/method.cc
2828
ja4/ja4.cc
29+
ja4/datasource.cc
2930
ja4/tls_client_hello_summary.cc
30-
ja4h/ja4h_method.cc
31+
ja4h/method.cc
3132
ja4h/ja4h.cc
3233
ja4h/datasource.cc
34+
ja4_common/utils.cc
3335
)
3436
target_link_libraries(jax_fingerprint PRIVATE OpenSSL::Crypto OpenSSL::SSL)
35-
verify_global_plugin(jax_fingerprint)
3637
target_include_directories(jax_fingerprint BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
38+
verify_global_plugin(jax_fingerprint)
39+
verify_remap_plugin(jax_fingerprint)
3740

3841
if(BUILD_TESTING)
3942
add_executable(
4043
test_jax
41-
ja3/test_ja3.cc
42-
ja3/ja3_utils.cc
43-
ja4/test_ja4.cc
44+
ja3/test.cc
45+
ja3/utils.cc
46+
ja4/test.cc
4447
ja4/ja4.cc
45-
ja4/tls_client_hello_summary.cc
46-
ja4h/test_ja4h.cc
48+
ja4/datasource.cc
49+
ja4h/test.cc
4750
ja4h/ja4h.cc
4851
ja4h/datasource.cc
52+
ja4_common/utils.cc
4953
)
5054
target_link_libraries(test_jax PRIVATE Catch2::Catch2WithMain OpenSSL::Crypto OpenSSL::SSL)
5155
target_include_directories(test_jax BEFORE PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})

plugins/experimental/jax_fingerprint/ja3/ja3_method.cc renamed to plugins/experimental/jax_fingerprint/ja3/method.cc

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,38 +24,22 @@
2424

2525
#include <plugin.h>
2626
#include <context.h>
27-
#include "ja3_method.h"
28-
#include "ja3_utils.h"
27+
#include "method.h"
28+
#include "utils.h"
2929

3030
#include <openssl/ssl.h>
3131
#include <openssl/md5.h>
3232
#include <openssl/opensslv.h>
3333

3434
#include <algorithm>
3535

36-
namespace ja3_method
37-
{
38-
39-
void on_client_hello(JAxContext *, TSVConn);
40-
41-
struct Method method = {
42-
"JA3",
43-
Method::Type::CONNECTION_BASED,
44-
on_client_hello,
45-
nullptr,
46-
};
47-
48-
} // namespace ja3_method
49-
5036
namespace
5137
{
5238
constexpr int ja3_hash_included_byte_count{16};
5339
static_assert(ja3_hash_included_byte_count <= MD5_DIGEST_LENGTH);
5440

5541
constexpr int ja3_hash_hex_string_with_null_terminator_length{2 * ja3_hash_included_byte_count + 1};
5642

57-
} // end anonymous namespace
58-
5943
static std::string
6044
get_fingerprint(TSClientHello ch)
6145
{
@@ -115,8 +99,13 @@ get_fingerprint(TSClientHello ch)
11599
return {fingerprint};
116100
}
117101

102+
} // end anonymous namespace
103+
104+
namespace ja3
105+
{
106+
118107
void
119-
ja3_method::on_client_hello(JAxContext *ctx, TSVConn vconn)
108+
on_client_hello(JAxContext *ctx, TSVConn vconn)
120109
{
121110
TSClientHello ch = TSVConnClientHelloGet(vconn);
122111

@@ -126,3 +115,12 @@ ja3_method::on_client_hello(JAxContext *ctx, TSVConn vconn)
126115
ctx->set_fingerprint(get_fingerprint(ch));
127116
}
128117
}
118+
119+
struct Method method = {
120+
"JA3",
121+
Method::Type::CONNECTION_BASED,
122+
on_client_hello,
123+
nullptr,
124+
};
125+
126+
} // namespace ja3

plugins/experimental/jax_fingerprint/ja4/ja4_method.h renamed to plugins/experimental/jax_fingerprint/ja3/method.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424

2525
#include <method.h>
2626

27-
namespace ja4_method
27+
namespace ja3
2828
{
2929

3030
extern struct Method method;

plugins/experimental/jax_fingerprint/ja3/test_ja3.cc renamed to plugins/experimental/jax_fingerprint/ja3/test.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
2323
*/
2424

25-
#include "ja3_utils.h"
25+
#include "utils.h"
2626

2727
#include <catch2/catch_test_macros.hpp>
2828

File renamed without changes.
File renamed without changes.
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
/** @file
2+
3+
@section license License
4+
5+
Licensed to the Apache Software Foundation (ASF) under one
6+
or more contributor license agreements. See the NOTICE file
7+
distributed with this work for additional information
8+
regarding copyright ownership. The ASF licenses this file
9+
to you under the Apache License, Version 2.0 (the
10+
"License"); you may not use this file except in compliance
11+
with the License. You may obtain a copy of the License at
12+
13+
http://www.apache.org/licenses/LICENSE-2.0
14+
15+
Unless required by applicable law or agreed to in writing, software
16+
distributed under the License is distributed on an "AS IS" BASIS,
17+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
See the License for the specific language governing permissions and
19+
limitations under the License.
20+
*/
21+
22+
#include "datasource.h"
23+
24+
#include <array>
25+
#include <algorithm>
26+
27+
constexpr std::array<std::uint16_t, 16> GREASE_values{0x0a0a, 0x1a1a, 0x2a2a, 0x3a3a, 0x4a4a, 0x5a5a, 0x6a6a, 0x7a7a,
28+
0x8a8a, 0x9a9a, 0xaaaa, 0xbaba, 0xcaca, 0xdada, 0xeaea, 0xfafa};
29+
30+
ja4::Datasource::Protocol
31+
ja4::Datasource::get_protocol()
32+
{
33+
return this->_protocol;
34+
}
35+
36+
int
37+
ja4::Datasource::get_version()
38+
{
39+
return this->_version;
40+
}
41+
42+
ja4::Datasource::SNI
43+
ja4::Datasource::get_sni_type()
44+
{
45+
return this->_has_SNI ? ja4::Datasource::SNI::to_domain : ja4::Datasource::SNI::to_IP;
46+
}
47+
48+
int
49+
ja4::Datasource::get_cipher_count()
50+
{
51+
return this->_n_ciphers;
52+
}
53+
54+
int
55+
ja4::Datasource::get_extension_count()
56+
{
57+
return this->_n_extensions + (this->_has_ALPN ? 1 : 0) + (this->_has_SNI ? 1 : 0);
58+
}
59+
60+
/**
61+
* Check whether @a value is a GREASE value.
62+
*
63+
* These are reserved extensions randomly advertised to keep implementations
64+
* well lubricated. They are ignored in all parts of JA4 because of their
65+
* random nature.
66+
*
67+
* @return Returns true if the value is a GREASE value, false otherwise.
68+
*/
69+
bool
70+
ja4::Datasource::_is_GREASE(uint16_t value)
71+
{
72+
return std::binary_search(GREASE_values.begin(), GREASE_values.end(), value);
73+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/** @file
2+
3+
@section license License
4+
5+
Licensed to the Apache Software Foundation (ASF) under one
6+
or more contributor license agreements. See the NOTICE file
7+
distributed with this work for additional information
8+
regarding copyright ownership. The ASF licenses this file
9+
to you under the Apache License, Version 2.0 (the
10+
"License"); you may not use this file except in compliance
11+
with the License. You may obtain a copy of the License at
12+
13+
http://www.apache.org/licenses/LICENSE-2.0
14+
15+
Unless required by applicable law or agreed to in writing, software
16+
distributed under the License is distributed on an "AS IS" BASIS,
17+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18+
See the License for the specific language governing permissions and
19+
limitations under the License.
20+
21+
*/
22+
23+
#pragma once
24+
25+
#include <string_view>
26+
#include <cstdint>
27+
28+
constexpr uint16_t EXT_SNI{0x0};
29+
constexpr uint16_t EXT_ALPN{0x10};
30+
constexpr uint16_t EXT_SUPPORTED_VERSIONS{0x2b};
31+
32+
namespace ja4
33+
{
34+
35+
class Datasource
36+
{
37+
public:
38+
Datasource() = default;
39+
virtual ~Datasource() = default;
40+
41+
enum class Protocol {
42+
DTLS = 'd',
43+
QUIC = 'q',
44+
TLS = 't',
45+
};
46+
47+
enum class SNI {
48+
to_domain = 'd',
49+
to_IP = 'i',
50+
};
51+
52+
Protocol get_protocol();
53+
int get_version();
54+
SNI get_sni_type();
55+
int get_cipher_count();
56+
int get_extension_count();
57+
virtual std::string_view get_first_alpn() = 0;
58+
virtual void get_cipher_suites_hash(unsigned char out[32]) = 0;
59+
virtual void get_extension_hash(unsigned char out[32]) = 0;
60+
61+
protected:
62+
bool _is_GREASE(uint16_t value);
63+
64+
Protocol _protocol;
65+
int _version = 0;
66+
bool _has_ALPN = false;
67+
bool _has_SNI = false;
68+
int _n_ciphers = 0;
69+
int _n_extensions = 0;
70+
};
71+
72+
} // namespace ja4

0 commit comments

Comments
 (0)