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 , '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
    // ^ 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) {
    		$iface1_rules[] = $rule;
    	if ($rule['interface'] == $iface2) {
    		$iface2_rules[] = $rule;
    $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);

    You should be able to use it in a cron as well; it should prevent itself from running twice at the same time.

    Enjoy! :)

Log in to reply