Skip to content

Commit d75e6f6

Browse files
committed
feature: implement the tcpsock:tlshandshake and tcpsock:sslhandshake
functions using FFI.
1 parent e3f3fad commit d75e6f6

File tree

2 files changed

+173
-0
lines changed

2 files changed

+173
-0
lines changed

lib/resty/core.lua

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ end
2424

2525
require "resty.core.misc"
2626
require "resty.core.ctx"
27+
require "resty.core.socket_tcp"
2728

2829

2930
local base = require "resty.core.base"

lib/resty/core/socket_tcp.lua

+172
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,172 @@
1+
local ffi = require("ffi")
2+
local base = require("resty.core.base")
3+
4+
local C = ffi.C
5+
local ffi_string = ffi.string
6+
local ffi_gc = ffi.gc
7+
local FFI_ERROR = base.FFI_ERROR
8+
local FFI_DONE = base.FFI_DONE
9+
local FFI_OK = base.FFI_OK
10+
local FFI_AGAIN = base.FFI_AGAIN
11+
local get_request = base.get_request
12+
local error = error
13+
local assert = assert
14+
local getmetatable = getmetatable
15+
local type = type
16+
local select = select
17+
local co_yield = coroutine._yield
18+
local table_new = require("table.new")
19+
local table_clear = require("table.clear")
20+
21+
if not pcall(ffi.typeof, "ngx_ssl_session_t") then
22+
ffi.cdef[[
23+
typedef struct SSL_SESSION ngx_ssl_session_t;
24+
]]
25+
end
26+
27+
ffi.cdef[[
28+
typedef struct ngx_http_lua_socket_tcp_upstream_s ngx_http_lua_socket_tcp_upstream_t;
29+
30+
int ngx_http_lua_ffi_socket_tcp_tlshandshake(ngx_http_request_t *r,
31+
ngx_http_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t *sess,
32+
int enable_session_reuse, ngx_str_t *server_name, int verify,
33+
int ocsp_status_req, char **errmsg);
34+
int ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result(ngx_http_request_t *r,
35+
ngx_http_lua_socket_tcp_upstream_t *u, ngx_ssl_session_t **sess,
36+
char **errmsg, int *openssl_error_code);
37+
void ngx_http_lua_ffi_tls_free_session(ngx_ssl_session_t *sess);
38+
]]
39+
40+
41+
local SOCKET_CTX_INDEX = 1
42+
43+
44+
local errmsg = base.get_errmsg_ptr()
45+
local session_ptr = ffi.new("ngx_ssl_session_t *[1]")
46+
local server_name_str = ffi.new("ngx_str_t[1]")
47+
local openssl_error_code = ffi.new("int[1]")
48+
local cached_options = table_new(0, 4)
49+
50+
51+
local function tlshandshake(self, options)
52+
if not options then
53+
table_clear(cached_options)
54+
options = cached_options
55+
56+
elseif type(options) ~= "table" then
57+
error("bad options table type")
58+
end
59+
60+
local r = get_request()
61+
62+
if not r then
63+
error("no request found")
64+
end
65+
66+
local reused_session = options.reused_session
67+
session_ptr[0] = type(reused_session) == "cdata" and reused_session or nil
68+
69+
if options.server_name then
70+
server_name_str[0].data = options.server_name
71+
server_name_str[0].len = #options.server_name
72+
73+
else
74+
server_name_str[0].data = nil
75+
server_name_str[0].len = 0
76+
end
77+
78+
local rc =
79+
C.ngx_http_lua_ffi_socket_tcp_tlshandshake(r, self[SOCKET_CTX_INDEX],
80+
session_ptr[0],
81+
reused_session ~= false,
82+
server_name_str,
83+
options.verify and 1 or 0,
84+
options.ocsp_status_req
85+
and 1 or 0,
86+
errmsg)
87+
88+
::again::
89+
90+
if rc == FFI_ERROR then
91+
if openssl_error_code[0] ~= 0 then
92+
return nil, openssl_error_code[0] .. ": " .. ffi_string(errmsg[0])
93+
end
94+
95+
return nil, ffi_string(errmsg[0])
96+
end
97+
98+
if rc == FFI_DONE then
99+
return options.reused_session
100+
end
101+
102+
if rc == FFI_OK then
103+
if options.reused_session == false then
104+
return true
105+
end
106+
107+
rc = C.ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result(r,
108+
self[SOCKET_CTX_INDEX], session_ptr, errmsg, openssl_error_code)
109+
110+
assert(rc == FFI_OK)
111+
112+
if session_ptr[0] == nil then
113+
return session_ptr[0]
114+
end
115+
116+
return ffi_gc(session_ptr[0], C.ngx_http_lua_ffi_tls_free_session)
117+
end
118+
119+
assert(rc == FFI_AGAIN)
120+
121+
co_yield()
122+
123+
rc = C.ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result(r,
124+
self[SOCKET_CTX_INDEX], session_ptr, errmsg, openssl_error_code)
125+
126+
assert(rc == FFI_OK or rc == FFI_ERROR)
127+
128+
goto again
129+
end
130+
131+
132+
local function sslhandshake(self, reused_session, server_name, ssl_verify,
133+
send_status_req, ...)
134+
135+
local n = select("#", ...)
136+
if not self or n > 1 then
137+
error("ngx.socket sslhandshake: expecting 1 ~ 5 "
138+
.. "arguments (including the object), but seen " .. n)
139+
end
140+
141+
cached_options.reused_session = reused_session
142+
cached_options.server_name = server_name
143+
cached_options.verify = ssl_verify
144+
cached_options.ocsp_status_req = send_status_req
145+
146+
local res, err = tlshandshake(self, cached_options)
147+
table_clear(cached_options)
148+
149+
return res, err
150+
end
151+
152+
153+
do
154+
local old_socket_tcp = ngx.socket.tcp
155+
156+
function ngx.socket.tcp()
157+
local sock = old_socket_tcp()
158+
local mt = getmetatable(sock)
159+
160+
mt.tlshandshake = tlshandshake
161+
mt.sslhandshake = sslhandshake
162+
163+
ngx.socket.tcp = old_socket_tcp
164+
165+
return sock
166+
end
167+
end
168+
169+
170+
return {
171+
version = base.version
172+
}

0 commit comments

Comments
 (0)