Multiple interfaces sharing a filter config: a script
-
Hello, everyone!
We manage a pfSense box running 1.2.3 for stability reasons, and had run into a problem where we needed the rules for two interfaces to be exactly the same at all times. I've since heard that there's a feature in pfSense 2.x that will allow one set of rules to apply to multiple interfaces, but upgrading is not an option; therefore, I wrote this script with some guidance from the IRC channel. Hopefully it will be of use to someone.
In the configuration section, $iface1 is the "master" interface that you want to propagate to the other interface; $iface2 is the interface to compare and POTENTIALLY OVERWRITE. They use the internal names pfSense uses: you can usually figure out the internal names of the interfaces you want to use by looking at their firewall rules pages and taking the "if=" parameter from the URL. For example, in the URL https://your.pfsense.firewall.com/firewall_rules.php?if=opt1 , 'opt1' is your interface name.
Be sure to take a full backup of your configuration before running this script. Of course, I am not responsible for any damage done to your firewall as a result of running this script; it is provided free of charge with no warranty and all of that.
// Configuration section $iface1 = "wan"; $iface2 = "opt1"; // End configuration section require_once("globals.inc"); require_once("functions.inc"); require_once("config.inc"); require_once("util.inc"); // ^ preamble $lock_fh = fopen("/tmp/propagator.lock", "w+"); $blocked_lock = FALSE; $test_lock = flock($lock_fh, LOCK_EX|LOCK_NB, $blocked_lock); if (!$test_lock && $blocked_lock) exit(0); if (!$test_lock) exit(1); $iface1_rules = array(); $iface2_rules = array(); $sorted_out_rules = array(); foreach ($config['filter']['rule'] as $index => $rule) { if ($rule['interface'] != $iface2) { if (!isset($sorted_out_rules[$rule['interface']])) $sorted_out_rules[$rule['interface']] = array(); $sorted_out_rules[$rule['interface']][] = $rule; } if ($rule['interface'] == $iface1) { unset($rule['interface']); $iface1_rules[] = $rule; continue; } if ($rule['interface'] == $iface2) { unset($rule['interface']); $iface2_rules[] = $rule; continue; } } $filter_applied = (file_exists($g['varrun_path'] . "/filter.conf.dirty") ? 0 : 1); if ($iface1_rules != $iface2_rules) { /* Our iface2 is different from our iface1 :( */ $new_rules = array(); foreach ($sorted_out_rules as $iface => $rule_array) { $new_rules = array_merge($new_rules, $rule_array); } foreach ($sorted_out_rules[$iface1] as $rule) { $rule['interface'] = $iface2; $new_rules[] = $rule; } $config['filter']['rule'] = $new_rules; write_config("Syncing out-of-date firewall rules in {$iface2}..."); if ($filter_applied) filter_configure(); } flock($lock_fh, LOCK_UN|LOCK_NB); fclose($lock_fh); unlink("/tmp/propagator.lock"); ?>
You should be able to use it in a cron as well; it should prevent itself from running twice at the same time.
Enjoy! :)