Mercurial > prosody-modules
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 |