Skip to content

Commit

Permalink
Merge pull request #19 from mozilla-services/ajvb/v0.1.6
Browse files Browse the repository at this point in the history
v0.1.6
  • Loading branch information
ajvb committed Dec 17, 2018
2 parents 8550b47 + e03fcba commit 92137ee
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 23 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ init_by_lua_block {
statsd_max_buffer_count = tonumber(os.getenv("STATSD_MAX_BUFFER_COUNT")) or 100,
statsd_flush_timer = tonumber(os.getenv("STATSD_FLUSH_TIMER")) or 5,
dont_block = tonumber(os.getenv("DONT_BLOCK")) or 0,
verbose = tonumber(os.getenv("VERBOSE")) or 0,
whitelist = {},
})
}
Expand Down Expand Up @@ -116,7 +117,11 @@ violations for your environment.
-- statsd_max_buffer_count - Max number of metrics in buffer before metrics should be submitted
-- to statsd (defaults to 100)
-- statsd_flush_timer - Interval for attempting to flush the stats in seconds. (defaults to 5)
-- dont_block - Enables (1) or disables (0) not blocking within nginx by returning a 403. (defaults to disabled)
-- dont_block - Enables (1) or disables (0) not blocking within nginx by returning
-- a 403. (defaults to disabled)
-- verbose - Enables (1) or disables (0) verbose logging. Messages are logged with a
-- severity of "ERROR" so that nginx log levels do not need to be changed. (defaults
-- to disabled)
-- whitelist - List of whitelisted IP's and IP CIDR's. (defaults to empty)
--
client = require("resty.iprepd").new({
Expand All @@ -132,6 +137,7 @@ client = require("resty.iprepd").new({
statsd_max_buffer_count = 100,
statsd_flush_timer = 10,
dont_block = 0,
verbose = 0,
whitelist = {"127.0.0.1", "10.10.10.0/24", "192.168.0.0/16"}
})
```
Expand Down
2 changes: 1 addition & 1 deletion dist.ini
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name = iprepd-nginx
abstract = iprepd openresty module
author = AJ Bahnken (ajvb)
version = 0.1.5
version = 0.1.6
is_original = yes
license = mozilla2
lib_dir = lib
Expand Down
1 change: 1 addition & 0 deletions etc/conf.d/server.conf
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ init_by_lua_block {
statsd_max_buffer_count = tonumber(os.getenv("STATSD_MAX_BUFFER_COUNT")) or 100,
statsd_flush_timer = tonumber(os.getenv("STATSD_FLUSH_TIMER")) or 5,
dont_block = tonumber(os.getenv("DONT_BLOCK")) or 0,
verbose = tonumber(os.getenv("VERBOSE")) or 0,
whitelist = {},
})
}
Expand Down
52 changes: 31 additions & 21 deletions lib/resty/iprepd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ function _M.new(options)

local cache, err = lrucache.new(cache_buffer_count)
if not cache then
fatal_error('failed to create the cache: ' .. (err or 'unknown'))
fatal_error(string.format('failed to create the cache: %s', (err or 'unknown')))
end

local statsd_client = nil
Expand All @@ -45,7 +45,7 @@ function _M.new(options)
timeout = options.timeout or 10,
threshold = iprepd_threshold,
api_key_hdr = {
['Authorization'] = 'APIKey ' .. iprepd_api_key,
['Authorization'] = string.format('APIKey %s', iprepd_api_key),
},
cache = cache,
cache_ttl = options.cache_ttl or 30,
Expand All @@ -56,23 +56,28 @@ function _M.new(options)
statsd_max_buffer_count = options.statsd_max_buffer_count or 100,
statsd_flush_timer = options.statsd_flush_timer or 5,
dont_block = options.dont_block or 0,
verbose = options.verbose or 0,
whitelist = whitelist,
}

return setmetatable(self, mt)
end

function _M.check(self, ip)
self:debug_log(string.format("Checking %s", ip))
ngx.req.set_header('X-Foxsec-IP-Reputation-Below-Threshold', 'false')
ngx.req.set_header('X-Foxsec-Block', 'false')
if self.whitelist then
if iputils.ip_in_cidrs(ip, self.whitelist) then
self:debug_log(string.format("%s in whitelist", ip))
return
end
end


local reputation = self:get_reputation(ip)
if reputation then
self:debug_log(string.format("Got reputation of %d for %s", reputation, ip))
ngx.req.set_header('X-Foxsec-IP-Reputation', tostring(reputation))
if reputation <= self.threshold then
ngx.req.set_header('X-Foxsec-IP-Reputation-Below-Threshold', 'true')
Expand All @@ -82,23 +87,20 @@ function _M.check(self, ip)
end

if self.dont_block == 1 then
ngx.log(ngx.ERR, ip .. ' is below threshold with a reputation of ' .. reputation)
ngx.log(ngx.ERR, string.format("%s is below threshold with a reputation of %d", ip, reputation))
else
ngx.log(ngx.ERR, ip .. ' rejected with a reputation of ' .. reputation)
ngx.log(ngx.ERR, string.format("%s rejected with a reputation of %d", ip, reputation))
if self.statsd then
self.statsd.incr("iprepd.status.rejected")
end
ngx.exit(ngx.HTTP_FORBIDDEN)
end
else
if self.statsd then
self.statsd.incr("iprepd.status.accepted")
end
end

return
return
end
end

self:debug_log(string.format("%s accepted", ip))
if self.statsd then
self.statsd.incr("iprepd.status.accepted")
end
Expand All @@ -110,40 +112,42 @@ function _M.get_reputation(self, ip)
if not reputation then
local httpc = http.new()
httpc:set_timeout(self.timeout)
local resp, err = httpc:request_uri(self.url .. '/' .. ip, {
local resp, err = httpc:request_uri(string.format("%s/%s", self.url, ip), {
method = "GET",
headers = self.api_key_hdr,
})
if err then
if self.statsd and err == "timeout" then
self.statsd.incr("iprepd.err.timeout")
if self.statsd then
self.statsd.incr("iprepd.err." .. err)
end
ngx.log(ngx.ERR, 'Error with request to iprepd: ' .. err)
ngx.log(ngx.ERR, string.format("Error with request to iprepd: %s", err))
return nil
end

-- If the IP was found
if resp.status == 200 then
reputation = cjson.decode(resp.body)['reputation']
if reputation and reputation >= 0 and reputation <= 100 then
self.cache:set(ip, reputation, self.cache_ttl)
else
if not reputation then
ngx.log(ngx.ERR, 'Unable to parse `reputation` value from response body')
end
elseif resp.status == 404 then
self.cache:set(ip, 100, self.cache_ttl)
reputation = 100
else
ngx.log(ngx.ERR, 'iprepd responded with a ' .. resp.status .. ' http status code')
ngx.log(ngx.ERR, string.format("iprepd responded with a %d http status code", resp.status))
if self.statsd then
self.statsd.incr("iprepd.err." .. resp.status)
end
if self.cache_errors == 1 then
ngx.log(ngx.ERR, 'cache_errors is enabled, setting reputation of ' .. ip .. ' to 100 within the cache')
self.cache:set(ip, 100, self.cache_ttl)
reputation = 100
self:debug_log(string.format("cache_errors is enabled, setting reputation of %s to 100 within the cache", ip))
end
end
end

if reputation and reputation >= 0 and reputation <= 100 then
self.cache:set(ip, reputation, self.cache_ttl)
end

return reputation
end

Expand All @@ -163,4 +167,10 @@ function _M.config_flush_timer(self)
ngx.timer.every(self.statsd_flush_timer, self.async_flush_stats, self)
end

function _M.debug_log(self, msg)
if self.verbose == 1 then
ngx.log(ngx.ERR, string.format("[verbose] %s", msg))
end
end

return _M

0 comments on commit 92137ee

Please sign in to comment.