|
| 1 | +diff --git Makefile Makefile |
| 2 | +index 3caabe2..6361a23 100644 |
| 3 | +--- Makefile |
| 4 | ++++ Makefile |
| 5 | +@@ -12,10 +12,12 @@ all: ; |
| 6 | + |
| 7 | + install: all |
| 8 | + $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/resty/core/ |
| 9 | ++ $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/resty/core/socket |
| 10 | + $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/ngx/ |
| 11 | + $(INSTALL) -d $(DESTDIR)$(LUA_LIB_DIR)/ngx/ssl |
| 12 | + $(INSTALL) lib/resty/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty/ |
| 13 | + $(INSTALL) lib/resty/core/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty/core/ |
| 14 | ++ $(INSTALL) lib/resty/core/socket/*.lua $(DESTDIR)$(LUA_LIB_DIR)/resty/core/socket |
| 15 | + $(INSTALL) lib/ngx/*.lua $(DESTDIR)$(LUA_LIB_DIR)/ngx/ |
| 16 | + $(INSTALL) lib/ngx/ssl/*.lua $(DESTDIR)$(LUA_LIB_DIR)/ngx/ssl/ |
| 17 | + |
| 18 | +diff --git lib/resty/core/socket/tcp.lua lib/resty/core/socket/tcp.lua |
| 19 | +new file mode 100644 |
| 20 | +index 0000000..30302f0 |
| 21 | +--- /dev/null |
| 22 | ++++ lib/resty/core/socket/tcp.lua |
| 23 | +@@ -0,0 +1,236 @@ |
| 24 | ++-- Copyright (C) by OpenResty Inc. |
| 25 | ++ |
| 26 | ++ |
| 27 | ++local base = require "resty.core.base" |
| 28 | ++local ffi = require "ffi" |
| 29 | ++local ssl = require "ngx.ssl" |
| 30 | ++ |
| 31 | ++ |
| 32 | ++local C = ffi.C |
| 33 | ++local ffi_str = ffi.string |
| 34 | ++local ffi_gc = ffi.gc |
| 35 | ++local FFI_ERROR = base.FFI_ERROR |
| 36 | ++local FFI_DONE = base.FFI_DONE |
| 37 | ++local FFI_OK = base.FFI_OK |
| 38 | ++local FFI_AGAIN = base.FFI_AGAIN |
| 39 | ++local FFI_NO_REQ_CTX = base.FFI_NO_REQ_CTX |
| 40 | ++local get_request = base.get_request |
| 41 | ++local new_tab = base.new_tab |
| 42 | ++local clear_tab = base.clear_tab |
| 43 | ++local error = error |
| 44 | ++local assert = assert |
| 45 | ++local type = type |
| 46 | ++local pcall = pcall |
| 47 | ++local select = select |
| 48 | ++local co_yield = coroutine._yield |
| 49 | ++local io_open = io.open |
| 50 | ++ |
| 51 | ++ |
| 52 | ++ffi.cdef[[ |
| 53 | ++typedef struct ngx_http_lua_socket_tcp_upstream_s |
| 54 | ++ ngx_http_lua_socket_tcp_upstream_t; |
| 55 | ++ |
| 56 | ++int ngx_http_lua_ffi_socket_tcp_tlshandshake(ngx_http_request_t *r, |
| 57 | ++ ngx_http_lua_socket_tcp_upstream_t *u, void *sess, |
| 58 | ++ int enable_session_reuse, ngx_str_t *server_name, int verify, |
| 59 | ++ int ocsp_status_req, void *chain, void *pkey, char **errmsg); |
| 60 | ++ |
| 61 | ++int ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result(ngx_http_request_t *r, |
| 62 | ++ ngx_http_lua_socket_tcp_upstream_t *u, void **sess, char **errmsg, |
| 63 | ++ int *openssl_error_code); |
| 64 | ++ |
| 65 | ++void ngx_http_lua_ffi_tls_free_session(void *sess); |
| 66 | ++]] |
| 67 | ++ |
| 68 | ++ |
| 69 | ++local SOCKET_CTX_INDEX = 1 |
| 70 | ++ |
| 71 | ++ |
| 72 | ++local errmsg = base.get_errmsg_ptr() |
| 73 | ++local session_ptr = ffi.new("void *[1]") |
| 74 | ++local server_name_str = ffi.new("ngx_str_t[1]") |
| 75 | ++local openssl_error_code = ffi.new("int[1]") |
| 76 | ++local cached_options = new_tab(0, 4) |
| 77 | ++ |
| 78 | ++ |
| 79 | ++local function read_file(path) |
| 80 | ++ local f, err = io_open(path) |
| 81 | ++ if not f then |
| 82 | ++ return nil, err |
| 83 | ++ end |
| 84 | ++ |
| 85 | ++ local txt, err = f:read("*a") |
| 86 | ++ f:close() |
| 87 | ++ if not txt then |
| 88 | ++ return nil, err |
| 89 | ++ end |
| 90 | ++ |
| 91 | ++ return txt |
| 92 | ++end |
| 93 | ++ |
| 94 | ++ |
| 95 | ++local function tlshandshake(self, options) |
| 96 | ++ if not options then |
| 97 | ++ clear_tab(cached_options) |
| 98 | ++ options = cached_options |
| 99 | ++ |
| 100 | ++ elseif type(options) ~= "table" then |
| 101 | ++ error("bad options arg: table expected", 2) |
| 102 | ++ end |
| 103 | ++ |
| 104 | ++ local r = get_request() |
| 105 | ++ if not r then |
| 106 | ++ error("no request found", 2) |
| 107 | ++ end |
| 108 | ++ |
| 109 | ++ local reused_session = options.reused_session |
| 110 | ++ session_ptr[0] = type(reused_session) == "cdata" and reused_session or nil |
| 111 | ++ |
| 112 | ++ if options.server_name then |
| 113 | ++ server_name_str[0].data = options.server_name |
| 114 | ++ server_name_str[0].len = #options.server_name |
| 115 | ++ |
| 116 | ++ else |
| 117 | ++ server_name_str[0].data = nil |
| 118 | ++ server_name_str[0].len = 0 |
| 119 | ++ end |
| 120 | ++ |
| 121 | ++ local client_cert, client_pkey |
| 122 | ++ |
| 123 | ++ local client_cert_path = options.client_cert_path |
| 124 | ++ local client_pkey_path = options.client_priv_key_path |
| 125 | ++ if client_cert_path then |
| 126 | ++ if not client_pkey_path then |
| 127 | ++ error("client certificate supplied without corresponding " .. |
| 128 | ++ "private key", 2) |
| 129 | ++ end |
| 130 | ++ |
| 131 | ++ if type(client_cert_path) ~= "string" then |
| 132 | ++ error("bad client_cert option type", 2) |
| 133 | ++ end |
| 134 | ++ |
| 135 | ++ if type(client_pkey_path) ~= "string" then |
| 136 | ++ error("bad client_priv_key option type", 2) |
| 137 | ++ end |
| 138 | ++ |
| 139 | ++ local txt, err = read_file(client_cert_path) |
| 140 | ++ if not txt then |
| 141 | ++ return nil, err |
| 142 | ++ end |
| 143 | ++ |
| 144 | ++ local cert, err = ssl.parse_pem_cert(txt) |
| 145 | ++ if not cert then |
| 146 | ++ return nil, err |
| 147 | ++ end |
| 148 | ++ |
| 149 | ++ client_cert = cert |
| 150 | ++ |
| 151 | ++ local txt, err = read_file(client_pkey_path) |
| 152 | ++ if not txt then |
| 153 | ++ return nil, err |
| 154 | ++ end |
| 155 | ++ |
| 156 | ++ local pkey, err = ssl.parse_pem_priv_key(txt) |
| 157 | ++ if not pkey then |
| 158 | ++ return nil, err |
| 159 | ++ end |
| 160 | ++ |
| 161 | ++ client_pkey = pkey |
| 162 | ++ end |
| 163 | ++ |
| 164 | ++ local u = self[SOCKET_CTX_INDEX] |
| 165 | ++ |
| 166 | ++ local rc = C.ngx_http_lua_ffi_socket_tcp_tlshandshake(r, u, |
| 167 | ++ session_ptr[0], |
| 168 | ++ reused_session ~= false, |
| 169 | ++ server_name_str, |
| 170 | ++ options.verify and 1 or 0, |
| 171 | ++ options.ocsp_status_req and 1 or 0, |
| 172 | ++ client_cert, client_pkey, errmsg) |
| 173 | ++ |
| 174 | ++ if rc == FFI_NO_REQ_CTX then |
| 175 | ++ error("no request ctx found", 2) |
| 176 | ++ end |
| 177 | ++ |
| 178 | ++ while true do |
| 179 | ++ if rc == FFI_ERROR then |
| 180 | ++ if openssl_error_code[0] ~= 0 then |
| 181 | ++ return nil, openssl_error_code[0] .. ": " .. ffi_str(errmsg[0]) |
| 182 | ++ end |
| 183 | ++ |
| 184 | ++ return nil, ffi_str(errmsg[0]) |
| 185 | ++ end |
| 186 | ++ |
| 187 | ++ if rc == FFI_DONE then |
| 188 | ++ return reused_session |
| 189 | ++ end |
| 190 | ++ |
| 191 | ++ if rc == FFI_OK then |
| 192 | ++ if reused_session == false then |
| 193 | ++ return true |
| 194 | ++ end |
| 195 | ++ |
| 196 | ++ rc = C.ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result(r, u, |
| 197 | ++ session_ptr, errmsg, openssl_error_code) |
| 198 | ++ |
| 199 | ++ assert(rc == FFI_OK) |
| 200 | ++ |
| 201 | ++ if session_ptr[0] == nil then |
| 202 | ++ return nil |
| 203 | ++ end |
| 204 | ++ |
| 205 | ++ return ffi_gc(session_ptr[0], C.ngx_http_lua_ffi_tls_free_session) |
| 206 | ++ end |
| 207 | ++ |
| 208 | ++ assert(rc == FFI_AGAIN) |
| 209 | ++ |
| 210 | ++ co_yield() |
| 211 | ++ |
| 212 | ++ rc = C.ngx_http_lua_ffi_socket_tcp_get_tlshandshake_result(r, u, |
| 213 | ++ session_ptr, errmsg, openssl_error_code) |
| 214 | ++ end |
| 215 | ++end |
| 216 | ++ |
| 217 | ++ |
| 218 | ++local function sslhandshake(self, reused_session, server_name, ssl_verify, |
| 219 | ++ send_status_req, ...) |
| 220 | ++ |
| 221 | ++ local n = select("#", ...) |
| 222 | ++ if not self or n > 1 then |
| 223 | ++ error("ngx.socket sslhandshake: expecting 1 ~ 5 arguments " .. |
| 224 | ++ "(including the object), but seen " .. (self and 5 + n or 0)) |
| 225 | ++ end |
| 226 | ++ |
| 227 | ++ cached_options.reused_session = reused_session |
| 228 | ++ cached_options.server_name = server_name |
| 229 | ++ cached_options.verify = ssl_verify |
| 230 | ++ cached_options.ocsp_status_req = send_status_req |
| 231 | ++ |
| 232 | ++ local res, err = tlshandshake(self, cached_options) |
| 233 | ++ |
| 234 | ++ clear_tab(cached_options) |
| 235 | ++ |
| 236 | ++ return res, err |
| 237 | ++end |
| 238 | ++ |
| 239 | ++ |
| 240 | ++do |
| 241 | ++ local old_socket_tcp = ngx.socket.tcp |
| 242 | ++ |
| 243 | ++ function ngx.socket.tcp() |
| 244 | ++ local ok, sock = pcall(old_socket_tcp) |
| 245 | ++ if not ok then |
| 246 | ++ error(sock, 2) |
| 247 | ++ end |
| 248 | ++ |
| 249 | ++ sock.tlshandshake = tlshandshake |
| 250 | ++ sock.sslhandshake = sslhandshake |
| 251 | ++ |
| 252 | ++ return sock |
| 253 | ++ end |
| 254 | ++end |
| 255 | ++ |
| 256 | ++ |
| 257 | ++return { |
| 258 | ++ version = base.version |
| 259 | ++} |
0 commit comments