changeset 6536:24c34968dd45

mod_firewall: Preserve original source of actions/conditions for debug purposes
author Matthew Wild <mwild1@gmail.com>
date Mon, 11 May 2026 13:18:25 +0100
parents 82b6a03b9dfa
children 9bc83fba89ac
files mod_firewall/mod_firewall.lua
diffstat 1 files changed, 21 insertions(+), 14 deletions(-) [+]
line wrap: on
line diff
--- a/mod_firewall/mod_firewall.lua	Mon May 11 13:16:18 2026 +0100
+++ b/mod_firewall/mod_firewall.lua	Mon May 11 13:18:25 2026 +0100
@@ -388,7 +388,7 @@
 
 local function new_rule(ruleset, chain, line_no)
 	assert(chain, "no chain specified");
-	local rule = { conditions = {}, actions = {}, deps = {}, line_no = line_no };
+	local rule = { conditions = {}, actions = {}, deps = {}, line_no = line_no, source = { conditions = {}, actions = {} } };
 	table.insert(ruleset[chain], rule);
 	return rule;
 end
@@ -500,6 +500,7 @@
 				return nil, errmsg(action_string);
 			end
 			table.insert(rule.actions, action_string);
+			table.insert(rule.source.actions, line);
 			for _, dep in ipairs(action_deps or {}) do
 				table.insert(rule.deps, dep);
 			end
@@ -515,7 +516,9 @@
 			end
 			-- Check standard modifiers for the condition (e.g. NOT)
 			local negated;
-			local condition = line:match("^[^:=%.?]*");
+			local raw_condition = line:match("^[^:=%.?]*");
+			local condition = raw_condition;
+
 			if condition:find("%f[%w]NOT%f[^%w]") then
 				local s, e = condition:match("%f[%w]()NOT()%f[^%w]");
 				condition = (condition:sub(1,s-1)..condition:sub(e+1, -1)):match("^%s*(.-)%s*$");
@@ -532,6 +535,7 @@
 			end
 			if negated then condition_code = "not("..condition_code..")"; end
 			table.insert(rule.conditions, condition_code);
+			table.insert(rule.source.conditions, line);
 			for _, dep in ipairs(condition_deps or {}) do
 				table.insert(rule.deps, dep);
 			end
@@ -616,7 +620,8 @@
 			table.insert(code.global_header, 1, "local "..name:lower().."s = definitions."..name..";");
 		end
 
-		local code_string = "return function (definitions, fire_event, log, module, pass_return)\n\t"
+		-- The function signature here must match what gets passed in compile_handler()
+		local code_string = "return function (definitions, fire_event, log, module, pass_return, source_rules)\n\t"
 			..table.concat(code.global_header, "\n\t")
 			.."\n\tlocal db = require 'util.debug';\n\n\t"
 			.."return function (event)\n\t\t"
@@ -624,7 +629,7 @@
 			..table.concat(code, "")
 			.."\n\tend;\nend";
 
-		chain_handlers[chain_name] = code_string;
+		chain_handlers[chain_name] = { code = code_string, rules = rules };
 	end
 
 	return chain_handlers;
@@ -639,7 +644,7 @@
 
 -- Compile handler code into a factory that produces a valid event handler. Factory accepts
 -- a value to be returned on PASS
-local function compile_handler(code_string, filename)
+local function compile_handler(code_string, filename, source_rules)
 	-- Prepare event handler function
 	local chunk, err = envload(code_string, "="..filename, _G);
 	if not chunk then
@@ -653,7 +658,7 @@
 		return nil, "Error initializing compiled rules: "..initialized_chunk;
 	end
 	return function (pass_return)
-		return initialized_chunk(active_definitions, fire_event, logger(filename), module, pass_return); -- Returns event handler with upvalues
+		return initialized_chunk(active_definitions, fire_event, logger(filename), module, pass_return, source_rules); -- Returns event handler with upvalues
 	end
 end
 
@@ -693,8 +698,9 @@
 	-- Loop through the chains in the script, and for each chain attach the compiled code to the
 	-- relevant events, keeping track in events_hooked so we can cleanly unload later
 	local events_hooked = {};
-	for chain, handler_code in pairs(chain_functions) do
-		local new_handler, err = compile_handler(handler_code, "mod_firewall::"..chain);
+	for chain, chain_info in pairs(chain_functions) do
+		local handler_code = chain_info.code;
+		local new_handler, err = compile_handler(handler_code, "mod_firewall:"..base_name.."::"..chain, chain_info.rules);
 		if not new_handler then
 			module:log("error", "Compilation error for %s: %s", script, err);
 			errs = true;
@@ -823,10 +829,11 @@
 			print();
 		end
 		local c = 0;
-		for chain, handler_code in pairs(chain_functions) do
+		for chain_name, chain_info in pairs(chain_functions) do
+			local handler_code = chain_info.code;
 			c = c + 1;
-			print("---- Chain "..chain:gsub("_", " "));
-			local chain_func_name = "chain_"..tostring(c).."_"..chain:gsub("%p", "_");
+			print("---- Chain "..chain_name:gsub("_", " "));
+			local chain_func_name = "chain_"..tostring(c).."_"..chain_name:gsub("%p", "_");
 			if not verbose then
 				print(("%s = %s;"):format(chain_func_name, handler_code:sub(8)));
 			else
@@ -834,16 +841,16 @@
 				print(("local %s = (%s)(active_definitions, fire_event, logger(%q));"):format(chain_func_name, handler_code:sub(8), filename));
 				print();
 
-				local chain_definition = chains[chain];
+				local chain_definition = chains[chain_name];
 				if chain_definition and chain_definition.type == "event" then
 					for _, event_name in ipairs(chain_definition) do
 						print(("module:hook(%q, %s, %d);"):format(event_name, chain_func_name, chain_definition.priority or 0));
 					end
 				end
-				print(("module:hook(%q, %s, %d);"):format("firewall/chains/"..chain, chain_func_name, chain_definition.priority or 0));
+				print(("module:hook(%q, %s, %d);"):format("firewall/chains/"..chain_name, chain_func_name, chain_definition.priority or 0));
 			end
 
-			print("---- End of chain "..chain);
+			print("---- End of chain "..chain_name);
 			print();
 		end
 		print("end -- End of file "..filename);