Verified Commit 0c60a0ac authored by Jonathan Coetzee's avatar Jonathan Coetzee Committed by Vladimír Čunát

modules/policy RPZ: auto-reloading function

vcunat squashed this, rebased, etc.
parent c3d7c487
......@@ -34,6 +34,7 @@ Depends:
libkres9 (= ${binary:Version}),
......@@ -59,6 +59,7 @@ BuildRequires: pkgconfig(lmdb)
BuildRequires: python3-sphinx
Requires: lua-socket-compat
Requires: lua-sec-compat
Requires: lua-cqueues
Requires(pre): shadow-utils
%if 0%{?suse_version}
......@@ -227,10 +227,11 @@ Most properties (actions, filters) are described above.
Like suffix match, but you can also provide a common suffix of all matches for faster processing (nil otherwise).
This function is faster for small suffix tables (in the order of "hundreds").
.. function:: policy.rpz(action, path)
.. function:: policy.rpz(action, path, watch)
:param action: the default action for match in the zone; typically you want ``policy.DENY``
:param path: path to zone file | database
:param watch: boolean, if true the file will be reparsed and the ruleset reloaded on file change
Enforce RPZ_ rules. This can be used in conjunction with published blocklist feeds.
The RPZ_ operation is well described in this `Jan-Piet Mens's post`_,
......@@ -453,14 +453,52 @@ local function rpz_parse(action, path)
print(string.format('[ rpz ] %s:%d: unsupported policy action', path, tonumber(parser.line_counter)))
return rules
local function get_dir_and_file(path)
local dir, file = string.match(path, "(.*)/([^/]+)")
-- If regex doesn't match then path must be the file directly (i.e. doesn't contain '/')
-- This assumes that the file exists (rpz_parse() would fail if it doesn't)
if not dir and not file then
dir = '.'
file = path
return dir, file
-- RPZ policy set
-- Create RPZ from zone file
function policy.rpz(action, path)
-- Create RPZ from zone file and optionally watch the file for changes
function policy.rpz(action, path, watch)
local rules = rpz_parse(action, path)
if watch then
local has_notify, notify = pcall(require, 'cqueues.notify')
if has_notify then
local bit = require('bit')
local dir, file = get_dir_and_file(path)
local watcher = notify.opendir(dir)
watcher:add(file, bit.bxor(notify.CREATE, notify.MODIFY))
worker.coroutine(function ()
for _, name in watcher:changes() do
-- Limit to changes on file we're interested in
-- Watcher will also fire for changes to the directory itself
if name == file then
-- If the file changes then reparse and replace the existing ruleset
rules = rpz_parse(action, path)
log('[poli] lua-cqueues required to watch and reload RPZ file, continuing without watching')
return function(_, query)
local label = query:name()
local rule = rules[label]
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment