diff --git a/.github/workflows/nginx.yml b/.github/workflows/nginx.yml index a3b38d4..6c60805 100644 --- a/.github/workflows/nginx.yml +++ b/.github/workflows/nginx.yml @@ -16,6 +16,9 @@ jobs: openssl: [openssl-3.2, openssl-3.1, openssl-3.0, OpenSSL_1_1_1-stable] nginx: [release-1.25.3, release-1.24.0, release-1.23.4, release-1.22.1, release-1.21.6, release-1.20.2] steps: + - name: Dependency + run: | + sudo apt update -y && sudo apt-get install -y libpcre3 libpcre3-dev - name: Clone run: | git clone -b ${{ matrix.openssl }} --depth=1 https://github.com/openssl/openssl diff --git a/.github/workflows/performance.yml b/.github/workflows/performance.yml index 14d8a5b..9fb0d36 100644 --- a/.github/workflows/performance.yml +++ b/.github/workflows/performance.yml @@ -16,7 +16,7 @@ jobs: nginx: [release-1.25.3] steps: - name: Install packages - run: sudo apt update -y && sudo apt-get install -y wrk + run: sudo apt update -y && sudo apt-get install -y wrk libpcre3 libpcre3-dev - name: Config run: | cat < nginx.conf diff --git a/README.md b/README.md index 8b8e1a5..15923bf 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,15 @@ A high performance nginx module for ja3 and http2 fingerprint. ### Support Matrix -| | OpenSSL_1_1_1 | openssl-3.0 | openssl-3.1 | openssl-3.2 | -| -----------| -------------------- | ----------- | ----------- | ----------- | -| nginx-1.20 | ✅ | ✅ | ✅ | ✅ | -| nginx-1.21 | ✅ | ✅ | ✅ | ✅ | -| nginx-1.22 | ✅ | ✅ | ✅ | ✅ | -| nginx-1.23 | ✅ | ✅ | ✅ | ✅ | -| nginx-1.24 | ✅ | ✅ | ✅ | ✅ | -| nginx-1.25 | ✅ | ✅ | ✅ | ✅ | +| | OpenSSL_1_1_1 | openssl-3.0 | openssl-3.1 | openssl-3.2 | openssl-3.4 | +| -----------| -------------------- | ----------- | ----------- | ----------- | ----------- +| nginx-1.20 | ✅ | ✅ | ✅ | ✅ | | +| nginx-1.21 | ✅ | ✅ | ✅ | ✅ | | +| nginx-1.22 | ✅ | ✅ | ✅ | ✅ | | +| nginx-1.23 | ✅ | ✅ | ✅ | ✅ | | +| nginx-1.24 | ✅ | ✅ | ✅ | ✅ | | +| nginx-1.25 | ✅ | ✅ | ✅ | ✅ | | +| nginx-1.27 | | | | | ✅ | ## Configuration diff --git a/config b/config index 4e99c56..f5c142d 100644 --- a/config +++ b/config @@ -1,16 +1,29 @@ + +# +# JA3 module conf +# + ngx_addon_name=ngx_ssl_fingerprint_module CORE_LIBS="$CORE_LIBS" - CORE_INCS="$CORE_INCS $ngx_addon_dir/src" -STREAM_MODULES="ngx_stream_ssl_fingerprint_preread_module $STREAM_MODULES" - HTTP_MODULES="$HTTP_MODULES ngx_http_ssl_fingerprint_module" -NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ - $ngx_addon_dir/src/nginx_ssl_fingerprint.c \ - $ngx_addon_dir/src/ngx_stream_ssl_fingerprint_preread_module.c \ - $ngx_addon_dir/src/ngx_http_ssl_fingerprint_module.c - " +stream_module="" + +if [ $STREAM_SSL = YES ]; then + echo "[+] ngx_stream_ssl_fingerprint_preread_module included" + STREAM_MODULES="ngx_stream_ssl_fingerprint_preread_module $STREAM_MODULES" + stream_module="$ngx_addon_dir/src/ngx_stream_ssl_fingerprint_preread_module.c" +else + echo "[-] ngx_stream_ssl_fingerprint_preread_module will no be compiled" +fi + +NGX_ADDON_SRCS="$NGX_ADDON_SRCS \ + $ngx_addon_dir/src/nginx_ssl_fingerprint.c \ + $ngx_addon_dir/src/ngx_http_ssl_fingerprint_module.c \ + $stream_module" + +have=NGX_JA3_FINGERPRING_MODULE . auto/have diff --git a/patches/nginx-1.27.patch b/patches/nginx-1.27.patch new file mode 100644 index 0000000..0cc2aae --- /dev/null +++ b/patches/nginx-1.27.patch @@ -0,0 +1,180 @@ +diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c +index 2f68a55de..d069b72ea 100644 +--- a/src/event/ngx_event_openssl.c ++++ b/src/event/ngx_event_openssl.c +@@ -11,6 +11,7 @@ + #include + + ++#define NGX_SSL_JA3_BUFFER_SIZE 256 /* = (sizeof(uint16_t) * 128) */ + #define NGX_SSL_PASSWORD_BUFFER_SIZE 4096 + + #if (NGX_HAVE_NTLS) +@@ -1971,6 +1972,40 @@ ngx_ssl_set_session(ngx_connection_t *c, ngx_ssl_session_t *session) + return NGX_OK; + } + ++int ++ngx_ssl_client_hello_ja3_cb(SSL *s, int *al, void *arg) ++{ ++ ngx_connection_t *c = arg; ++ ngx_str_t *ja; ++ ++ if (c == NULL) { ++ return SSL_CLIENT_HELLO_SUCCESS; ++ } ++ ++ if (c->ssl == NULL) { ++ return SSL_CLIENT_HELLO_SUCCESS; ++ } ++ ++ ja = &c->ssl->fp_ja3_data; ++ ja->len = NGX_SSL_JA3_BUFFER_SIZE; ++ ++ ja->data = ngx_pnalloc(c->pool, c->ssl->fp_ja3_data.len); ++ if (ja->data == NULL) { ++ ja->len = 0; ++ return SSL_CLIENT_HELLO_SUCCESS; ++ } ++ ++ ja->len = SSL_client_hello_get_ja3_data(c->ssl->connection, ja->data, ++ NGX_SSL_JA3_BUFFER_SIZE); ++ if (ja->len == 0) { ++ ngx_log_error(NGX_LOG_WARN, c->log, 0, "SSL_client_hello_get_ja3_data " ++ "seems the buffer size is less that number of fileds; " ++ "for this SSL connection can't get a ja3 hash string"); ++ ja->data = NULL; ++ } ++ ++ return SSL_CLIENT_HELLO_SUCCESS; ++} + + ngx_int_t + ngx_ssl_handshake(ngx_connection_t *c) +@@ -1991,6 +2026,9 @@ ngx_ssl_handshake(ngx_connection_t *c) + + ngx_ssl_clear_error(c->log); + ++ (void) SSL_CTX_set_client_hello_cb(c->ssl->session_ctx, ++ ngx_ssl_client_hello_ja3_cb, c); ++ + n = SSL_do_handshake(c->ssl->connection); + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n); +diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h +index 42a01ce62..c4adc270d 100644 +--- a/src/event/ngx_event_openssl.h ++++ b/src/event/ngx_event_openssl.h +@@ -129,6 +129,11 @@ struct ngx_ssl_connection_s { + unsigned in_ocsp:1; + unsigned early_preread:1; + unsigned write_blocked:1; ++ ++ ngx_str_t fp_ja3_data; ++ ngx_str_t fp_ja3_str; ++ ngx_str_t fp_ja3_hash; ++ uint16_t fp_tls_greased; + }; + + +diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c +index 0f5bd3de8..1b85e378d 100644 +--- a/src/http/v2/ngx_http_v2.c ++++ b/src/http/v2/ngx_http_v2.c +@@ -301,6 +301,8 @@ ngx_http_v2_init(ngx_event_t *rev) + ngx_add_timer(rev, cscf->client_header_timeout); + } + ++ h2c->fp_fingerprinted = 0; ++ + c->idle = 1; + ngx_reusable_connection(c, 0); + +@@ -1352,6 +1354,14 @@ ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, + } + } + ++ if (!h2c->fp_fingerprinted && h2c->fp_priorities.len < 32) { ++ h2c->fp_priorities.data[h2c->fp_priorities.len] = (uint8_t)stream->node->id; ++ h2c->fp_priorities.data[h2c->fp_priorities.len+1] = (uint8_t)excl; ++ h2c->fp_priorities.data[h2c->fp_priorities.len+2] = (uint8_t)depend; ++ h2c->fp_priorities.data[h2c->fp_priorities.len+3] = (uint8_t)(weight-1); ++ h2c->fp_priorities.len += 4; ++ } ++ + return ngx_http_v2_state_header_block(h2c, pos, end); + + rst_stream: +@@ -1775,6 +1785,9 @@ ngx_http_v2_state_process_header(ngx_http_v2_connection_t *h2c, u_char *pos, + } + + if (header->name.data[0] == ':') { ++ if (!h2c->fp_fingerprinted && h2c->fp_pseudoheaders.len < 32 && header->name.len > 1) ++ h2c->fp_pseudoheaders.data[h2c->fp_pseudoheaders.len++] = header->name.data[1]; ++ + rc = ngx_http_v2_pseudo_header(r, header); + + if (rc == NGX_OK) { +@@ -2194,6 +2207,12 @@ ngx_http_v2_state_settings_params(ngx_http_v2_connection_t *h2c, u_char *pos, + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, + "http2 setting %ui:%ui", id, value); + ++ if (!h2c->fp_fingerprinted && h2c->fp_settings.len < 32) { ++ h2c->fp_settings.data[h2c->fp_settings.len] = (uint8_t)id; ++ *(uint32_t*)(h2c->fp_settings.data + h2c->fp_settings.len + 1) = (uint32_t)value; ++ h2c->fp_settings.len += 5; ++ } ++ + switch (id) { + + case NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING: +@@ -2478,6 +2497,9 @@ ngx_http_v2_state_window_update(ngx_http_v2_connection_t *h2c, u_char *pos, + } + + h2c->send_window += window; ++ if (!h2c->fp_fingerprinted) { ++ h2c->fp_windowupdate = window; ++ } + + while (!ngx_queue_empty(&h2c->waiting)) { + q = ngx_queue_head(&h2c->waiting); +diff --git a/src/http/v2/ngx_http_v2.h b/src/http/v2/ngx_http_v2.h +index 6751b3026..60a68a0fd 100644 +--- a/src/http/v2/ngx_http_v2.h ++++ b/src/http/v2/ngx_http_v2.h +@@ -17,6 +17,8 @@ + + #define NGX_HTTP_V2_STATE_BUFFER_SIZE 16 + ++#define NGX_FP_V2_BUFFER_SIZE 32 ++ + #define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14) + #define NGX_HTTP_V2_MAX_FRAME_SIZE ((1 << 24) - 1) + +@@ -121,6 +123,12 @@ typedef struct { + } ngx_http_v2_hpack_t; + + ++typedef struct { ++ u_char data[NGX_FP_V2_BUFFER_SIZE]; ++ size_t len; ++} ngx_http_v2_fp_fixed_str_t; ++ ++ + struct ngx_http_v2_connection_s { + ngx_connection_t *connection; + ngx_http_connection_t *http_connection; +@@ -168,6 +176,13 @@ struct ngx_http_v2_connection_s { + unsigned table_update:1; + unsigned blocked:1; + unsigned goaway:1; ++ ++ unsigned fp_fingerprinted:1; ++ ngx_http_v2_fp_fixed_str_t fp_settings, ++ fp_priorities, ++ fp_pseudoheaders; ++ ngx_uint_t fp_windowupdate; ++ ngx_str_t fp_str; + }; + + diff --git a/patches/openssl.OpenSSL_1_1_1-stable.patch b/patches/openssl.OpenSSL_1_1_1-stable.patch index a8f08c3..1b1bd60 100644 --- a/patches/openssl.OpenSSL_1_1_1-stable.patch +++ b/patches/openssl.OpenSSL_1_1_1-stable.patch @@ -1,5 +1,5 @@ diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h -index 9af0c899..c77a04cd 100644 +index 9af0c8995e..c77a04cd90 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -1818,6 +1818,7 @@ size_t SSL_client_hello_get0_ciphers(SSL *s, const unsigned char **out); @@ -11,7 +11,7 @@ index 9af0c899..c77a04cd 100644 const unsigned char **out, size_t *outlen); diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h -index 76d9fda4..a29114f2 100644 +index 76d9fda46e..a29114f215 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -131,6 +131,15 @@ extern "C" { @@ -31,10 +31,10 @@ index 76d9fda4..a29114f2 100644 # define TLSEXT_TYPE_session_ticket 35 diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c -index 47adc321..635b23b3 100644 +index 47adc3211c..be20746b98 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c -@@ -5219,6 +5219,95 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) +@@ -5219,6 +5219,94 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) return 0; } @@ -74,11 +74,12 @@ index 47adc321..635b23b3 100644 + ptr += 2; + + /* ciphers */ -+ num = PACKET_remaining(&s->clienthello->ciphersuites); -+ *(uint16_t*)ptr = (uint16_t)num; -+ ptr += 2; -+ memcpy(ptr, PACKET_data(&s->clienthello->ciphersuites), num); -+ ptr += num; ++ if (num = PACKET_remaining(&s->clienthello->ciphersuites)) { ++ *(uint16_t*)ptr = (uint16_t)num; ++ ptr += 2; ++ memcpy(ptr, PACKET_data(&s->clienthello->ciphersuites), num); ++ ptr += num; ++ } + + /* extensions */ + num = 0; @@ -104,19 +105,17 @@ index 47adc321..635b23b3 100644 + ptr += num*2; + + /* groups */ -+ if (groups) { -+ num = PACKET_remaining(groups); ++ if (groups && (num = PACKET_remaining(groups))) { + memcpy(ptr, PACKET_data(groups), num); + *(uint16_t*)ptr = (uint16_t)num; + ptr += num; + } else { -+ *(uint16_t*)ptr = 0; -+ ptr += 2; ++ *(uint16_t*)ptr = 0; ++ ptr += 2; + } + + /* formats */ -+ if (formats) { -+ num = PACKET_remaining(formats); ++ if (formats && (num = PACKET_remaining(formats))) { + memcpy(ptr, PACKET_data(formats), num); + *ptr = (uint8_t)num; + ptr += num; @@ -131,7 +130,7 @@ index 47adc321..635b23b3 100644 size_t *outlen) { diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h -index 5c792154..a3038c79 100644 +index 5c79215423..a3038c79ea 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h @@ -714,6 +714,10 @@ typedef enum tlsext_index_en { @@ -146,7 +145,7 @@ index 5c792154..a3038c79 100644 TLSEXT_IDX_psk, /* Dummy index - must always be the last entry */ diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c -index 0f39275b..7cb1e622 100644 +index 0f39275baa..7cb1e62287 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -377,6 +377,38 @@ static const EXTENSION_DEFINITION ext_defs[] = { diff --git a/patches/openssl.openssl-3.0.patch b/patches/openssl.openssl-3.0.patch index a961abc..46bc0e9 100644 --- a/patches/openssl.openssl-3.0.patch +++ b/patches/openssl.openssl-3.0.patch @@ -11,7 +11,7 @@ index 105b4a4a3c..6c7eb4643a 100644 const unsigned char **out, size_t *outlen); diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h -index d6e9331fa1..b62b4e380d 100644 +index 91558fa8d1..b04e6ec4fa 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -134,6 +134,15 @@ extern "C" { @@ -31,10 +31,10 @@ index d6e9331fa1..b62b4e380d 100644 # define TLSEXT_TYPE_session_ticket 35 diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c -index 2c8479eb5f..4c62687258 100644 +index e628140dfa..512e5a552c 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c -@@ -5463,6 +5463,95 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) +@@ -5481,6 +5481,94 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) return 0; } @@ -74,11 +74,12 @@ index 2c8479eb5f..4c62687258 100644 + ptr += 2; + + /* ciphers */ -+ num = PACKET_remaining(&s->clienthello->ciphersuites); -+ *(uint16_t*)ptr = (uint16_t)num; -+ ptr += 2; -+ memcpy(ptr, PACKET_data(&s->clienthello->ciphersuites), num); -+ ptr += num; ++ if (num = PACKET_remaining(&s->clienthello->ciphersuites)) { ++ *(uint16_t*)ptr = (uint16_t)num; ++ ptr += 2; ++ memcpy(ptr, PACKET_data(&s->clienthello->ciphersuites), num); ++ ptr += num; ++ } + + /* extensions */ + num = 0; @@ -104,19 +105,17 @@ index 2c8479eb5f..4c62687258 100644 + ptr += num*2; + + /* groups */ -+ if (groups) { -+ num = PACKET_remaining(groups); ++ if (groups && (num = PACKET_remaining(groups))) { + memcpy(ptr, PACKET_data(groups), num); + *(uint16_t*)ptr = (uint16_t)num; + ptr += num; + } else { -+ *(uint16_t*)ptr = 0; -+ ptr += 2; ++ *(uint16_t*)ptr = 0; ++ ptr += 2; + } + + /* formats */ -+ if (formats) { -+ num = PACKET_remaining(formats); ++ if (formats && (num = PACKET_remaining(formats))) { + memcpy(ptr, PACKET_data(formats), num); + *ptr = (uint8_t)num; + ptr += num; @@ -146,7 +145,7 @@ index 5fb1feb801..99f1370ea3 100644 TLSEXT_IDX_psk, /* Dummy index - must always be the last entry */ diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c -index 1518ca7f4e..66a83bcb16 100644 +index f8157389b7..fb5e1a8453 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -370,6 +370,38 @@ static const EXTENSION_DEFINITION ext_defs[] = { diff --git a/patches/openssl.openssl-3.1.patch b/patches/openssl.openssl-3.1.patch index 3c37f92..3621805 100644 --- a/patches/openssl.openssl-3.1.patch +++ b/patches/openssl.openssl-3.1.patch @@ -11,7 +11,7 @@ index f03f52fbd8..3140c3c5c5 100644 const unsigned char **out, size_t *outlen); diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h -index 793155e186..ef1f187b15 100644 +index 03f43744b1..a54c78e1fe 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -134,6 +134,15 @@ extern "C" { @@ -31,10 +31,10 @@ index 793155e186..ef1f187b15 100644 # define TLSEXT_TYPE_session_ticket 35 diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c -index b5cc4af2f0..578598e664 100644 +index f218dcf1db..8bf43c4c58 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c -@@ -5464,6 +5464,95 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) +@@ -5482,6 +5482,94 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) return 0; } @@ -74,11 +74,12 @@ index b5cc4af2f0..578598e664 100644 + ptr += 2; + + /* ciphers */ -+ num = PACKET_remaining(&s->clienthello->ciphersuites); -+ *(uint16_t*)ptr = (uint16_t)num; -+ ptr += 2; -+ memcpy(ptr, PACKET_data(&s->clienthello->ciphersuites), num); -+ ptr += num; ++ if (num = PACKET_remaining(&s->clienthello->ciphersuites)) { ++ *(uint16_t*)ptr = (uint16_t)num; ++ ptr += 2; ++ memcpy(ptr, PACKET_data(&s->clienthello->ciphersuites), num); ++ ptr += num; ++ } + + /* extensions */ + num = 0; @@ -104,19 +105,17 @@ index b5cc4af2f0..578598e664 100644 + ptr += num*2; + + /* groups */ -+ if (groups) { -+ num = PACKET_remaining(groups); ++ if (groups && (num = PACKET_remaining(groups))) { + memcpy(ptr, PACKET_data(groups), num); + *(uint16_t*)ptr = (uint16_t)num; + ptr += num; + } else { -+ *(uint16_t*)ptr = 0; -+ ptr += 2; ++ *(uint16_t*)ptr = 0; ++ ptr += 2; + } + + /* formats */ -+ if (formats) { -+ num = PACKET_remaining(formats); ++ if (formats && (num = PACKET_remaining(formats))) { + memcpy(ptr, PACKET_data(formats), num); + *ptr = (uint8_t)num; + ptr += num; @@ -146,7 +145,7 @@ index 845329a809..8fa0619feb 100644 TLSEXT_IDX_psk, /* Dummy index - must always be the last entry */ diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c -index e182b5abac..7d5adbf845 100644 +index 2ff809bc0f..fd730c09b8 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -369,6 +369,38 @@ static const EXTENSION_DEFINITION ext_defs[] = { diff --git a/patches/openssl.openssl-3.2.patch b/patches/openssl.openssl-3.2.patch index 54b905d..1b4fda5 100644 --- a/patches/openssl.openssl-3.2.patch +++ b/patches/openssl.openssl-3.2.patch @@ -11,7 +11,7 @@ index 9f91039f8a..81b9c51892 100644 size_t *num_exts); int SSL_client_hello_get0_ext(SSL *s, unsigned int type, diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h -index 7e3d1a725b..ecee15e29f 100644 +index 5329338efa..9755b5f44c 100644 --- a/include/openssl/tls1.h +++ b/include/openssl/tls1.h @@ -142,6 +142,13 @@ extern "C" { @@ -29,10 +29,10 @@ index 7e3d1a725b..ecee15e29f 100644 # define TLSEXT_TYPE_compress_certificate 27 diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c -index 26cae27dae..f5d1d8013a 100644 +index a6695ca4a0..4af995af35 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c -@@ -6572,6 +6572,99 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) +@@ -6595,6 +6595,98 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) return 0; } @@ -76,11 +76,12 @@ index 26cae27dae..f5d1d8013a 100644 + ptr += 2; + + /* ciphers */ -+ num = PACKET_remaining(&sc->clienthello->ciphersuites); -+ *(uint16_t*)ptr = (uint16_t)num; -+ ptr += 2; -+ memcpy(ptr, PACKET_data(&sc->clienthello->ciphersuites), num); -+ ptr += num; ++ if (num = PACKET_remaining(&sc->clienthello->ciphersuites)) { ++ *(uint16_t*)ptr = (uint16_t)num; ++ ptr += 2; ++ memcpy(ptr, PACKET_data(&sc->clienthello->ciphersuites), num); ++ ptr += num; ++ } + + /* extensions */ + num = 0; @@ -106,19 +107,17 @@ index 26cae27dae..f5d1d8013a 100644 + ptr += num*2; + + /* groups */ -+ if (groups) { -+ num = PACKET_remaining(groups); ++ if (groups && (num = PACKET_remaining(groups))) { + memcpy(ptr, PACKET_data(groups), num); + *(uint16_t*)ptr = (uint16_t)num; + ptr += num; + } else { -+ *(uint16_t*)ptr = 0; -+ ptr += 2; ++ *(uint16_t*)ptr = 0; ++ ptr += 2; + } + + /* formats */ -+ if (formats) { -+ num = PACKET_remaining(formats); ++ if (formats && (num = PACKET_remaining(formats))) { + memcpy(ptr, PACKET_data(formats), num); + *ptr = (uint8_t)num; + ptr += num; @@ -133,10 +132,10 @@ index 26cae27dae..f5d1d8013a 100644 { RAW_EXTENSION *ext; diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h -index 0d3acfbe66..01ceec6897 100644 +index 5f19e679fc..a5241e163d 100644 --- a/ssl/ssl_local.h +++ b/ssl/ssl_local.h -@@ -707,6 +707,9 @@ typedef enum tlsext_index_en { +@@ -708,6 +708,9 @@ typedef enum tlsext_index_en { TLSEXT_IDX_compress_certificate, TLSEXT_IDX_early_data, TLSEXT_IDX_certificate_authorities, @@ -147,7 +146,7 @@ index 0d3acfbe66..01ceec6897 100644 TLSEXT_IDX_psk, /* Dummy index - must always be the last entry */ diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c -index 0a64ca2246..9460207d1f 100644 +index c35c2ccd33..55c04a9937 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -411,6 +411,30 @@ static const EXTENSION_DEFINITION ext_defs[] = { diff --git a/patches/openssl.openssl-3.4.patch b/patches/openssl.openssl-3.4.patch new file mode 100644 index 0000000..45d4ac8 --- /dev/null +++ b/patches/openssl.openssl-3.4.patch @@ -0,0 +1,193 @@ +diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in +index 4bab2ac767..9732ece423 100644 +--- a/include/openssl/ssl.h.in ++++ b/include/openssl/ssl.h.in +@@ -1905,6 +1905,8 @@ size_t SSL_client_hello_get0_ciphers(SSL *s, const unsigned char **out); + size_t SSL_client_hello_get0_compression_methods(SSL *s, + const unsigned char **out); + int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen); ++size_t SSL_client_hello_get_ja3_data(SSL *s, unsigned char *data, ++ size_t data_size); + int SSL_client_hello_get_extension_order(SSL *s, uint16_t *exts, + size_t *num_exts); + int SSL_client_hello_get0_ext(SSL *s, unsigned int type, +diff --git a/include/openssl/tls1.h b/include/openssl/tls1.h +index 8e9b110bb3..3a2407b0e4 100644 +--- a/include/openssl/tls1.h ++++ b/include/openssl/tls1.h +@@ -142,6 +142,13 @@ extern "C" { + /* ExtensionType value from RFC7627 */ + # define TLSEXT_TYPE_extended_master_secret 23 + ++/* ExtensionType value from RFC6961 */ ++# define TLSEXT_TYPE_status_request_v2 17 ++/* ExtensionType value from RFC8449 */ ++# define TLSEXT_TYPE_record_size_limit 28 ++/* ExtensionType value from RFC7639 */ ++# define TLSEXT_TYPE_application_settings 17513 ++ + /* ExtensionType value from RFC8879 */ + # define TLSEXT_TYPE_compress_certificate 27 + +diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c +index 295b719ff2..c3df123253 100644 +--- a/ssl/ssl_lib.c ++++ b/ssl/ssl_lib.c +@@ -6641,6 +6641,108 @@ int SSL_client_hello_get1_extensions_present(SSL *s, int **out, size_t *outlen) + return 0; + } + ++size_t SSL_client_hello_get_ja3_data(SSL *s, unsigned char *data, ++ size_t data_size) ++{ ++ RAW_EXTENSION *ext; ++ PACKET *groups = NULL, *formats = NULL; ++ size_t num = 0, i; ++ unsigned char *ptr = data, ++ *end = data + data_size; ++ const SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s); ++ ++ if (sc == NULL) ++ return 0; ++ ++ if (ossl_unlikely(sc->clienthello == NULL || data == NULL ++ /** just checking that we have at least this */ ++ || data_size < 128)) ++ return 0; ++ ++ /* version */ ++ *(uint16_t *) ptr = (uint16_t) sc->clienthello->legacy_version; ++ ptr += sizeof(uint16_t); ++ ++ /* ciphers */ ++ num = PACKET_remaining(&sc->clienthello->ciphersuites); ++ if (ossl_likely(num > 0)) { ++ *(uint16_t *) ptr = (uint16_t) num; ++ ptr += sizeof(uint16_t); ++ ++ if (ossl_unlikely(ptr + num > end)) ++ return 0; ++ ++ memcpy(ptr, PACKET_data(&sc->clienthello->ciphersuites), num); ++ ptr += num; ++ } ++ ++ /* extensions */ ++ num = 0; ++ for (i = 0; i < sc->clienthello->pre_proc_exts_len; i++) { ++ ext = sc->clienthello->pre_proc_exts + i; ++ if (ext->present) ++ num++; ++ } ++ ++ num = num * 2; ++ if (ossl_unlikely((ptr + num + sizeof(uint16_t)) > end)) ++ return 0; ++ ++ *(uint16_t*) ptr = (uint16_t) num; ++ ptr += sizeof(uint16_t); ++ ++ for (i = 0; i < sc->clienthello->pre_proc_exts_len; i++) { ++ ext = sc->clienthello->pre_proc_exts + i; ++ if (ext->present) { ++ if (ext->received_order >= num) ++ break; ++ if (ext->type == TLSEXT_TYPE_supported_groups) ++ groups = &ext->data; ++ if (ext->type == TLSEXT_TYPE_ec_point_formats) ++ formats = &ext->data; ++ if (ossl_likely(ext->received_order < data_size)) { ++ ((uint16_t*)(ptr))[ext->received_order] = (uint16_t) ext->type; ++ } ++ } ++ } ++ ++ ptr += num; ++ ++ /* groups */ ++ if (groups ++ && (num = PACKET_remaining(groups)) > 0) ++ { ++ if (ossl_unlikely((ptr + num + sizeof(uint16_t)) > end)) ++ return 0; ++ memcpy(ptr, PACKET_data(groups), num); ++ *(uint16_t*) ptr = (uint16_t) num; ++ ptr += num; ++ } else { ++ if (ossl_unlikely(ptr + sizeof(uint16_t) > end)) ++ return 0; ++ *(uint16_t *) ptr = (uint16_t) 0; ++ ptr += sizeof(uint16_t); ++ } ++ ++ /* formats */ ++ if (formats ++ && (num = PACKET_remaining(formats)) > 0) ++ { ++ if (ossl_unlikely((ptr + num + sizeof(uint8_t)) > end)) ++ return 0; ++ memcpy(ptr, PACKET_data(formats), num); ++ *(uint8_t *) ptr = (uint8_t) num; ++ ptr += num; ++ } else { ++ if (ossl_unlikely(ptr + sizeof(uint8_t) > end)) ++ return 0; ++ *(uint8_t *) ptr = (uint8_t) 0; ++ ptr += sizeof(uint8_t); ++ } ++ ++ return ptr - data; ++} ++ + int SSL_client_hello_get_extension_order(SSL *s, uint16_t *exts, size_t *num_exts) + { + RAW_EXTENSION *ext; +diff --git a/ssl/ssl_local.h b/ssl/ssl_local.h +index 277be3084d..6b3821737f 100644 +--- a/ssl/ssl_local.h ++++ b/ssl/ssl_local.h +@@ -701,6 +701,9 @@ typedef enum tlsext_index_en { + TLSEXT_IDX_compress_certificate, + TLSEXT_IDX_early_data, + TLSEXT_IDX_certificate_authorities, ++ TLSEXT_IDX_status_request_v2, ++ TLSEXT_IDX_record_size_limit, ++ TLSEXT_IDX_application_settings, + TLSEXT_IDX_padding, + TLSEXT_IDX_psk, + /* Dummy index - must always be the last entry */ +diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c +index 762c7ac0d4..56d2f5ba60 100644 +--- a/ssl/statem/extensions.c ++++ b/ssl/statem/extensions.c +@@ -413,6 +413,30 @@ static const EXTENSION_DEFINITION ext_defs[] = { + tls_construct_certificate_authorities, + tls_construct_certificate_authorities, NULL, + }, ++ { ++ TLSEXT_TYPE_status_request_v2, ++ SSL_EXT_CLIENT_HELLO, ++ NULL, ++ NULL, NULL, ++ NULL, ++ NULL, NULL, ++ }, ++ { ++ TLSEXT_TYPE_record_size_limit, ++ SSL_EXT_CLIENT_HELLO, ++ NULL, ++ NULL, NULL, ++ NULL, ++ NULL, NULL, ++ }, ++ { ++ TLSEXT_TYPE_application_settings, ++ SSL_EXT_CLIENT_HELLO, ++ NULL, ++ NULL, NULL, ++ NULL, ++ NULL, NULL, ++ }, + { + /* Must be immediately before pre_shared_key */ + TLSEXT_TYPE_padding, diff --git a/src/nginx_ssl_fingerprint.c b/src/nginx_ssl_fingerprint.c index 950c670..c73a8c1 100755 --- a/src/nginx_ssl_fingerprint.c +++ b/src/nginx_ssl_fingerprint.c @@ -5,6 +5,8 @@ #include #include +#include + #define IS_GREASE_CODE(code) (((code)&0x0f0f) == 0x0a0a && ((code)&0xff) == ((code)>>8)) static inline @@ -186,31 +188,46 @@ unsigned char *append_uint32(unsigned char* dst, uint32_t n) return dst; } + +/** + * Params: + * c and c->ssl should be valid pointers + * + * Returns: + * NGX_OK - c->ssl->fp_ja3_str is already set + * NGX_ERROR - something went wrong + */ int ngx_ssl_ja3(ngx_connection_t *c) { u_char *ptr = NULL, *data = NULL; size_t num = 0, i; uint16_t n, greased = 0; - if (c == NULL) { - return NGX_DECLINED; - } - - if (c->ssl == NULL) { - return NGX_DECLINED; - } - data = c->ssl->fp_ja3_data.data; - if (!data) { - return NGX_DECLINED; + if (data == NULL) { + /** + * NOTE: + * If we can't set it in OpenSSL, + * then something defenetly something went wrong. + * Typical production configuration has log level set to error, + * this would help to debug this case, if it happened. + */ + ngx_log_error(NGX_LOG_WARN, c->log, 0, + "ngx_ssl_ja3: fp_ja_data == NULL"); + return NGX_ERROR; } - if (c->ssl->fp_ja3_str.len > 0) { + if (c->ssl->fp_ja3_str.data != NULL) { return NGX_OK; } c->ssl->fp_ja3_str.len = c->ssl->fp_ja3_data.len * 3; c->ssl->fp_ja3_str.data = ngx_pnalloc(c->pool, c->ssl->fp_ja3_str.len); + if (c->ssl->fp_ja3_str.data == NULL) { + /** Else we break a data stream */ + c->ssl->fp_ja3_str.len = 0; + return NGX_ERROR; + } ngx_log_debug(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_ssl_ja3: alloc bytes: [%d]\n", c->ssl->fp_ja3_str.len); @@ -293,32 +310,37 @@ int ngx_ssl_ja3(ngx_connection_t *c) return NGX_OK; } +/** + * Params: + * c and c->ssl should be valid pointers and tested before. + * + * Returns: + * NGX_OK - c->ssl->fp_ja3_hash is alread set + * NGX_ERROR - something went wrong + */ int ngx_ssl_ja3_hash(ngx_connection_t *c) { - if (c == NULL) { - return NGX_DECLINED; - } - - if (c->ssl == NULL) { - return NGX_DECLINED; - } + ngx_md5_t ctx; + u_char hash_buf[16]; if (c->ssl->fp_ja3_hash.len > 0) { return NGX_OK; } - if (ngx_ssl_ja3(c) == NGX_DECLINED) { - return NGX_DECLINED; + if (ngx_ssl_ja3(c) != NGX_OK) { + return NGX_ERROR; } c->ssl->fp_ja3_hash.len = 32; c->ssl->fp_ja3_hash.data = ngx_pnalloc(c->pool, c->ssl->fp_ja3_hash.len); + if (c->ssl->fp_ja3_hash.data == NULL) { + /** Else we can break a stream */ + c->ssl->fp_ja3_hash.len = 0; + return NGX_ERROR; + } ngx_log_debug(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_ssl_ja3_hash: alloc bytes: [%d]\n", c->ssl->fp_ja3_hash.len); - ngx_md5_t ctx; - u_char hash_buf[16]; - ngx_md5_init(&ctx); ngx_md5_update(&ctx, c->ssl->fp_ja3_str.data, c->ssl->fp_ja3_str.len); ngx_md5_final(hash_buf, &ctx); @@ -327,22 +349,33 @@ int ngx_ssl_ja3_hash(ngx_connection_t *c) return NGX_OK; } +/** + * Params: + * c and h2c should be a valid pointers + * + * Returns: + * NGX_OK -- h2c->fp_str is set + * NGX_ERROR -- something went wrong + */ int ngx_http2_fingerprint(ngx_connection_t *c, ngx_http_v2_connection_t *h2c) { unsigned char *pstr = NULL; unsigned short n = 0; size_t i; - if (!h2c) { - return NGX_DECLINED; - } - if (h2c->fp_str.len > 0) { return NGX_OK; } - n = 4 + h2c->fp_settings.len * 3 + 10 + h2c->fp_priorities.len * 2 + h2c->fp_pseudoheaders.len * 2; + n = 4 + h2c->fp_settings.len * 3 + + 10 + h2c->fp_priorities.len * 2 + + h2c->fp_pseudoheaders.len * 2; + h2c->fp_str.data = ngx_pnalloc(c->pool, n); + if (h2c->fp_str.data == NULL) { + /** Else we break a stream */ + return NGX_ERROR; + } pstr = h2c->fp_str.data; ngx_log_debug(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_http2_fingerprint: alloc bytes: [%d]\n", n); diff --git a/src/nginx_ssl_fingerprint.h b/src/nginx_ssl_fingerprint.h new file mode 100644 index 0000000..28ccca6 --- /dev/null +++ b/src/nginx_ssl_fingerprint.h @@ -0,0 +1,19 @@ + +/* + * Obj: nginx_ssl_fingerprint.c + */ + +#ifndef NGINX_SSL_FINGERPRINT_H_ +#define NGINX_SSL_FINGERPRINT_H_ 1 + + +#include +#include +#include + +int ngx_ssl_ja3(ngx_connection_t *c); +int ngx_ssl_ja3_hash(ngx_connection_t *c); +int ngx_http2_fingerprint(ngx_connection_t *c, ngx_http_v2_connection_t *h2c); + +#endif /** NGINX_SSL_FINGERPRINT_H_ */ + diff --git a/src/ngx_http_ssl_fingerprint_module.c b/src/ngx_http_ssl_fingerprint_module.c index 5166096..e2b0afd 100644 --- a/src/ngx_http_ssl_fingerprint_module.c +++ b/src/ngx_http_ssl_fingerprint_module.c @@ -1,63 +1,75 @@ + #include #include #include -extern int ngx_ssl_ja3(ngx_connection_t *c); -extern int ngx_ssl_ja3_hash(ngx_connection_t *c); -extern int ngx_http2_fingerprint(ngx_connection_t *c, ngx_http_v2_connection_t *h2c); +#include static ngx_int_t ngx_http_ssl_fingerprint_init(ngx_conf_t *cf); +static ngx_int_t ngx_http_ssl_greased(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_ssl_fingerprint(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_ssl_fingerprint_hash(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_http2_fingerprint(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); static ngx_http_module_t ngx_http_ssl_fingerprint_module_ctx = { - NULL, /* preconfiguration */ - ngx_http_ssl_fingerprint_init, /* postconfiguration */ - NULL, /* create main configuration */ - NULL, /* init main configuration */ - NULL, /* create server configuration */ - NULL, /* merge server configuration */ - NULL, /* create location configuration */ - NULL /* merge location configuration */ + ngx_http_ssl_fingerprint_init, /* preconfiguration */ + NULL, /* postconfiguration */ + NULL, /* create main configuration */ + NULL, /* init main configuration */ + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + NULL, /* create location configuration */ + NULL /* merge location configuration */ }; ngx_module_t ngx_http_ssl_fingerprint_module = { NGX_MODULE_V1, &ngx_http_ssl_fingerprint_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_HTTP_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ + NULL, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ NGX_MODULE_V1_PADDING}; +static ngx_http_variable_t ngx_http_ssl_fingerprint_variables_list[] = { + {ngx_string("http_ssl_greased"), NULL, ngx_http_ssl_greased, + 0, NGX_HTTP_VAR_NOCACHEABLE, 0}, + {ngx_string("http_ssl_ja3"), NULL, ngx_http_ssl_fingerprint, + 0, NGX_HTTP_VAR_NOCACHEABLE, 0}, + {ngx_string("http_ssl_ja3_hash"), NULL, ngx_http_ssl_fingerprint_hash, + 0, NGX_HTTP_VAR_NOCACHEABLE, 0}, + {ngx_string("http2_fingerprint"), NULL, ngx_http_http2_fingerprint, + 0, NGX_HTTP_VAR_NOCACHEABLE, 0}, + ngx_http_null_variable +}; static ngx_int_t ngx_http_ssl_greased(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - if (r->connection == NULL) - { - return NGX_OK; - } + /* For access.log's map $http2_VAR {}: + * if it's not found, then user could add a defined string */ + v->not_found = 1; - if (r->connection->ssl == NULL) - { + if (r->connection->ssl == NULL) { return NGX_OK; } - if (ngx_ssl_ja3(r->connection) == NGX_DECLINED) - { + if (ngx_ssl_ja3(r->connection) != NGX_OK) { return NGX_ERROR; } v->len = 1; - v->data = (u_char*)(r->connection->ssl->fp_tls_greased ? "1" : "0"); - - v->valid = 1; - v->no_cacheable = 1; + v->data = (u_char*) (r->connection->ssl->fp_tls_greased ? "1" : "0"); v->not_found = 0; return NGX_OK; @@ -67,25 +79,20 @@ static ngx_int_t ngx_http_ssl_fingerprint(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - if (r->connection == NULL) - { - return NGX_OK; - } + /* For access.log's map $VAR {}: + * if it's not found, then user could add a defined string */ + v->not_found = 1; - if (r->connection->ssl == NULL) - { + if (r->connection->ssl == NULL) { return NGX_OK; } - if (ngx_ssl_ja3(r->connection) == NGX_DECLINED) - { + if (ngx_ssl_ja3(r->connection) != NGX_OK) { return NGX_ERROR; } v->data = r->connection->ssl->fp_ja3_str.data; v->len = r->connection->ssl->fp_ja3_str.len; - v->valid = 1; - v->no_cacheable = 1; v->not_found = 0; return NGX_OK; @@ -95,25 +102,20 @@ static ngx_int_t ngx_http_ssl_fingerprint_hash(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - if (r->connection == NULL) - { - return NGX_OK; - } + /* For access.log's map $VAR {}: + * if it's not found, then user could add a defined string */ + v->not_found = 1; - if (r->connection->ssl == NULL) - { + if (r->connection->ssl == NULL) { return NGX_OK; } - if (ngx_ssl_ja3_hash(r->connection) == NGX_DECLINED) - { - return NGX_ERROR; + if (ngx_ssl_ja3_hash(r->connection) != NGX_OK) { + return NGX_OK; } v->data = r->connection->ssl->fp_ja3_hash.data; v->len = r->connection->ssl->fp_ja3_hash.len; - v->valid = 1; - v->no_cacheable = 1; v->not_found = 0; return NGX_OK; @@ -123,77 +125,43 @@ static ngx_int_t ngx_http_http2_fingerprint(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data) { - if (r->connection == NULL) - { - return NGX_OK; - } + /* For access.log's map $VAR {}: + * if it's not found, then user could add a defined string */ + v->not_found = 1; - if (r->stream == NULL) - { + if (r->stream == NULL) { return NGX_OK; } - if (r->stream->connection == NULL) - { - return NGX_OK; - } - - if (ngx_http2_fingerprint(r->connection, r->stream->connection) == NGX_DECLINED) + if (ngx_http2_fingerprint(r->connection, r->stream->connection) + != NGX_OK) { return NGX_ERROR; } v->data = r->stream->connection->fp_str.data; v->len = r->stream->connection->fp_str.len; - v->valid = 1; - v->no_cacheable = 1; v->not_found = 0; return NGX_OK; } -static ngx_http_variable_t ngx_http_ssl_fingerprint_variables_list[] = { - {ngx_string("http_ssl_greased"), - NULL, - ngx_http_ssl_greased, - 0, 0, 0}, - {ngx_string("http_ssl_ja3"), - NULL, - ngx_http_ssl_fingerprint, - 0, 0, 0}, - {ngx_string("http_ssl_ja3_hash"), - NULL, - ngx_http_ssl_fingerprint_hash, - 0, 0, 0}, - {ngx_string("http2_fingerprint"), - NULL, - ngx_http_http2_fingerprint, - 0, 0, 0}, -}; - static ngx_int_t ngx_http_ssl_fingerprint_init(ngx_conf_t *cf) { + ngx_http_variable_t *var, *v; - ngx_http_variable_t *v; - size_t l = 0; - size_t vars_len; - - vars_len = (sizeof(ngx_http_ssl_fingerprint_variables_list) / - sizeof(ngx_http_ssl_fingerprint_variables_list[0])); + for (v = ngx_http_ssl_fingerprint_variables_list; v->name.len; v++) { - /* Register variables */ - for (l = 0; l < vars_len; ++l) - { - v = ngx_http_add_variable(cf, - &ngx_http_ssl_fingerprint_variables_list[l].name, - ngx_http_ssl_fingerprint_variables_list[l].flags); - if (v == NULL) - { - continue; + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; } - *v = ngx_http_ssl_fingerprint_variables_list[l]; + /** NOTE: update it, if set_handler will be needed */ + var->get_handler = v->get_handler; + var->data = v->data; } return NGX_OK; } + diff --git a/src/ngx_stream_ssl_fingerprint_preread_module.c b/src/ngx_stream_ssl_fingerprint_preread_module.c index 46b5186..a2629e2 100644 --- a/src/ngx_stream_ssl_fingerprint_preread_module.c +++ b/src/ngx_stream_ssl_fingerprint_preread_module.c @@ -1,3 +1,9 @@ + +/* + * Please make sure that you have been incuded --with-streams_ssl_moduke + * before --add-module Else this module won't be compiled + */ + #include #include #include @@ -20,15 +26,15 @@ static ngx_stream_module_t ngx_stream_ssl_fingerprint_preread_module_ctx = { ngx_module_t ngx_stream_ssl_fingerprint_preread_module = { NGX_MODULE_V1, &ngx_stream_ssl_fingerprint_preread_module_ctx, /* module context */ - NULL, /* module directives */ - NGX_STREAM_MODULE, /* module type */ - NULL, /* init master */ - NULL, /* init module */ - NULL, /* init process */ - NULL, /* init thread */ - NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ + NULL, /* module directives */ + NGX_STREAM_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ NGX_MODULE_V1_PADDING }; @@ -162,3 +168,4 @@ ngx_stream_ssl_fingerprint_preread_init(ngx_conf_t *cf) return NGX_OK; } +