wonderbeyond
2/10/2017 - 9:07 AM

Access controll based on IP address

Access controll based on IP address

-- Access controll based on IP address

local iputils = require("resty.iputils")
local ip_groups = require('lib.ip_groups')

function get_real_ip()
    if not ngx.var.http_x_forwarded_for then
        -- return ngx.null;
        return ngx.var.remote_addr
    end
    local m = ngx.re.match(ngx.var.http_x_forwarded_for, [=[[\d\.]+]=])
    return m and m[0]
end

function match_group(remote_grp, client_grp)
    -- Returns:
    --     true: matched
    --     false: not matched or no need to match

    local matched_r, matched_c

    if ngx.ctx._ip_access_ctrl_has_matched_rule then
        return false
    end

    -- evaluate matched_r
    local remote_list = ip_groups:get_parsed(remote_grp)
    matched_r = iputils.ip_in_cidrs(ngx.var.remote_addr, remote_list)

    -- Judge directly if no client_grp provided
    if not client_grp then
        if matched_r then
            ngx.ctx._ip_access_ctrl_has_matched_rule = true
            return true
        else
            return false
        end
    end

    local real_ip = get_real_ip()
    local client_list = ip_groups:get_parsed(client_grp)
    matched_c = iputils.ip_in_cidrs(real_ip, client_list)
    if matched_r and matched_c then
        ngx.ctx._ip_access_ctrl_has_matched_rule = true
        return true
    else
        return false
    end
end


local exports = {
    allow_group = function(remote_grp, client_grp)
        -- remote_grp and client_grp must all match!
        if not ngx.ctx._ip_access_ctrl_has_matched_rule then
            ngx.log(ngx.INFO, string.format('Try matching %s/%s for allow', remote_grp or '--', client_grp or '--'))
        end

        local matched = match_group(remote_grp, client_grp)

        if matched then
            ngx.log(ngx.INFO, 'Allowed directly')
        end
    end,

    deny_group = function(remote_grp, client_grp)
        if not ngx.ctx._ip_access_ctrl_has_matched_rule then
            ngx.log(ngx.INFO, string.format('Try matching %s/%s for deny', remote_grp or '--', client_grp or '--'))
        end

        local matched = match_group(remote_grp, client_grp)

        if matched then
            ngx.log(ngx.ERR, 'Denied')
            ngx.exit(ngx.HTTP_FORBIDDEN)
        end
    end
}

return exports