Mercurial > prosody-modules
comparison mod_firewall/definitions.lib.lua @ 2520:c6fd8975704b
mod_firewall: Initial support for lists, in-memory and HTTP
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sun, 19 Feb 2017 21:10:26 +0000 |
parents | 5fe483b73fd2 |
children | 72cbec103709 |
comparison
equal
deleted
inserted
replaced
2519:d4bc434a60a4 | 2520:c6fd8975704b |
---|---|
2 -- Name arguments are unused here | 2 -- Name arguments are unused here |
3 -- luacheck: ignore 212 | 3 -- luacheck: ignore 212 |
4 | 4 |
5 local definition_handlers = {}; | 5 local definition_handlers = {}; |
6 | 6 |
7 local http = require "net.http"; | |
8 local timer = require "util.timer"; | |
7 local set = require"util.set"; | 9 local set = require"util.set"; |
8 local new_throttle = require "util.throttle".create; | 10 local new_throttle = require "util.throttle".create; |
9 | 11 |
10 local multirate_cache_size = module:get_option_number("firewall_multirate_cache_limit", 1000); | 12 local multirate_cache_size = module:get_option_number("firewall_multirate_cache_limit", 1000); |
11 | 13 |
55 } | 57 } |
56 end; | 58 end; |
57 }; | 59 }; |
58 end | 60 end |
59 | 61 |
62 local list_backends = { | |
63 memory = { | |
64 init = function (self, type, opts) | |
65 if opts.limit then | |
66 local have_cache_lib, cache_lib = pcall(require, "util.cache"); | |
67 if not have_cache_lib then | |
68 error("In-memory lists with a size limit require Prosody 0.10"); | |
69 end | |
70 self.cache = cache_lib.new((assert(tonumber(opts.limit), "Invalid list limit"))); | |
71 if not self.cache.table then | |
72 error("In-memory lists with a size limit require a newer version of Prosody 0.10"); | |
73 end | |
74 self.items = self.cache:table(); | |
75 else | |
76 self.items = {}; | |
77 end | |
78 end; | |
79 add = function (self, item) | |
80 self.items[item] = true; | |
81 end; | |
82 remove = function (self, item) | |
83 self.items[item] = nil; | |
84 end; | |
85 contains = function (self, item) | |
86 return self.items[item] == true; | |
87 end; | |
88 }; | |
89 http = { | |
90 init = function (self, url, opts) | |
91 local poll_interval = assert(tonumber(opts.ttl or "3600"), "invalid ttl for <"..url.."> (expected number of seconds)"); | |
92 local pattern = opts.pattern or "([^\r\n]+)\r?\n"; | |
93 assert(pcall(string.match, "", pattern), "invalid pattern for <"..url..">"); | |
94 if opts.hash then | |
95 assert(opts.hash:match("^%w+$") and type(hashes[opts.hash]) == "function", "invalid hash function: "..opts.hash); | |
96 self.hash_function = hashes[opts.hash]; | |
97 end | |
98 local etag; | |
99 local function update_list() | |
100 http.request(url, { | |
101 headers = { | |
102 ["If-None-Match"] = etag; | |
103 }; | |
104 }, function (body, code, response) | |
105 if code == 200 and body then | |
106 etag = response.headers.etag; | |
107 local items = {}; | |
108 for entry in body:gmatch(pattern) do | |
109 items[entry] = true; | |
110 end | |
111 self.items = items; | |
112 module:log("debug", "Fetched updated list from <%s>", url); | |
113 elseif code == 304 then | |
114 module:log("debug", "List at <%s> is unchanged", url); | |
115 else | |
116 module:log("warn", "Failed to fetch list from <%s>: %d %s", url, code, tostring(body)); | |
117 end | |
118 if poll_interval > 0 then | |
119 timer.add_task(poll_interval, update_list); | |
120 end | |
121 end); | |
122 end | |
123 update_list(); | |
124 timer.add_task(0, update_list); | |
125 end; | |
126 contains = function (self, item) | |
127 if self.hash_function then | |
128 item = self.hash_function(item); | |
129 end | |
130 return self.items and self.items[item] == true; | |
131 end; | |
132 }; | |
133 }; | |
134 | |
135 local function create_list(list_backend, list_def, opts) | |
136 if not list_backends[list_backend] then | |
137 error("Unknown list type '"..list_backend.."'", 0); | |
138 end | |
139 local list = setmetatable({}, { __index = list_backends[list_backend] }); | |
140 if list.init then | |
141 list:init(list_def, opts); | |
142 end | |
143 return list; | |
144 end | |
145 | |
146 --[[ | |
147 %LIST spammers: memory (source: /etc/spammers.txt) | |
148 | |
149 %LIST spammers: memory (source: /etc/spammers.txt) | |
150 | |
151 | |
152 %LIST spammers: http://example.com/blacklist.txt | |
153 ]] | |
154 | |
155 function definition_handlers.LIST(list_name, list_definition) | |
156 local list_backend = list_definition:match("^%w+"); | |
157 local opts = {}; | |
158 local opt_string = list_definition:match("^%S+%s+%((.+)%)"); | |
159 if opt_string then | |
160 for opt_k, opt_v in opt_string:gmatch("(%w+): ?([^,]+)") do | |
161 opts[opt_k] = opt_v; | |
162 end | |
163 end | |
164 return create_list(list_backend, list_definition:match("^%S+"), opts); | |
165 end | |
166 | |
60 return definition_handlers; | 167 return definition_handlers; |
61 |