Skip to content

Commit 52eb88d

Browse files
catbro666zhuizhuhaomeng
authored andcommitted
feature: implemented the ssl_client_hello_by_lua* api for controlling the NGINX downstream SSL handshake dynamically with Lua.
1 parent 2d667ec commit 52eb88d

File tree

4 files changed

+1289
-0
lines changed

4 files changed

+1289
-0
lines changed

lib/ngx/ssl/clienthello.lua

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
-- Copyright (C) Yichun Zhang (agentzh)
2+
3+
4+
local base = require "resty.core.base"
5+
base.allows_subsystem('http', 'stream')
6+
7+
8+
local ffi = require "ffi"
9+
local bit = require "bit"
10+
local C = ffi.C
11+
local ffi_str = ffi.string
12+
local get_request = base.get_request
13+
local error = error
14+
local errmsg = base.get_errmsg_ptr()
15+
local get_size_ptr = base.get_size_ptr
16+
local FFI_OK = base.FFI_OK
17+
local subsystem = ngx.config.subsystem
18+
local ngx_phase = ngx.get_phase
19+
20+
21+
local ngx_lua_ffi_ssl_get_client_hello_server_name
22+
local ngx_lua_ffi_ssl_get_client_hello_ext
23+
local ngx_lua_ffi_ssl_set_protocols
24+
25+
26+
if subsystem == 'http' then
27+
ffi.cdef[[
28+
int ngx_http_lua_ffi_ssl_get_client_hello_server_name(ngx_http_request_t *r,
29+
const char **name, size_t *namelen, char **err);
30+
31+
int ngx_http_lua_ffi_ssl_get_client_hello_ext(ngx_http_request_t *r,
32+
unsigned int type, const unsigned char **out, size_t *outlen,
33+
char **err);
34+
35+
int ngx_http_lua_ffi_ssl_set_protocols(ngx_http_request_t *r,
36+
int protocols, char **err);
37+
]]
38+
39+
ngx_lua_ffi_ssl_get_client_hello_server_name =
40+
C.ngx_http_lua_ffi_ssl_get_client_hello_server_name
41+
ngx_lua_ffi_ssl_get_client_hello_ext =
42+
C.ngx_http_lua_ffi_ssl_get_client_hello_ext
43+
ngx_lua_ffi_ssl_set_protocols = C.ngx_http_lua_ffi_ssl_set_protocols
44+
45+
elseif subsystem == 'stream' then
46+
ffi.cdef[[
47+
int ngx_stream_lua_ffi_ssl_get_client_hello_server_name(
48+
ngx_stream_lua_request_t *r, const char **name, size_t *namelen,
49+
char **err);
50+
51+
int ngx_stream_lua_ffi_ssl_get_client_hello_ext(
52+
ngx_stream_lua_request_t *r, unsigned int type,
53+
const unsigned char **out, size_t *outlen, char **err);
54+
55+
int ngx_stream_lua_ffi_ssl_set_protocols(ngx_stream_lua_request_t *r,
56+
int protocols, char **err);
57+
]]
58+
59+
ngx_lua_ffi_ssl_get_client_hello_server_name =
60+
C.ngx_stream_lua_ffi_ssl_get_client_hello_server_name
61+
ngx_lua_ffi_ssl_get_client_hello_ext =
62+
C.ngx_stream_lua_ffi_ssl_get_client_hello_ext
63+
ngx_lua_ffi_ssl_set_protocols = C.ngx_stream_lua_ffi_ssl_set_protocols
64+
end
65+
66+
67+
local _M = { version = base.version }
68+
69+
70+
local ccharpp = ffi.new("const char*[1]")
71+
local cucharpp = ffi.new("const unsigned char*[1]")
72+
73+
74+
-- return server_name, err
75+
function _M.get_client_hello_server_name()
76+
local r = get_request()
77+
if not r then
78+
error("no request found")
79+
end
80+
81+
if ngx_phase() ~= "ssl_client_hello" then
82+
error("API disabled in the current context", 2)
83+
end
84+
85+
local sizep = get_size_ptr()
86+
87+
local rc = ngx_lua_ffi_ssl_get_client_hello_server_name(r, ccharpp, sizep,
88+
errmsg)
89+
if rc == FFI_OK then
90+
return ffi_str(ccharpp[0], sizep[0])
91+
end
92+
93+
-- NGX_DECLINED: no sni extension
94+
if rc == -5 then
95+
return nil
96+
end
97+
98+
return nil, ffi_str(errmsg[0])
99+
end
100+
101+
102+
-- return ext, err
103+
function _M.get_client_hello_ext(ext_type)
104+
local r = get_request()
105+
if not r then
106+
error("no request found")
107+
end
108+
109+
if ngx_phase() ~= "ssl_client_hello" then
110+
error("API disabled in the current context", 2)
111+
end
112+
113+
local sizep = get_size_ptr()
114+
115+
local rc = ngx_lua_ffi_ssl_get_client_hello_ext(r, ext_type, cucharpp,
116+
sizep, errmsg)
117+
if rc == FFI_OK then
118+
return ffi_str(cucharpp[0], sizep[0])
119+
end
120+
121+
-- NGX_DECLINED: no extension
122+
if rc == -5 then
123+
return nil
124+
end
125+
126+
return nil, ffi_str(errmsg[0])
127+
end
128+
129+
130+
local prot_map = {
131+
["SSLv2"] = 0x0002,
132+
["SSLv3"] = 0x0004,
133+
["TLSv1"] = 0x0008,
134+
["TLSv1.1"] = 0x0010,
135+
["TLSv1.2"] = 0x0020,
136+
["TLSv1.3"] = 0x0040
137+
}
138+
139+
140+
-- return ok, err
141+
function _M.set_protocols(protocols)
142+
local r = get_request()
143+
if not r then
144+
error("no request found")
145+
end
146+
147+
if ngx_phase() ~= "ssl_client_hello" then
148+
error("API disabled in the current context" .. ngx_phase(), 2)
149+
end
150+
151+
local prots = 0
152+
for _, v in ipairs(protocols) do
153+
if not prot_map[v] then
154+
return nil, "invalid protocols failed"
155+
end
156+
prots = bit.bor(prots, prot_map[v])
157+
end
158+
159+
local rc = ngx_lua_ffi_ssl_set_protocols(r, prots, errmsg)
160+
if rc == FFI_OK then
161+
return true
162+
end
163+
164+
return nil, ffi_str(errmsg[0])
165+
end
166+
167+
return _M

0 commit comments

Comments
 (0)