Skip to content
This repository was archived by the owner on Apr 14, 2025. It is now read-only.

Commit 92137ee

Browse files
authored
Merge pull request #19 from mozilla-services/ajvb/v0.1.6
v0.1.6
2 parents 8550b47 + e03fcba commit 92137ee

File tree

4 files changed

+40
-23
lines changed

4 files changed

+40
-23
lines changed

README.md

+7-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ init_by_lua_block {
3535
statsd_max_buffer_count = tonumber(os.getenv("STATSD_MAX_BUFFER_COUNT")) or 100,
3636
statsd_flush_timer = tonumber(os.getenv("STATSD_FLUSH_TIMER")) or 5,
3737
dont_block = tonumber(os.getenv("DONT_BLOCK")) or 0,
38+
verbose = tonumber(os.getenv("VERBOSE")) or 0,
3839
whitelist = {},
3940
})
4041
}
@@ -116,7 +117,11 @@ violations for your environment.
116117
-- statsd_max_buffer_count - Max number of metrics in buffer before metrics should be submitted
117118
-- to statsd (defaults to 100)
118119
-- statsd_flush_timer - Interval for attempting to flush the stats in seconds. (defaults to 5)
119-
-- dont_block - Enables (1) or disables (0) not blocking within nginx by returning a 403. (defaults to disabled)
120+
-- dont_block - Enables (1) or disables (0) not blocking within nginx by returning
121+
-- a 403. (defaults to disabled)
122+
-- verbose - Enables (1) or disables (0) verbose logging. Messages are logged with a
123+
-- severity of "ERROR" so that nginx log levels do not need to be changed. (defaults
124+
-- to disabled)
120125
-- whitelist - List of whitelisted IP's and IP CIDR's. (defaults to empty)
121126
--
122127
client = require("resty.iprepd").new({
@@ -132,6 +137,7 @@ client = require("resty.iprepd").new({
132137
statsd_max_buffer_count = 100,
133138
statsd_flush_timer = 10,
134139
dont_block = 0,
140+
verbose = 0,
135141
whitelist = {"127.0.0.1", "10.10.10.0/24", "192.168.0.0/16"}
136142
})
137143
```

dist.ini

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = iprepd-nginx
22
abstract = iprepd openresty module
33
author = AJ Bahnken (ajvb)
4-
version = 0.1.5
4+
version = 0.1.6
55
is_original = yes
66
license = mozilla2
77
lib_dir = lib

etc/conf.d/server.conf

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ init_by_lua_block {
1111
statsd_max_buffer_count = tonumber(os.getenv("STATSD_MAX_BUFFER_COUNT")) or 100,
1212
statsd_flush_timer = tonumber(os.getenv("STATSD_FLUSH_TIMER")) or 5,
1313
dont_block = tonumber(os.getenv("DONT_BLOCK")) or 0,
14+
verbose = tonumber(os.getenv("VERBOSE")) or 0,
1415
whitelist = {},
1516
})
1617
}

lib/resty/iprepd.lua

+31-21
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ function _M.new(options)
2626

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

3232
local statsd_client = nil
@@ -45,7 +45,7 @@ function _M.new(options)
4545
timeout = options.timeout or 10,
4646
threshold = iprepd_threshold,
4747
api_key_hdr = {
48-
['Authorization'] = 'APIKey ' .. iprepd_api_key,
48+
['Authorization'] = string.format('APIKey %s', iprepd_api_key),
4949
},
5050
cache = cache,
5151
cache_ttl = options.cache_ttl or 30,
@@ -56,23 +56,28 @@ function _M.new(options)
5656
statsd_max_buffer_count = options.statsd_max_buffer_count or 100,
5757
statsd_flush_timer = options.statsd_flush_timer or 5,
5858
dont_block = options.dont_block or 0,
59+
verbose = options.verbose or 0,
5960
whitelist = whitelist,
6061
}
6162

6263
return setmetatable(self, mt)
6364
end
6465

6566
function _M.check(self, ip)
67+
self:debug_log(string.format("Checking %s", ip))
6668
ngx.req.set_header('X-Foxsec-IP-Reputation-Below-Threshold', 'false')
6769
ngx.req.set_header('X-Foxsec-Block', 'false')
6870
if self.whitelist then
6971
if iputils.ip_in_cidrs(ip, self.whitelist) then
72+
self:debug_log(string.format("%s in whitelist", ip))
7073
return
7174
end
7275
end
7376

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

8489
if self.dont_block == 1 then
85-
ngx.log(ngx.ERR, ip .. ' is below threshold with a reputation of ' .. reputation)
90+
ngx.log(ngx.ERR, string.format("%s is below threshold with a reputation of %d", ip, reputation))
8691
else
87-
ngx.log(ngx.ERR, ip .. ' rejected with a reputation of ' .. reputation)
92+
ngx.log(ngx.ERR, string.format("%s rejected with a reputation of %d", ip, reputation))
8893
if self.statsd then
8994
self.statsd.incr("iprepd.status.rejected")
9095
end
9196
ngx.exit(ngx.HTTP_FORBIDDEN)
9297
end
93-
else
94-
if self.statsd then
95-
self.statsd.incr("iprepd.status.accepted")
96-
end
97-
end
9898

99-
return
99+
return
100+
end
100101
end
101102

103+
self:debug_log(string.format("%s accepted", ip))
102104
if self.statsd then
103105
self.statsd.incr("iprepd.status.accepted")
104106
end
@@ -110,40 +112,42 @@ function _M.get_reputation(self, ip)
110112
if not reputation then
111113
local httpc = http.new()
112114
httpc:set_timeout(self.timeout)
113-
local resp, err = httpc:request_uri(self.url .. '/' .. ip, {
115+
local resp, err = httpc:request_uri(string.format("%s/%s", self.url, ip), {
114116
method = "GET",
115117
headers = self.api_key_hdr,
116118
})
117119
if err then
118-
if self.statsd and err == "timeout" then
119-
self.statsd.incr("iprepd.err.timeout")
120+
if self.statsd then
121+
self.statsd.incr("iprepd.err." .. err)
120122
end
121-
ngx.log(ngx.ERR, 'Error with request to iprepd: ' .. err)
123+
ngx.log(ngx.ERR, string.format("Error with request to iprepd: %s", err))
122124
return nil
123125
end
124126

125127
-- If the IP was found
126128
if resp.status == 200 then
127129
reputation = cjson.decode(resp.body)['reputation']
128-
if reputation and reputation >= 0 and reputation <= 100 then
129-
self.cache:set(ip, reputation, self.cache_ttl)
130-
else
130+
if not reputation then
131131
ngx.log(ngx.ERR, 'Unable to parse `reputation` value from response body')
132132
end
133133
elseif resp.status == 404 then
134-
self.cache:set(ip, 100, self.cache_ttl)
134+
reputation = 100
135135
else
136-
ngx.log(ngx.ERR, 'iprepd responded with a ' .. resp.status .. ' http status code')
136+
ngx.log(ngx.ERR, string.format("iprepd responded with a %d http status code", resp.status))
137137
if self.statsd then
138138
self.statsd.incr("iprepd.err." .. resp.status)
139139
end
140140
if self.cache_errors == 1 then
141-
ngx.log(ngx.ERR, 'cache_errors is enabled, setting reputation of ' .. ip .. ' to 100 within the cache')
142-
self.cache:set(ip, 100, self.cache_ttl)
141+
reputation = 100
142+
self:debug_log(string.format("cache_errors is enabled, setting reputation of %s to 100 within the cache", ip))
143143
end
144144
end
145145
end
146146

147+
if reputation and reputation >= 0 and reputation <= 100 then
148+
self.cache:set(ip, reputation, self.cache_ttl)
149+
end
150+
147151
return reputation
148152
end
149153

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

170+
function _M.debug_log(self, msg)
171+
if self.verbose == 1 then
172+
ngx.log(ngx.ERR, string.format("[verbose] %s", msg))
173+
end
174+
end
175+
166176
return _M

0 commit comments

Comments
 (0)