diff --git a/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/FirewallController.php b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/FirewallController.php index 521d0b2b4..a6df48cd0 100644 --- a/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/FirewallController.php +++ b/src/opnsense/mvc/app/controllers/OPNsense/Diagnostics/FirewallController.php @@ -92,6 +92,11 @@ class FirewallController extends IndexController "name" => "interfaces", "caption" => gettext("interfaces"), "endpoint" => "/api/diagnostics/firewall/pf_statistcs/interfaces" + ], + [ + "name" => "rules", + "caption" => gettext("rules"), + "endpoint" => "/api/diagnostics/firewall/pf_statistcs/rules" ] ]; $this->view->default_tab = "info"; diff --git a/src/opnsense/mvc/app/views/OPNsense/Diagnostics/treeview.volt b/src/opnsense/mvc/app/views/OPNsense/Diagnostics/treeview.volt index 744591346..7382f7eb2 100644 --- a/src/opnsense/mvc/app/views/OPNsense/Diagnostics/treeview.volt +++ b/src/opnsense/mvc/app/views/OPNsense/Diagnostics/treeview.volt @@ -83,6 +83,8 @@ closedIcon: $(''), openedIcon: $(''), onCreateLi: function(node, $li) { + let n_title = $li.find('.jqtree-title'); + n_title.text(n_title.text().replace('>','\>').replace('<','\<')); if (node.value !== undefined) { $li.find('.jqtree-element').append( '  :  ' + node.value @@ -101,6 +103,10 @@ $tree.tree('openNode', $tree.tree('getNodeById', key)); } } + //open node on label click + $tree.bind('tree.click', function(e) { + $tree.tree('toggle', e.node); + }); } else { let curent_state = $tree.tree('getState'); $tree.tree('loadData', dict_to_tree(data)); diff --git a/src/opnsense/scripts/filter/pfstatistcs.py b/src/opnsense/scripts/filter/pfstatistcs.py index 05feb4d63..00ea17acf 100755 --- a/src/opnsense/scripts/filter/pfstatistcs.py +++ b/src/opnsense/scripts/filter/pfstatistcs.py @@ -96,17 +96,42 @@ def pfctl_interfaces(): return result -def main(): - result = { - 'info': pfctl_info(), - 'memory': pfctl_memory(), - 'timeouts': pfctl_timeouts(), - 'interfaces': pfctl_interfaces() +def pfctl_rules(): + result = dict() + headings = { + "rules": "filter rules", + "nat": "nat rules" } + for key in headings: + result[headings[key]] = dict() + rule = None + for line in subprocess.run(['/sbin/pfctl', '-vvs' + key], capture_output=True, text=True).stdout.split("\n"): + sline = line.strip() + if len(line) > 0 and line[0] not in ["\t", " "]: + rule = sline + result[headings[key]][rule] = dict() + elif rule is not None and sline.startswith('[') and sline.endswith(']'): + items = sline[1:].strip().lower().split(':') + for idx, item in enumerate(items[1:],1): + opt = 'state_creations' if items[idx-1].find('creations') > -1 else items[idx-1].split()[-1] + val = " ".join(item.split()[:-1]).replace('state', '') + result[headings[key]][rule][opt] = int(val) if val.isdigit() else val - if len(sys.argv) > 1 and sys.argv[1] in result: - return result[sys.argv[1]] - else: - return result + return result + +def main(): + sections = { + 'info': pfctl_info, + 'memory': pfctl_memory, + 'timeouts': pfctl_timeouts, + 'interfaces': pfctl_interfaces, + 'rules': pfctl_rules + } + result = dict() + for section in sections: + if (len(sys.argv) > 1 and sys.argv[1] == section) or (len(sys.argv) == 1): + result[section] = sections[section]() + + return result print(ujson.dumps(main()))