local ngx_re_split = require("ngx.re").split local original_randomseed = math.randomseed local string_format = string.format local ngx_redirect = ngx.redirect local _M = {} local seeds = {} -- general Nginx configuration passed by controller to be used in this module local config local function get_seed_from_urandom() local seed local frandom, err = io.open("/dev/urandom", "rb") if not frandom then ngx.log(ngx.WARN, 'failed to open /dev/urandom: ', err) return nil end local str = frandom:read(4) frandom:close() if not str then ngx.log(ngx.WARN, 'failed to read data from /dev/urandom') return nil end seed = 0 for i = 1, 4 do seed = 256 * seed + str:byte(i) end return seed end math.randomseed = function(seed) local pid = ngx.worker.pid() if seeds[pid] then ngx.log(ngx.WARN, string.format("ignoring math.randomseed(%d) since PRNG is already seeded for worker %d", seed, pid)) return end original_randomseed(seed) seeds[pid] = seed end local function randomseed() local seed = get_seed_from_urandom() if not seed then ngx.log(ngx.WARN, 'failed to get seed from urandom') seed = ngx.now() * 1000 + ngx.worker.pid() end math.randomseed(seed) end local function redirect_to_https() return ngx.var.pass_access_scheme == "http" and (ngx.var.scheme == "http" or ngx.var.scheme == "https") end local function redirect_host() local host_port, err = ngx_re_split(ngx.var.best_http_host, ":") if err then ngx.log(ngx.ERR, "could not parse variable: ", err) return ngx.var.best_http_host; end return host_port[1]; end function _M.init_worker() randomseed() end function _M.set_config(new_config) config = new_config end -- rewrite gets called in every location context. -- This is where we do variable assignments to be used in subsequent -- phases or redirection function _M.rewrite(location_config) ngx.var.pass_access_scheme = ngx.var.scheme ngx.var.pass_server_port = ngx.var.server_port ngx.var.best_http_host = ngx.var.http_host or ngx.var.host if config.use_forwarded_headers then -- trust http_x_forwarded_proto headers correctly indicate ssl offloading if ngx.var.http_x_forwarded_proto then ngx.var.pass_access_scheme = ngx.var.http_x_forwarded_proto end if ngx.var.http_x_forwarded_port then ngx.var.pass_server_port = ngx.var.http_x_forwarded_port end -- Obtain best http host if ngx.var.http_x_forwarded_host then -- TODO(elvinefendi) https://github.com/kubernetes/ingress-nginx/issues/3790 can -- be fixed here by splitting the value of ngx.var.http_x_forwarded_host by ',' -- and taking the first portion ngx.var.best_http_host = ngx.var.http_x_forwarded_host end end ngx.var.pass_port = ngx.var.pass_server_port if config.is_ssl_passthrough_enabled then if ngx.var.pass_server_port == config.listen_ports.ssl_proxy then ngx.var.pass_port = 443 end elseif ngx.var.pass_server_port == config.listen_ports.https then ngx.var.pass_port = 443 end if location_config.force_ssl_redirect and redirect_to_https() then local uri = string_format("https://%s%s", redirect_host(), ngx.var.request_uri) if location_config.use_port_in_redirects then uri = string_format("https://%s:%s%s", redirect_host(), config.listen_ports.https, ngx.var.request_uri) end ngx_redirect(uri, config.http_redirect_code) end end return _M