Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(patch): support dynamic disable http2 alpn in ssl client hello p… #13643

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
177 changes: 177 additions & 0 deletions build/openresty/patches/ngx_lua-0.10.26_01-ssl-disable-h2-alpn.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
diff --git a/bundle/lua-resty-core-0.1.28/lib/ngx/ssl.lua b/bundle/lua-resty-core-0.1.28/lib/ngx/ssl.lua
index 8792be0..38cbc51 100644
--- a/bundle/lua-resty-core-0.1.28/lib/ngx/ssl.lua
+++ b/bundle/lua-resty-core-0.1.28/lib/ngx/ssl.lua
@@ -18,6 +18,7 @@ local get_size_ptr = base.get_size_ptr
local FFI_DECLINED = base.FFI_DECLINED
local FFI_OK = base.FFI_OK
local subsystem = ngx.config.subsystem
+local get_phase = ngx.get_phase


local ngx_lua_ffi_ssl_set_der_certificate
@@ -37,7 +38,7 @@ local ngx_lua_ffi_set_priv_key
local ngx_lua_ffi_free_cert
local ngx_lua_ffi_free_priv_key
local ngx_lua_ffi_ssl_verify_client
-
+local ngx_lua_ffi_disable_http2

if subsystem == 'http' then
ffi.cdef[[
@@ -87,6 +88,7 @@ if subsystem == 'http' then

int ngx_http_lua_ffi_ssl_verify_client(void *r,
void *cdata, int depth, char **err);
+ int ngx_http_lua_ffi_ssl_disable_http2_alpn(ngx_http_request_t *r, char **err);
]]

ngx_lua_ffi_ssl_set_der_certificate =
@@ -108,6 +110,7 @@ if subsystem == 'http' then
ngx_lua_ffi_free_cert = C.ngx_http_lua_ffi_free_cert
ngx_lua_ffi_free_priv_key = C.ngx_http_lua_ffi_free_priv_key
ngx_lua_ffi_ssl_verify_client = C.ngx_http_lua_ffi_ssl_verify_client
+ ngx_lua_ffi_disable_http2 = C.ngx_http_lua_ffi_ssl_disable_http2_alpn

elseif subsystem == 'stream' then
ffi.cdef[[
@@ -436,6 +439,25 @@ function _M.verify_client(ca_certs, depth)
end


+function _M.disable_http2_alpn()
+ if get_phase() ~= "ssl_client_hello" then
+ error("API disabled in the current context")
+ end
+
+ local r = get_request()
+ if not r then
+ error("no request found")
+ end
+
+ local rc = ngx_lua_ffi_disable_http2(r, errmsg)
+ if rc == FFI_OK then
+ return true
+ end
+
+ return false, ffi_str(errmsg[0])
+end
+
+
do
_M.SSL3_VERSION = 0x0300
_M.TLS1_VERSION = 0x0301
diff --git a/bundle/nginx-1.25.3/src/http/modules/ngx_http_ssl_module.c b/bundle/nginx-1.25.3/src/http/modules/ngx_http_ssl_module.c
index 1c92d9f..cab2300 100644
--- a/bundle/nginx-1.25.3/src/http/modules/ngx_http_ssl_module.c
+++ b/bundle/nginx-1.25.3/src/http/modules/ngx_http_ssl_module.c
@@ -8,6 +8,7 @@
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
+#include <ngx_http_lua_api.h>

#if (NGX_QUIC_OPENSSL_COMPAT)
#include <ngx_event_quic_openssl_compat.h>
@@ -474,7 +475,7 @@ ngx_http_ssl_alpn_select(ngx_ssl_conn_t *ssl_conn, const unsigned char **out,
#if (NGX_HTTP_V2)
h2scf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_v2_module);

- if (h2scf->enable || hc->addr_conf->http2) {
+ if ((h2scf->enable || hc->addr_conf->http2) && !ngx_http_lua_get_ssl_disable_http2_alpn(c->ssl)) {
srv = (unsigned char *) NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS;
srvlen = sizeof(NGX_HTTP_V2_ALPN_PROTO NGX_HTTP_ALPN_PROTOS) - 1;

diff --git a/bundle/nginx-1.25.3/src/http/ngx_http_request.c b/bundle/nginx-1.25.3/src/http/ngx_http_request.c
index bd2be5e..022e905 100644
--- a/bundle/nginx-1.25.3/src/http/ngx_http_request.c
+++ b/bundle/nginx-1.25.3/src/http/ngx_http_request.c
@@ -8,6 +8,7 @@
#include <ngx_config.h>
#include <ngx_core.h>
#include <ngx_http.h>
+#include <ngx_http_lua_api.h>


static void ngx_http_wait_request_handler(ngx_event_t *ev);
diff --git a/bundle/ngx_lua-0.10.26/src/api/ngx_http_lua_api.h b/bundle/ngx_lua-0.10.26/src/api/ngx_http_lua_api.h
index 193c44e..b81c73d 100644
--- a/bundle/ngx_lua-0.10.26/src/api/ngx_http_lua_api.h
+++ b/bundle/ngx_lua-0.10.26/src/api/ngx_http_lua_api.h
@@ -70,6 +70,7 @@ void ngx_http_lua_co_ctx_resume_helper(ngx_http_lua_co_ctx_t *coctx, int nrets);

int ngx_http_lua_get_lua_http10_buffering(ngx_http_request_t *r);

+unsigned ngx_http_lua_get_ssl_disable_http2_alpn(ngx_ssl_connection_t *ssl);

#endif /* _NGX_HTTP_LUA_API_H_INCLUDED_ */

diff --git a/bundle/ngx_lua-0.10.26/src/ngx_http_lua_api.c b/bundle/ngx_lua-0.10.26/src/ngx_http_lua_api.c
index 0d3ec9c..963bf96 100644
--- a/bundle/ngx_lua-0.10.26/src/ngx_http_lua_api.c
+++ b/bundle/ngx_lua-0.10.26/src/ngx_http_lua_api.c
@@ -340,5 +340,14 @@ ngx_http_lua_get_lua_http10_buffering(ngx_http_request_t *r)
return llcf->http10_buffering;
}

+unsigned ngx_http_lua_get_ssl_disable_http2_alpn(ngx_ssl_connection_t *ssl)
+{
+ ngx_http_lua_assert(ssl->connection);
+ ngx_http_lua_ssl_ctx_t *cctx;
+
+ cctx = ngx_http_lua_ssl_get_ctx(ssl->connection);
+ ngx_http_lua_assert(cctx);
+ return cctx->disable_http2_alpn;
+}

/* vi:set ft=c ts=4 sw=4 et fdm=marker: */
diff --git a/bundle/ngx_lua-0.10.26/src/ngx_http_lua_ssl.h b/bundle/ngx_lua-0.10.26/src/ngx_http_lua_ssl.h
index 3d577c6..c6ff1ed 100644
--- a/bundle/ngx_lua-0.10.26/src/ngx_http_lua_ssl.h
+++ b/bundle/ngx_lua-0.10.26/src/ngx_http_lua_ssl.h
@@ -38,6 +38,7 @@ typedef struct {
unsigned entered_client_hello_handler:1;
unsigned entered_cert_handler:1;
unsigned entered_sess_fetch_handler:1;
+ unsigned disable_http2_alpn:1;
} ngx_http_lua_ssl_ctx_t;


diff --git a/bundle/ngx_lua-0.10.26/src/ngx_http_lua_ssl_client_helloby.c b/bundle/ngx_lua-0.10.26/src/ngx_http_lua_ssl_client_helloby.c
index 03ac430..4f178f8 100644
--- a/bundle/ngx_lua-0.10.26/src/ngx_http_lua_ssl_client_helloby.c
+++ b/bundle/ngx_lua-0.10.26/src/ngx_http_lua_ssl_client_helloby.c
@@ -713,4 +713,33 @@ ngx_http_lua_ffi_ssl_set_protocols(ngx_http_request_t *r,
return NGX_OK;
}

+int
+ngx_http_lua_ffi_ssl_disable_http2_alpn(ngx_http_request_t *r, char **err)
+{
+ ngx_ssl_conn_t *ssl_conn;
+ ngx_http_lua_ssl_ctx_t *cctx;
+
+ if (r->connection == NULL || r->connection->ssl == NULL) {
+ *err = "bad request";
+ return NGX_ERROR;
+ }
+
+ ssl_conn = r->connection->ssl->connection;
+ if (ssl_conn == NULL) {
+ *err = "bad ssl conn";
+ return NGX_ERROR;
+ }
+
+ cctx = ngx_http_lua_ssl_get_ctx(ssl_conn);
+ if (cctx == NULL) {
+ *err = "bad lua context";
+ return NGX_ERROR;
+ }
+ ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
+ "lua ssl disable http2");
+ cctx->disable_http2_alpn = 1;
+
+ return NGX_OK;
+}
+
#endif /* NGX_HTTP_SSL */
150 changes: 150 additions & 0 deletions t/04-patch/04-ngx-ssl-disable-http2-alpn.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# vim:set ft= ts=4 sw=4 et:

use Test::Nginx::Socket::Lua;
use Cwd qw(cwd);

repeat_each(2);

plan tests => repeat_each() * (blocks() * 7 - 2);

my $pwd = cwd();

$ENV{TEST_NGINX_HTML_DIR} ||= html_dir();

log_level('info');
no_long_string();
#no_diff();

run_tests();

__DATA__

=== TEST 1: normal http2 alpn
--- http_config

server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
listen 60000 ssl;
server_name konghq.com;
ssl_certificate ../../certs/test.crt;
ssl_certificate_key ../../certs/test.key;
ssl_session_cache off;
ssl_session_tickets on;
server_tokens off;
http2 on;
ssl_client_hello_by_lua_block {
local ssl = require "ngx.ssl"
local ok, err = ssl.disable_http2_alpn()
if not ok then
ngx.log(ngx.ERR, "failed to disable http2")
end
}
location /foo {
default_type 'text/plain';
content_by_lua_block {ngx.exit(200)}
more_clear_headers Date;
}
}
--- config
server_tokens off;
location /t {
content_by_lua_block {
local ngx_pipe = require "ngx.pipe"
local proc = ngx_pipe.spawn({'curl', '-vk', '--resolve', 'konghq.com:60000:127.0.0.1', 'https://konghq.com:60000'})
local stdout_data, err = proc:stdout_read_all()
if not stdout_data then
ngx.say(err)
return
end

local stderr_data, err = proc:stderr_read_all()
if not stderr_data then
ngx.say(err)
return
end

if string.find(stdout_data, "ALPN: server accepted h2") ~= nil then
ngx.say("alpn server accepted h2")
return
end

if string.find(stderr_data, "ALPN: server accepted http/1.1") ~= nil then
ngx.say("alpn server accepted http/1.1")
return
end
}
}
--- request
GET /t
--- response_body
alpn server accepted http/1.1
--- no_error_log
[error]
[alert]
[warn]
[crit]

=== TEST 2: disable http2 alpn
--- http_config

server {
listen unix:$TEST_NGINX_HTML_DIR/nginx.sock ssl;
listen 60000 ssl;
server_name konghq.com;
ssl_certificate ../../certs/test.crt;
ssl_certificate_key ../../certs/test.key;
ssl_session_cache off;
ssl_session_tickets on;
server_tokens off;
http2 on;
ssl_client_hello_by_lua_block {
local ssl = require "ngx.ssl"
local ok, err = ssl.disable_http2_alpn()
if not ok then
ngx.log(ngx.ERR, "failed to disable http2")
end
}
location /foo {
default_type 'text/plain';
content_by_lua_block {ngx.exit(200)}
more_clear_headers Date;
}
}
--- config
server_tokens off;
location /t {
content_by_lua_block {
local ngx_pipe = require "ngx.pipe"
local proc = ngx_pipe.spawn({'curl', '-vk', '--resolve', 'konghq.com:60000:127.0.0.1', 'https://konghq.com:60000'})
local stdout_data, err = proc:stdout_read_all()
if not stdout_data then
ngx.say(err)
return
end

local stderr_data, err = proc:stderr_read_all()
if not stderr_data then
ngx.say(err)
return
end

if string.find(stdout_data, "ALPN: server accepted h2") ~= nil then
ngx.say("alpn server accepted h2")
return
end

if string.find(stderr_data, "ALPN: server accepted http/1.1") ~= nil then
ngx.say("alpn server accepted http/1.1")
return
end
}
}
--- request
GET /t
--- response_body
alpn server accepted http/1.1
--- no_error_log
[error]
[alert]
[warn]
[crit]
Loading