-
-
Save spali/2da4f23e488219504b2ada12ac59a7dc to your computer and use it in GitHub Desktop.
| #!/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); | |
| } |
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");
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.
@coderph0x sorry I mean I had a different, older script - not one from this thread
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.
I have some problems with using this script. 2 things I can think about:
- I specify $ifkey wrongly (I take the interface name visible in opnsense, lagg0_vlan2 in my case)
- 26.1 changed something, and the methods for enabling/disabling the interface changed.
I see error log for triggering action, but interface is still UP.
Can anyone help me?
I also have problems on 26.1.
Also the scripts don't seem to output anything, e.g. the Validation doesn't print anything which makes me think there is some change to php maybe.
I stopped using scripts like this as I got the functionality working with opnsense itself. PPPoE to my ISP, dial up interfaces get torn down on CARP backup, I could never get this working which is why I started with this script, but I spent some time on it and have it working properly now.
@stevencoutts Do tell, how did you manage to configure this functionality directly within OpnSense?
The main thing I was missing was CARP on the VLAN interface of my WAN port. I had tried CARP on the physical interface, but it had to be on the VLAN. It works as expected now.
That sounds like a solution that only works for PPPoE connections. I believe that the "Disconnect dialup interfaces" functionality has been in there for a while now. This script is trying to solve the failover situation for any interface connection, including things like fiber, cellular bridge, or cable modem connections.
For anyone landing here later: I made a working fork for my setup, tested on OPNsense 26.1.6.
Warning: it is vibe-coded / AI-assisted, so please review it carefully before using it in production.
You must adapt the CARP trigger subsystem, interface key, and gateway name placeholders to your own setup.
In my environment, it correctly keeps the DHCP WAN inactive on BACKUP and active on MASTER.
Fork: Link
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.