comparison mod_firewall/mod_firewall.lua @ 6538:de1f17ed4dac

mod_firewall: Add support for tracing rule evaluation in real-time
author Matthew Wild <mwild1@gmail.com>
date Mon, 11 May 2026 13:37:19 +0100
parents 9bc83fba89ac
children 430584888704
comparison
equal deleted inserted replaced
6537:9bc83fba89ac 6538:de1f17ed4dac
326 new_long_id = { 326 new_long_id = {
327 global_code = [[local new_long_id = require "util.id".long;]]; 327 global_code = [[local new_long_id = require "util.id".long;]];
328 }; 328 };
329 329
330 trace = { 330 trace = {
331 global_code = [[local trace_init = module:require("trace").init;]]; 331 global_code = [[local trace_init = module.environment.trace.init;]];
332 }; 332 };
333 }; 333 };
334 334
335 local function include_dep(dependency, code) 335 local function include_dep(dependency, code)
336 local dep, dep_param = dependency:match("^([^:]+):?(.*)$"); 336 local dep, dep_param = dependency:match("^([^:]+):?(.*)$");
379 end 379 end
380 380
381 local definition_handlers = module:require("definitions"); 381 local definition_handlers = module:require("definitions");
382 local condition_handlers = module:require("conditions"); 382 local condition_handlers = module:require("conditions");
383 local action_handlers = module:require("actions"); 383 local action_handlers = module:require("actions");
384
385 module.environment.trace = module:require("trace");
386
387 local metadata_field_handlers = {
388 trace = function (v)
389 v = v:lower();
390 return v == "on" or v == "true";
391 end;
392 };
384 393
385 if module:get_option_boolean("firewall_experimental_user_marks", true) then 394 if module:get_option_boolean("firewall_experimental_user_marks", true) then
386 module:require"marks"; 395 module:require"marks";
387 end 396 end
388 397
447 ruleset[chain] = ruleset[chain] or {}; 456 ruleset[chain] = ruleset[chain] or {};
448 elseif not(state) and line:sub(1, 2) == "@@" then 457 elseif not(state) and line:sub(1, 2) == "@@" then
449 local k, v = line:match("^@@%s*([^%s=]+)%s*=%s*(.+)$"); 458 local k, v = line:match("^@@%s*([^%s=]+)%s*=%s*(.+)$");
450 if not k then 459 if not k then
451 return nil, errmsg("Unable to parse metadata assignment (expected '@@ key = value')"); 460 return nil, errmsg("Unable to parse metadata assignment (expected '@@ key = value')");
461 end
462 local handler = metadata_field_handlers[k];
463 if handler then
464 v = handler(v);
452 end 465 end
453 metadata[k] = v; 466 metadata[k] = v;
454 elseif not(state) and line:sub(1,1) == "%" then -- Definition (zone, limit, etc.) 467 elseif not(state) and line:sub(1,1) == "%" then -- Definition (zone, limit, etc.)
455 local what, name = line:match("^%%%s*([%w_]+) +([^ :]+)"); 468 local what, name = line:match("^%%%s*([%w_]+) +([^ :]+)");
456 if not definition_handlers[what] then 469 if not definition_handlers[what] then
564 end 577 end
565 end 578 end
566 579
567 if metadata.trace then 580 if metadata.trace then
568 include_dep("trace", code); 581 include_dep("trace", code);
569 table.insert(code, ("local trace = trace_init(%q, %q);"):format(metadata.filename, chain_name)) 582 table.insert(code, ("local trace_record <close>, trace = trace_init(%q, %q, stanza, event.firewall_trace_tag, source_rules);"):format(metadata.filename, chain_name))
570 end 583 end
571 584
572 local condition_cache, n_conditions = {}, 0; 585 local condition_cache, n_conditions = {}, 0;
573 for rule_n, rule in ipairs(rules) do 586 for rule_n, rule in ipairs(rules) do
574 for _, dep in ipairs(rule.deps) do 587 for _, dep in ipairs(rule.deps) do
609 622
610 rule_code = "if "..table.concat(rule.conditions, " and ").." then\n\t\t\t" 623 rule_code = "if "..table.concat(rule.conditions, " and ").." then\n\t\t\t"
611 ..table.concat(rule.actions, "\n\t\t\t") 624 ..table.concat(rule.actions, "\n\t\t\t")
612 .."\n\t\tend\n"; 625 .."\n\t\tend\n";
613 else 626 else
627 if metadata.trace then
628 table.insert(rule.actions, 2, ("trace(%d, nil, true)"):format(rule_n));
629 end
614 rule_code = table.concat(rule.actions, "\n\t\t"); 630 rule_code = table.concat(rule.actions, "\n\t\t");
615 end 631 end
616 table.insert(code, rule_code); 632 table.insert(code, rule_code);
617 end 633 end
618 634
674 -- [filename] = { last_modified = ..., events_hooked = { [name] = handler } } 690 -- [filename] = { last_modified = ..., events_hooked = { [name] = handler } }
675 local loaded_scripts = {}; 691 local loaded_scripts = {};
676 692
677 function load_script(script) 693 function load_script(script)
678 script = resolve_script_path(script); 694 script = resolve_script_path(script);
695 local base_name = script:match("[^/]+$");
696
679 local last_modified = (lfs.attributes(script) or {}).modification or os.time(); 697 local last_modified = (lfs.attributes(script) or {}).modification or os.time();
680 if loaded_scripts[script] then 698 if loaded_scripts[script] then
681 if loaded_scripts[script].last_modified == last_modified then 699 if loaded_scripts[script].last_modified == last_modified then
682 return; -- Already loaded, and source file hasn't changed 700 return; -- Already loaded, and source file hasn't changed
683 end 701 end