comparison mod_firewall/mod_firewall.lua @ 5920:254a21a104aa

mod_server_contact_info: Backport from prosody trunk
author Matthew Wild <mwild1@gmail.com>
date Fri, 07 Jun 2024 16:14:58 +0100
parents 1d1eadff331d
children
comparison
equal deleted inserted replaced
5919:99ecfe44910b 5920:254a21a104aa
313 global_code = [[local new_medium_id = require "util.id".medium;]]; 313 global_code = [[local new_medium_id = require "util.id".medium;]];
314 }; 314 };
315 new_long_id = { 315 new_long_id = {
316 global_code = [[local new_long_id = require "util.id".long;]]; 316 global_code = [[local new_long_id = require "util.id".long;]];
317 }; 317 };
318
319 trace = {
320 global_code = [[local trace_init = module:require("trace").init;]];
321 };
318 }; 322 };
319 323
320 local function include_dep(dependency, code) 324 local function include_dep(dependency, code)
321 local dep, dep_param = dependency:match("^([^:]+):?(.*)$"); 325 local dep, dep_param = dependency:match("^([^:]+):?(.*)$");
322 local dep_info = available_deps[dep]; 326 local dep_info = available_deps[dep];
369 373
370 if module:get_option_boolean("firewall_experimental_user_marks", true) then 374 if module:get_option_boolean("firewall_experimental_user_marks", true) then
371 module:require"marks"; 375 module:require"marks";
372 end 376 end
373 377
374 local function new_rule(ruleset, chain) 378 local function new_rule(ruleset, chain, line_no)
375 assert(chain, "no chain specified"); 379 assert(chain, "no chain specified");
376 local rule = { conditions = {}, actions = {}, deps = {} }; 380 local rule = { conditions = {}, actions = {}, deps = {}, line_no = line_no };
377 table.insert(ruleset[chain], rule); 381 table.insert(ruleset[chain], rule);
378 return rule; 382 return rule;
379 end 383 end
380 384
381 local function parse_firewall_rules(filename) 385 local function parse_firewall_rules(filename)
383 387
384 local function errmsg(err) 388 local function errmsg(err)
385 return "Error compiling "..filename.." on line "..line_no..": "..err; 389 return "Error compiling "..filename.." on line "..line_no..": "..err;
386 end 390 end
387 391
392 local metadata = { debug = {} };
388 local ruleset = { 393 local ruleset = {
389 deliver = {}; 394 deliver = {};
390 }; 395 };
391 396
392 local chain = "deliver"; -- Default chain 397 local chain = "deliver"; -- Default chain
427 end 432 end
428 elseif chain_info.type ~= "event" then 433 elseif chain_info.type ~= "event" then
429 return nil, errmsg("Only event chains supported at the moment"); 434 return nil, errmsg("Only event chains supported at the moment");
430 end 435 end
431 ruleset[chain] = ruleset[chain] or {}; 436 ruleset[chain] = ruleset[chain] or {};
437 elseif not(state) and line:sub(1, 2) == "@@" then
438 local k, v = line:match("^@@%s*([^%s=]+)%s*=%s*(.+)$");
439 if not k then
440 return nil, errmsg("Unable to parse metadata assignment (expected '@@ key = value')");
441 end
442 metadata[k] = v;
432 elseif not(state) and line:sub(1,1) == "%" then -- Definition (zone, limit, etc.) 443 elseif not(state) and line:sub(1,1) == "%" then -- Definition (zone, limit, etc.)
433 local what, name = line:match("^%%%s*([%w_]+) +([^ :]+)"); 444 local what, name = line:match("^%%%s*([%w_]+) +([^ :]+)");
434 if not definition_handlers[what] then 445 if not definition_handlers[what] then
435 return nil, errmsg("Definition of unknown object: "..what); 446 return nil, errmsg("Definition of unknown object: "..what);
436 elseif not name or not idsafe(name) then 447 elseif not name or not idsafe(name) then
481 for _, dep in ipairs(action_deps or {}) do 492 for _, dep in ipairs(action_deps or {}) do
482 table.insert(rule.deps, dep); 493 table.insert(rule.deps, dep);
483 end 494 end
484 elseif state == "actions" then -- state is actions but action pattern did not match 495 elseif state == "actions" then -- state is actions but action pattern did not match
485 state = nil; -- Awaiting next rule, etc. 496 state = nil; -- Awaiting next rule, etc.
486 table.insert(ruleset[chain], rule); 497 table.insert(ruleset[chain], rule); -- FIXME: Is this a bug? Rule should have already been inserted by new_rule()?
487 rule = nil; 498 rule = nil;
488 else 499 else
489 if not state then 500 -- Condition
501 if not state then -- Starting a new rule block?
490 state = "rules"; 502 state = "rules";
491 rule = new_rule(ruleset, chain); 503 rule = new_rule(ruleset, chain, line_no);
492 end 504 end
493 -- Check standard modifiers for the condition (e.g. NOT) 505 -- Check standard modifiers for the condition (e.g. NOT)
494 local negated; 506 local negated;
495 local condition = line:match("^[^:=%.?]*"); 507 local condition = line:match("^[^:=%.?]*");
496 if condition:find("%f[%w]NOT%f[^%w]") then 508 if condition:find("%f[%w]NOT%f[^%w]") then
512 for _, dep in ipairs(condition_deps or {}) do 524 for _, dep in ipairs(condition_deps or {}) do
513 table.insert(rule.deps, dep); 525 table.insert(rule.deps, dep);
514 end 526 end
515 end 527 end
516 end 528 end
517 return ruleset; 529 return ruleset, metadata;
518 end 530 end
519 531
520 local function process_firewall_rules(ruleset) 532 local function process_firewall_rules(ruleset, metadata)
521 -- Compile ruleset and return complete code 533 -- Compile ruleset and return complete code
522 534
523 local chain_handlers = {}; 535 local chain_handlers = {};
524 536
525 -- Loop through the chains in the parsed ruleset (e.g. incoming, outgoing) 537 -- Loop through the chains in the parsed ruleset (e.g. incoming, outgoing)
535 end 547 end
536 condition_uses[condition] = (condition_uses[condition] or 0) + 1; 548 condition_uses[condition] = (condition_uses[condition] or 0) + 1;
537 end 549 end
538 end 550 end
539 551
552 if metadata.trace then
553 include_dep("trace", code);
554 table.insert(code, ("local trace = trace_init(%q, %q);"):format(metadata.filename, chain_name))
555 end
556
540 local condition_cache, n_conditions = {}, 0; 557 local condition_cache, n_conditions = {}, 0;
541 for _, rule in ipairs(rules) do 558 for rule_n, rule in ipairs(rules) do
542 for _, dep in ipairs(rule.deps) do 559 for _, dep in ipairs(rule.deps) do
543 include_dep(dep, code); 560 include_dep(dep, code);
544 end 561 end
545 table.insert(code, "\n\t\t"); 562 table.insert(code, "\n\t\t");
546 local rule_code; 563 local rule_code;
560 end 577 end
561 rule.conditions[i] = (negated and "not(" or "")..name..(negated and ")" or ""); 578 rule.conditions[i] = (negated and "not(" or "")..name..(negated and ")" or "");
562 else 579 else
563 rule.conditions[i] = (negated and "not(" or "(")..condition..")"; 580 rule.conditions[i] = (negated and "not(" or "(")..condition..")";
564 end 581 end
582
583 if metadata.trace then
584 -- Wrap each condition in a tracer
585 rule.conditions[i] = ("trace(%d, %d, %s)"):format(rule_n, i, rule.conditions[i]);
586 end
587 end
588
589 if metadata.trace then
590 -- Trace overall action
591 table.insert(rule.actions, 1, ("trace(%d, nil, true)"):format(rule_n));
592 table.insert(rule.actions, ("else trace(%d, nil, false)"):format(rule_n));
565 end 593 end
566 594
567 rule_code = "if "..table.concat(rule.conditions, " and ").." then\n\t\t\t" 595 rule_code = "if "..table.concat(rule.conditions, " and ").." then\n\t\t\t"
568 ..table.concat(rule.actions, "\n\t\t\t") 596 ..table.concat(rule.actions, "\n\t\t\t")
569 .."\n\t\tend\n"; 597 .."\n\t\tend\n";
590 618
591 return chain_handlers; 619 return chain_handlers;
592 end 620 end
593 621
594 local function compile_firewall_rules(filename) 622 local function compile_firewall_rules(filename)
595 local ruleset, err = parse_firewall_rules(filename); 623 local ruleset, metadata = parse_firewall_rules(filename);
596 if not ruleset then return nil, err; end 624 if not ruleset then return nil, metadata; end
597 local chain_handlers = process_firewall_rules(ruleset); 625 local chain_handlers = process_firewall_rules(ruleset, metadata);
598 return chain_handlers; 626 return chain_handlers;
599 end 627 end
600 628
601 -- Compile handler code into a factory that produces a valid event handler. Factory accepts 629 -- Compile handler code into a factory that produces a valid event handler. Factory accepts
602 -- a value to be returned on PASS 630 -- a value to be returned on PASS