123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- require "apache2"
- local redis = require "redis"
- local regex = require "rex_pcre"
- local mime = require "mime"
- local cipher = require "openssl.cipher"
- -- --------------------------------------------------------------------------
- -- try to connect to redis
- --
- local redis_conn = nil
- function _decrypt(message_and_iv, key)
- if message_and_iv:len() < 32 then
- return ""
- end
- iv, _ = message_and_iv:sub(1, 16)
- message, _ = message_and_iv:sub(17, -1)
- local c = cipher.new("aes-256-cbc")
- c:decrypt(key, iv)
- cleartext, err = c:final(message)
- if err ~= nil then
- return ""
- end
- return cleartext
- end
- function scw(r)
- local start_time = r:clock()
- local has_redis = false
- local ignore = os.getenv("SCW_IGNORE")
- if ignore == nil or ignore == "" then
- r:err("SCW_IGNORE is not set!")
- end
- if ignore ~= nil and regex.match(r.uri, ignore) then
- return apache2.DECLINED
- end
- -- --------------------------------------------------------------------------
- -- Does the user have an encrypted scw cookie that proves he is human?
- --
- local cookie_name = os.getenv("SCW_COOKIE")
- if cookie_name == nil or cookie_name == "" then
- r:err("SCW_COOKIE is not set!")
- end
- local cookie_key = r:base64_decode(os.getenv("SCW_KEY"))
- if cookie_key == nil or cookie_key == "" then
- r:err("SCW_KEY is not set!")
- end
- local human_cookie = r:getcookie(cookie_name)
- local xff = tostring(r.headers_in["X-Forwarded-For"])
- local rip = tostring(r.headers_in["X-Real-IP"])
- if human_cookie then
- human_cookie = r:base64_decode(r:unescape(human_cookie))
- end
- local is_human = false
- if human_cookie ~= nil and cookie_key:len() == 32 then
- local cookie_data = _decrypt(human_cookie, cookie_key)
- is_human = string.gsub(cookie_data, "scw|(.-)|(%d+)$", function (ip, exp)
- if (ip == r.useragent_ip or ip == xff or ip == rip) and r:clock() <= tonumber(exp) then
- return true
- end
- return false
- end)
- if is_human then
- return apache2.DECLINED
- end
- end
- -- --------------------------------------------------------------------------
- -- check for blacklist status
- --
- if pcall(function() redis_conn:ping() end) then
- has_redis = true
- else
- -- io.stderr:write("reconnecting to redis\n")
- local redis_host = os.getenv("SCW_REDIS_HOST")
- if redis_host == nil or redis_host == "" then
- r:err("SCW_REDIS_HOST is not set!")
- end
- local redis_port = os.getenv("SCW_REDIS_PORT")
- if redis_port == nil or redis_port == "" then
- r:err("SCW_REDIS_PORT is not set!")
- end
- if pcall(function() redis_conn = redis.connect(redis_host, 6379) end) then
- has_redis = true
- end
- end
- local captcha_url = os.getenv("SCW_CAPTCHA_URL")
- if captcha_url == nil or captcha_url == "" then
- r:err("SCW_CAPTCHA_URL is not set!")
- end
- if has_redis and captcha_url ~= "" then
- -- the client ip
- local v = redis_conn:get("bl:" .. r.useragent_ip)
- -- the X-Forwarded-For IP
- if v == nil then
- v = redis_conn:get("bl:" .. xff)
- end
- -- the X-Real-IP IP
- if v == nil then
- v = redis_conn:get("bl:" .. rip)
- end
- if v ~= nil then -- and h == nil then
- local rprotocol = "http"
- if r.is_https then
- rprotocol = "https"
- end
- local rport = ""
- if (r.is_https and r.port ~= 443) or (r.is_https ~= true and r.port ~= 80) then
- rport = string.format(":%d", r.port)
- end
- local referer = string.format("%s://%s%s%s", rprotocol, r.hostname, rport, r.unparsed_uri)
- r.headers_out["location"] = string.format(captcha_url, r.useragent_ip, r:escape(referer))
- --[[
- r.headers_in["X-SCW-IP"] = v
- r.handler = "proxy-server"
- r.proxyreq = apache2.PROXYREQ_REVERSE
- r.filename = string.format("proxy:http://captcha:8080/?src=%s&r=%s", r.useragent_ip, r.unparsed_uri)
- --]]
- return apache2.HTTP_MOVED_TEMPORARILY
- end
- end
- return apache2.DECLINED
- end
|