# HG changeset patch # User Matthew Wild # Date 1487716918 0 # Node ID 9b46d24edf0d3a9e28e0e9ba2771b6cdf62b0cab # Parent 223eea31588d49c45e77d07ae9b34caff654c539 mod_firewall: Add and document COUNT condition diff -r 223eea31588d -r 9b46d24edf0d mod_firewall/README.markdown --- a/mod_firewall/README.markdown Tue Feb 21 22:41:40 2017 +0000 +++ b/mod_firewall/README.markdown Tue Feb 21 22:41:58 2017 +0000 @@ -157,6 +157,21 @@ SCAN: body for word in badwords BOUNCE=policy-violation (This word is not allowed!) +#### COUNT + +COUNT is similar to SCAN, in that it uses a defined SEARCH and breaks it up according to a PATTERN. Then it +counts the number of results. + +For example, to block every message with more than one URL: + + # Define a search location called 'body' which fetches the text of the 'body' element + %SEARCH body: body# + # Define a pattern called 'url' which matches HTTP links + %PATTERN url: https?://%S+ + + COUNT: url in body > 1 + BOUNCE=policy-violation (Up to one HTTP URL is allowed in messages) + ### Stanza matching Condition Matches diff -r 223eea31588d -r 9b46d24edf0d mod_firewall/conditions.lib.lua --- a/mod_firewall/conditions.lib.lua Tue Feb 21 22:41:40 2017 +0000 +++ b/mod_firewall/conditions.lib.lua Tue Feb 21 22:41:58 2017 +0000 @@ -279,4 +279,23 @@ return ("scan_list(list_%s, %s)"):format(list_name, "tokens_"..search_name.."_"..pattern_name), { "scan_list", "tokens:"..search_name.."_"..pattern_name, "list:"..list_name }; end +local valid_comp_ops = { [">"] = ">", ["<"] = "<", ["="] = "==", ["=="] = "==", ["<="] = "<=", [">="] = ">=" }; +function condition_handlers.COUNT(count_expression) + local pattern_name, search_name, comparator_expression = count_expression:match("(%S+) in (%S+) (.+)$"); + if not (pattern_name) then + error("Error parsing COUNT expression, syntax: PATTERN in SEARCH COMPARATOR"); + end + local value; + comparator_expression = comparator_expression:gsub("%d+", function (value_string) + value = tonumber(value_string); + return ""; + end); + if not value then + error("Error parsing COUNT expression, expected value"); + end + local comp_op = comparator_expression:gsub("%s+", ""); + assert(valid_comp_ops[comp_op], "Error parsing COUNT expression, unknown comparison operator: "..comp_op); + return ("it_count(search_%s:gmatch(pattern_%s)) %s %d"):format(search_name, pattern_name, comp_op, value), { "it_count", "search:"..search_name, "pattern:"..pattern_name }; +end + return condition_handlers;