access_by_lua_block { -- get client IP local ip = ngx.var.remote_addr -- check if IP is in cache local cached = ngx.shared.dnsblcache:get(ip) if cached ~= nil then if cached == "ok" then ngx.exit(ngx.OK) else ngx.exit(ngx.HTTP_FORBIDDEN) end end -- get the reverse DNS local rdns = "" local both = false local resolver = require "resty.dns.resolver" local resolvers = {%DNSBL_RESOLVERS%} local r, err = resolver:new{nameservers=resolvers, retrans=2, timeout=2000} if not r then ngx.exit(ngx.OK) end local answers, err = r:reverse_query(ip) if not answers.errcode then for ak, av in ipairs(answers) do if av.ptrdname then rdns = av.ptrdname break end end end if rdns ~= "" then local answers, err, tries = r:query(rdns, nil, {}) for ak, av in ipairs(answers) do if av.address and av.address == ip then both = true break end end end -- check if it's a legitimate SE crawler local ips = {"23.21.227.69", "40.88.21.235", "50.16.241.113", "50.16.241.114", "50.16.241.117", "50.16.247.234", "52.204.97.54", "52.5.190.19", "54.197.234.188", "54.208.100.253", "54.208.102.37", "107.21.1.8"} local domains = {".googlebot.com", ".google.com", ".search.msn.com", ".crawl.yahoot.net", ".crawl.baidu.jp", ".crawl.baidu.com", ".yandex.com", ".yandex.ru", ".yandex.net"} for k, v in pairs(ips) do if v == ip then ngx.shared.dnsblcache:set(ip, "ok", 86400) ngx.exit(ngx.OK) end end if both and rdns ~= "" then for k, v in pairs(domains) do if rdns:sub(-#v) == v then ngx.shared.dnsblcache:set(ip, "ok", 86400) ngx.exit(ngx.OK) end end end -- dnsbl check local dnsbls = {%DNSBL_LIST%} for k, v in pairs(dnsbls) do local name = resolver.arpa_str(ip) name = name:gsub("%.in%-addr%.arpa", ""):gsub("%.ip6%.arpa", "") .. "." .. v local answers, err, tries = r:query(name, nil, {}) if not answers.errcode then for ak, av in ipairs(answers) do if av.address then a,b,c,d = av.address:match("([%d]+).([%d]+).([%d]+).([%d]+)") if a == "127" then ngx.shared.dnsblcache:set(ip, "dnsbl", 86400) ngx.exit(ngx.HTTP_FORBIDDEN) end end end end end -- legitimate user ngx.shared.dnsblcache:set(ip, "ok", 86400) ngx.exit(ngx.OK) }