Skip to content

Instantly share code, notes, and snippets.

@spali
Last active November 11, 2025 17:07
Show Gist options
  • Save spali/2da4f23e488219504b2ada12ac59a7dc to your computer and use it in GitHub Desktop.
Save spali/2da4f23e488219504b2ada12ac59a7dc to your computer and use it in GitHub Desktop.
Disable WAN Interface on CARP Backup
#!/usr/local/bin/php
<?php
require_once("config.inc");
require_once("interfaces.inc");
require_once("util.inc");
$subsystem = !empty($argv[1]) ? $argv[1] : '';
$type = !empty($argv[2]) ? $argv[2] : '';
if ($type != 'MASTER' && $type != 'BACKUP') {
log_error("Carp '$type' event unknown from source '{$subsystem}'");
exit(1);
}
if (!strstr($subsystem, '@')) {
log_error("Carp '$type' event triggered from wrong source '{$subsystem}'");
exit(1);
}
$ifkey = 'wan';
if ($type === "MASTER") {
log_error("enable interface '$ifkey' due CARP event '$type'");
$config['interfaces'][$ifkey]['enable'] = '1';
write_config("enable interface '$ifkey' due CARP event '$type'", false);
interface_configure(false, $ifkey, false, false);
} else {
log_error("disable interface '$ifkey' due CARP event '$type'");
unset($config['interfaces'][$ifkey]['enable']);
write_config("disable interface '$ifkey' due CARP event '$type'", false);
interface_configure(false, $ifkey, false, false);
}
@coderph0x
Copy link

coderph0x commented Sep 5, 2025

i use this script on OPNsense 25.7.2. Unlike the original, it only triggers on CARP events for a specific CARP address (replace "99@vlan099" with your CARP interface to react on). Replace "wan" with your WAN interface and "WAN_GATEWAY" with your WAN gateway name. It properly handles interface, gateway, and DHCP client states to avoid failover issues.

Works great, thanks a lot! If your WAN-Interface works with PPPoE, you might want to have a look at https://github.com/Pieshka/minibox-pppoe-annihilator
Switching the gateway costs around three pings even with DHCP, and deactivating the gateway isn't even necessary. Disabling the interface is sufficient.

@USBAkimbo
Copy link

USBAkimbo commented Sep 25, 2025

My WAN DHCP script seems to have broken recently as well

I fed some context and versions to Claude and got this

I'll note that this is specific to my setup and works great, though I imagine others will have a similar setup

  • 2x OPNsense VMs in Proxmox, each on separate physical nodes
  • Each OPNsense VM has a WAN interface on VLAN 2
  • The NIC on each WAN interface have the same MAC address (because only 1 is ever active at once - so from the router in modem mode's perspective, OPNsense just changed switch ports
  • My Virgin ISP router in modem mode is plugged into a port in VLAN 2
  • Virgin run DHCP on WAN, so the IP config is received automatically
#!/usr/local/bin/php

# This files lives in
# /usr/local/etc/rc.syshook.d/carp/50-dhcp

<?php

require_once("config.inc");
require_once("interfaces.inc");
require_once("util.inc");
require_once("plugins.inc");

$subsystem = !empty($argv[1]) ? $argv[1] : '';
$type = !empty($argv[2]) ? $argv[2] : '';

if ($type != 'MASTER' && $type != 'BACKUP') {
    log_error("Carp '$type' event unknown from source '{$subsystem}'");
    exit(1);
}

if (!strstr($subsystem, '@')) {
    log_error("Carp '$type' event triggered from wrong source '{$subsystem}'");
    exit(1);
}

$ifkey = 'wan';
$realif = get_real_interface($ifkey);

if (empty($realif)) {
    log_error("Could not determine real interface for '$ifkey'");
    exit(1);
}

if ($type === "MASTER") {
    log_error("CARP MASTER event: Enabling WAN interface '$ifkey' ($realif)");
    
    // Bring the interface up at OS level
    mwexec("/sbin/ifconfig {$realif} up");
    
    // Small delay to ensure interface is ready
    sleep(2);
    
    // Reconfigure the interface (this will trigger DHCP client)
    interface_configure(false, $ifkey, true, false);
    
    // Explicitly request DHCP renewal if interface uses DHCP
    if (!empty($config['interfaces'][$ifkey]['ipaddr']) && 
        $config['interfaces'][$ifkey]['ipaddr'] == 'dhcp') {
        
        log_error("Requesting DHCP renewal on '$ifkey' ($realif)");
        
        // Kill any existing dhclient process for this interface
        mwexec("/bin/pkill -f 'dhclient: {$realif}'");
        
        // Small delay after killing dhclient
        sleep(1);
        
        // Restart DHCP client
        interface_dhcp_configure($ifkey);
        
        // Alternative method if the above doesn't work:
        // mwexec("/usr/local/sbin/configctl interface reconfigure {$ifkey}");
    }
    
} else {
    log_error("CARP BACKUP event: Disabling WAN interface '$ifkey' ($realif)");
    
    // Release DHCP lease if applicable
    if (!empty($config['interfaces'][$ifkey]['ipaddr']) && 
        $config['interfaces'][$ifkey]['ipaddr'] == 'dhcp') {
        
        log_error("Releasing DHCP lease on '$ifkey' ($realif)");
        
        // Kill dhclient to release the lease
        mwexec("/bin/pkill -f 'dhclient: {$realif}'");
        
        // Explicitly release DHCP lease
        mwexec("/sbin/dhclient -r {$realif}");
    }
    
    // Bring the interface down at OS level
    mwexec("/sbin/ifconfig {$realif} down");
    
    // Clear any remaining IP configuration
    mwexec("/sbin/ifconfig {$realif} inet 0.0.0.0 delete 2>/dev/null");
    mwexec("/sbin/ifconfig {$realif} inet6 ::1 delete 2>/dev/null");
}

// Reload filter rules to accommodate interface state change
filter_configure();

// Signal any plugins about the interface change
plugins_configure('interface', false, array($ifkey));

log_error("CARP WAN failover script completed for '$type' state");

@coderph0x
Copy link

The script doesn't break, it gets reset to default if you update to the next version. I haven't checked what Claude made differentl, however the latest versions posted above still work well.

@USBAkimbo
Copy link

@coderph0x sorry I mean I had a different, older script - not one from this thread

@kronenpj
Copy link

kronenpj commented Sep 26, 2025

I used my script at https://gist.github.com/kronenpj/e90258f12f7a40c4f38a23b609b3288b many times last week while diagnosing a problem. It works very well for me on Opnsense 25.7.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment