LiquidProxy Lua Edition
at master 161 lines 4.1 kB view raw
1local cn = require "coro-net" 2local ss = require "secure-socket" 3local tp = require "app.tlspeek" 4local uvproxy = require "app.uvproxy" 5 6local tlspeek = tp.peek 7local tpconst = tp.const 8local request_cert = Config.secure.request_cer 9local maxver = Ver2Num((Config.secure.tls.max)) 10local tp_max 11if maxver == 0.3 then 12 tp_max = tpconst.tlsVersion10 - 1 -- NOT RECOMMENDED 13else 14 tp_max = tpconst["tlsVersion"..tostring(maxver):gsub("%.", "")] 15end 16 17-- Keeping for later 18--local D_CIPHERS = require "deps.tls.common".DEFAULT_CIPHERS 19 20local errs = { 21 EAI_NONAME = {404, "Cannot resolve host"}, 22 ECONNREFUSED = {502, "Connection refused"}, 23 ETIMEDOUT = {504, "Timed out"} 24} 25 26errs.EAI_NODATA = errs.EAI_NONAME 27 28for _, t in pairs(errs) do 29 t[3] = tostring(t[2]:len()) 30end 31 32local issb = "Internal Server Error\r\n" 33local issh = { 34 code = 500, 35 {"Content-Length", issb:len()} 36} 37 38---@param cSocket uv_tcp_t 39return function(req, cSocket, cread, cwrite) 40 local authpass = HTTPAuth(req, cSocket) 41 local host, port = req.path:match("([^:]+):?(%d*)") 42 port = tonumber(port) or 443 43 44 if Config.log_ip then 45 local ua = req["User-Agent"] 46 l:info("CONNECT to %s:%s by %s (%s)", 47 host, port, 48 ---@diagnostic disable-next-line: undefined-field 49 cSocket:getpeername().ip, 50 ua and ("UA: "..ua) or "No UA") 51 end 52 53 local read, write, sSocket = cn.connect({ 54 port = port, 55 host = host, 56 hostname = host, 57 tls = true 58 }) 59 if not (read and write and sSocket) then 60 read, write, sSocket = cn.connect({ 61 port = port, 62 host = host, 63 hostname = host 64 }) 65 if not (read and write and sSocket) then 66 local e = errs[write] 67 l:error("Error connecting to server: "..(e and ("%s (%s)"):format(e[2], write) or write)) 68 if e then 69 return { 70 code = e[1], 71 reason = e[2], 72 {"Content-Length", errs[3]} 73 }, e[2] 74 end 75 return issh, issb 76 else 77 cSocket:write("HTTP/1.1 200 Connection Established\r\n\r\n") 78 uvproxy(cSocket, sSocket) return 79 end 80 end 81 cSocket:write("HTTP/1.1 200 Connection Established\r\n\r\n") 82 83 local buf, info, err, nhs = tlspeek(cSocket) 84 if nhs then 85 l:warning "Not a TLS handshake, going with direct proxy" 86 sSocket:close_reset(function() 87 read, write, sSocket = cn.connect({ 88 port = port, 89 host = host, 90 hostname = host 91 }) 92 if not (read and write and sSocket) then 93 local e = errs[write] 94 l:error("Error connecting to server: "..(e and ("%s (%s)"):format(e[2], write) or write)) 95 if e then 96 return { 97 code = e[1], 98 reason = e[2], 99 {"Content-Length", errs[3]} 100 }, e[2] 101 end 102 cSocket:close_reset() 103 else 104 write(buf) 105 uvproxy(cSocket, sSocket) 106 end 107 end) 108 return 109 end 110 111 if err then 112 l:warning("Failed to read handshake ("..err..")") 113 end 114 if not authpass then 115 if info then 116 if Config.secure.mod.http.httpver_auth and not info.supportsHTTP2 then 117 authpass = true 118 elseif Config.secure.tls.pass_auth and not (info.tlsVersion == tp_max or info.tlsVersions[tp_max]) then 119 authpass = true 120 end 121 end 122 end 123 if not authpass then 124 ---@diagnostic disable-next-line: undefined-field 125 l:info("Post-connect auth failed ("..cSocket:getpeername().ip..")") 126 cSocket:close_reset() 127 sSocket:close_reset() 128 end 129 130 local c, k = GenCert((info and next(info.serverNames)) and info.serverNames or host) 131 if not (c and k) then 132 cSocket:close_reset() 133 sSocket:close_reset() 134 end 135 136 137 ---@type uv_tcp_t 138 local tSocket = ss(cSocket, { 139 ca = Cert, 140 cert = c:export(), -- I have zero clue on why this is needed 141 key = k:export(), -- But I do it because I apparently have to 142 server = true, 143 144 buffer = buf, 145 146 hostname = host, 147 host = host, 148 servername = host, 149 150 requestCert = request_cert, -- another reminder to do this 151 ciphers = X_CIPHERS 152 }) 153 154 if not tSocket then 155 l:error("Error when upgrading (usually client issue)") 156 print("OpenSSL error: ", require "openssl".error()) 157 return 158 end 159 160 uvproxy(tSocket, sSocket) 161end