LoginSignup
4
4

More than 5 years have passed since last update.

lua-nginx-module で forward proxy

Posted at

https の GET リクエストを、Nginx からの転送時に forward proxy サーバを通して送信してみました。
(チャンク形式には対応させてません)

はじめに、ngx.socket.tcp() を使用して、CONNECT メソッドを foward proxy サーバに送信して、トンネルを確立してから、
sock:sslhandshake() で SSL 接続を開始して、リクエストを送信し、受信した応答をクライアントに送っています。

local host = ngx.var.dest_host
local port = tonumber(ngx.var.dest_port)
local proxy_host = ngx.var.proxy_host
local proxy_port = tonumber(ngx.var.proxy_port)


local sock = ngx.socket.tcp()
sock:settimeout(1000)
local ok, err = sock:connect(proxy_host, proxy_port)

local uri = string.format('CONNECT %s:%s HTTP/1.1', host, port)
local header = string.format('Host: %s:%s', host, port)
local request = table.concat({uri, header}, '\r\n') .. '\r\n\r\n'
local bytes, err = sock:send(request)
local data, err, partial = sock:receive('*l')
if err then
    ngx.log(ngx.DEBUG, err)
    ngx.exit(ngx.HTTP_BAD_REQUEST)
end

local m, err = ngx.re.match(data, '^HTTP/1\\.(0|1) 2\\d{2}\\s.+')
if err then
    ngx.log(ngx.DEBUG, err)
    ngx.exit(ngx.HTTP_BAD_REQUEST)
end


local session, err = sock:sslhandshake()
local method = ngx.req.get_method()
local uri = string.format('%s %s HTTP/1.1', method, ngx.var.uri)
local header = string.format('Host: %s:%s', host, port)
local request = table.concat({uri, header}, '\r\n') .. '\r\n\r\n'
local bytes, err = sock:send(request)
local iter = sock:receiveuntil('\r\n\r\n')

local data, err, partial = iter()
if err then
    ngx.log(ngx.DEBUG, err)
end


local header, n, err = string.gsub(data, '^\r\n', '')
local m, err = ngx.re.match(header, 'Content-Length:\\s(.+)', 'i')
if err then
    local ok, err = sock:close()
    if err then
        ngx.exit(ngx.HTTP_BAD_REQUEST)
    end
    ngx.exit(ngx.HTTP_BAD_REQUEST)
end

if not m[1] then
    ngx.exit(ngx.HTTP_BAD_REQUEST)
end

local length = tonumber(m[1])
local body, err, partial = sock:receive(length)
if err then
    local ok, err = sock:close()
    if err then
        ngx.exit(ngx.HTTP_BAD_REQUEST)
    end
    ngx.exit(ngx.HTTP_BAD_REQUEST)
end

local ok, err = sock:close()
if err then
    ngx.exit(ngx.HTTP_BAD_REQUEST)
end

local iter, err = ngx.re.gmatch(header, '(.+):\\s*(.+)')
while true do
    local m, err = iter()
    if err then
        ngx.exit(ngx.HTTP_BAD_REQUEST)
    end

    if m then
        if m[1] then
            local from, to, err = ngx.re.find(m[1], 'content-length', 'i')
            if err then
                ngx.exit(ngx.HTTP_BAD_REQUEST)
            end

            if not from then
                ngx.header[m[1]] = m[2]
            end
        end
    else
        break
    end
end

ngx.print(body)
ngx.exit(ngx.HTTP_OK)
4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4