123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171 |
- require "apache2"
- -- local redis = require "redis"
- local hiredis = require "hiredis"
- local regex = require "rex_pcre"
- local mime = require "mime"
- local cipher = require "openssl".cipher
- local pretty = require 'pl.pretty'
- -- --------------------------------------------------------------------------
- -- 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
- local uri = string.match(r.the_request, "^%w+%s+(.+)%s+HTTP")
- if ignore ~= nil and regex.match(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
- --
-
-
- local sucess = false
- local err = ""
-
- if redis_conn ~= nil then
- success, err = pcall(function() redis_conn:command("PING") end)
- if redis_conn == nil then
- r:info("redis_conn turned nil after ping")
- end
- end
- if success then
- r:info("redis ping was successful")
- 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
- r:info(string.format("connecting to redis %s:%s", redis_host, redis_port))
- success, err = pcall(function() redis_conn = hiredis.connect(redis_host, redis_port) end)
- if success then
- r:info("created redis connection to " .. redis_host .. ":" .. redis_port)
- 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
- if redis_conn == nil then
- r:info("redis is suddenly nil!")
- end
- local v = redis_conn:command("GET", "bl:" .. r.useragent_ip)
- -- if v == nil then
- -- r:info("v is nil!")
- -- end
- -- the X-Forwarded-For IP
- if v == nil and xff ~= "" then
- v = redis_conn:command("GET", "bl:" .. xff)
- end
- -- the X-Real-IP IP
- if v == nil and rip ~= "" then
- v = redis_conn:command("GET", "bl:" .. rip)
- end
- if tostring(v) ~= "" and tostring(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
|