LUA Scripts

Tips

Most defense logic and execution order in this project are encapsulated in LUA scripts.

Basic Structure

function should_block()
    local req = request
    local client_ip = req.client_ip or ""
    local site_id = req.site_id or 0

    if client_ip == "" then
        return 0
    end

    if is_ip_blacklisted(client_ip, site_id) then
        log("Blocked by IP blacklist: " .. client_ip .. " (site_id=" .. tostring(site_id) .. ")")
        return 1
    end
    return 0
end

Tips

As shown above, the script must be a function and must return one of: 0, 1, or -1.

Return ValueMeaning
0Do not block, continue with later scripts
1Block the request
-1Do not block, and skip all later scripts

Global Objects

To simplify defense customization, several global objects are injected into LUA scripts.

request: request context

This object contains request context with the following fields:

FieldDefaultDescription
methodHTTP method
uriRequest URI
headersRequest headers
bodyRequest body. Large bodies may be truncated for performance
client_ipSource IP selection: 1) if trusted_source is configured and request is from a trusted source, IP is selected from X-Real-IP -> X-Forwarded-For (first) -> peer_ip; 2) if trusted_source is not configured, use direct peer IP (which could be upstream nginx)
timestampRequest timestamp
site_idTarget site ID

log: logging helper

For debugging, scripts can print logs directly:

log("Blocked by IP blacklist: " .. client_ip .. " (site_id=" .. tostring(site_id) .. ")")

Built-in defense helpers

The script runtime provides several built-in helper methods.

is_verified_crawler: crawler verification

function should_block()
    local req = request
    local user_agent = req.headers["user-agent"] or req.headers["User-Agent"] or ""
    if user_agent == "" then return 1 end

    local client_ip = req.client_ip or ""
    local exempts = {"MicroMessenger", "DingTalk"}
    local value = is_verified_crawler(client_ip, user_agent, nil, 0)  -- do not blacklist, block directly
    -- log("is_verified_crawler returned: " .. tostring(value))
    return value
end
Parameters of is_verified_crawler
NameTypeDefaultDescription
client_ipstringRequest IP
user_agentstringRequest UA
exemptslist of UA stringsExempt from blacklisting. If fake crawler is detected, only reject request without blacklisting IP
block_durationnumberBlacklist duration in minutes when fake crawler is detected

is_ip_blacklisted: blacklist check

function should_block()
    local req = request
    local client_ip = req.client_ip or ""
    local site_id = req.site_id or 0

    if client_ip == "" then
        return 0
    end

    if is_ip_blacklisted(client_ip, site_id) then
        log("Blocked by IP blacklist: " .. client_ip .. " (site_id=" .. tostring(site_id) .. ")")
        return 1
    end
    return 0
end

is_ip_whitelisted: whitelist check

function should_block()
    local req = request
    local client_ip = req.client_ip or ""
    local site_id = req.site_id or 0

    if client_ip == "" then
        return 0
    end

    if is_ip_whitelisted(client_ip, site_id) then
        log("Allowed by IP whitelist: " .. client_ip .. " (site_id=" .. tostring(site_id) .. ")")
        return -1  -- skip all later scripts
    end
    return 0
end

is_rate_limited: request rate limit check

function should_block()
    local req = request
    local ip = req.client_ip or "unknown"
    local site = req.site_id or 0

    -- If CC limited, block immediately
    if is_rate_limited(ip, site) then
        log("CC rate limited: " .. ip .. " @site " .. tostring(site))
        return 1
    end

    return 0
end
Last Updated::
Contributors: Pcloth