Files
opnsense-carp-dhcp/opnsense-carp-dhcp-master.php
2021-12-04 16:39:22 -05:00

342 lines
13 KiB
PHP

#!/usr/local/bin/php
<?php
require_once("config.inc");
require_once("interfaces.inc");
require_once("util.inc");
require_once("filter.inc");
require_once("util.inc");
require_once("system.inc");
require_once('rrd.inc');
require_once('plugins.inc.d/webgui.inc');
require_once("XMLRPC_Client.inc");
/*
*/
# to get the $config, put file_put_contents('/root/config_php.log', print_r($config, true)); at the end of the /usr/local/opnsense/scripts/shell/setaddr.php file
# Locations:
# /usr/local/etc/inc
# /usr/local/opnsense/scripts/shell
# /usr/local/sbin/opnsense-shell
#############
# Variables #
#############
# Master Node/Router
$wanInterface = 'wan';
$gatewayName = 'WAN_GW';
$wanStaticIP = '192.168.255.1';
$wanStaticIPSubnet = '30';
###################
# Start of Script #
###################
$randomString = getRandString(5);
function getRandString($n) {
$characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
$randomString = '';
for ($i = 0; $i < $n; $i++) {
$index = rand(0, strlen($characters) - 1);
$randomString .= $characters[$index];
}
return $randomString;
}
function write_config_and_restart_services ($interface) {
write_config();
system_hosts_generate(true);
system_resolvconf_generate(true);
interface_bring_down($interface);
interface_configure(true, $interface, true);
plugins_configure('monitor', true);
filter_configure_sync(true);
webgui_configure_do(true);
rrd_configure(true);
}
function echo_write_log ($message) {
global $randomString;
$dateTime = date("Y-m-d H:i:s");
$folder = '/var/log/opnsense_carp_dhcp';
$message = $dateTime . " - " . $randomString . " - " . $message . "\n";
if (!is_dir($folder)) {
mkdir($folder);
}
file_put_contents("$folder/log_".date("Ymd").".log", $message, FILE_APPEND);
echo $message;
}
function is_specialnet($net) {
if (in_array($net, array('any','(self)'))) {
return true;
} else {
foreach (legacy_config_get_interfaces(array("enable" => true)) as $ifent => $ifdetail) {
if ($ifent == $net || (!isset($ifdetail['virtual']) && $ifent."ip" == $net)) {
return true;
}
}
}
return false;
}
function get_specialnets($only_enabled = false) {
$specialnets = array();
$specialnets["any"] = gettext("any");
$specialnets["(self)"] = gettext("This Firewall");
$filter = $only_enabled ? array("enable" => true) : array();
foreach (legacy_config_get_interfaces($filter) as $ifent => $ifdetail) {
$specialnets[$ifent] = htmlspecialchars($ifdetail['descr']) . " " . gettext("net");
if (!isset($ifdetail['virtual'])) {
$specialnets[$ifent."ip"] = htmlspecialchars($ifdetail['descr']). " ". gettext("address");
}
}
return $specialnets;
}
function xmlrpc_exec($method, $params = [], $debug = false) {
global $config;
$synchronizeto = null;
$hasync = $config['hasync'];
if (is_ipaddrv6($hasync['synchronizetoip'])) {
$hasync['synchronizetoip'] = "[{$hasync['synchronizetoip']}]";
}
if (!empty($hasync['synchronizetoip'])) {
// determine target url
if (substr($hasync['synchronizetoip'],0, 4) == 'http') {
// URL provided
if (substr($hasync['synchronizetoip'], strlen($hasync['synchronizetoip'])-1, 1) == '/') {
$synchronizeto = $hasync['synchronizetoip']."xmlrpc.php";
} else {
$synchronizeto = $hasync['synchronizetoip']."/xmlrpc.php";
}
} elseif (!empty($config['system']['webgui']['protocol'])) {
// no url provided, assume the backup is using the same settings as our box.
$port = $config['system']['webgui']['port'];
if (!empty($port)) {
$synchronizeto = $config['system']['webgui']['protocol'] . '://'.$hasync['synchronizetoip'].':'.$port."/xmlrpc.php";
} else {
$synchronizeto = $config['system']['webgui']['protocol'] . '://'.$hasync['synchronizetoip']."/xmlrpc.php" ;
}
}
$username = empty($hasync['username']) ? "root" : $hasync['username'];
$client = new SimpleXMLRPC_Client($synchronizeto,240);
$client->debug=$debug;
$client->setCredentials($username, $hasync['password']);
if ($client->query($method, $params)) {
return $client->getResponse();
}
}
return false;
}
echo_write_log("Start of Script " . $argv[0]);
echo_write_log("WAN Interface: " . $wanInterface);
echo_write_log("Name of static WAN Gateway: " . $gatewayName);
echo_write_log("Static WAN IP: " . $wanStaticIP);
echo_write_log("Static WAN Subnit Bits: " . $wanStaticIPSubnet);
$vip = $config['virtualip']['vip'];
$intf_details = legacy_interfaces_details();
$intf = get_real_interface($wanInterface);
echo_write_log("Real WAN Interface: " . $intf);
echo_write_log("Looping through VIP carps to get WAN status...");
foreach ($vip as $carp) {
if ($carp['interface'] == $wanInterface) {
echo_write_log("VIP CARP WAN Interface and vhid: " . convert_friendly_interface_to_friendly_descr($carp['interface']) . "@{$carp['vhid']}");
$wanCarp = $carp;
break;
}
}
# CARP Status MASTER or BACKUP
$carpStatus = $intf_details[$intf]['carp'][$wanCarp['vhid']]['status'];
echo_write_log("VIP CARP WAN Status: " . $carpStatus);
if ($carpStatus == "MASTER") {
do {
echo_write_log("Setting WAN to DHCP");
# Config for WAN DHCP and disable static gateway
$config['interfaces'][$wanInterface]['ipaddr'] = 'dhcp';
$config['interfaces'][$wanInterface]['subnet'] = '';
$config['interfaces'][$wanInterface]['gateway'] = '';
echo_write_log("Looping through gateways to remove the static WAN gateway...");
foreach ($config['gateways']['gateway_item'] as $i => $gateway) {
if ($gateway['name'] == $gatewayName) {
echo_write_log("Removing the static WAN gateway: ". $gateway['name']);
unset($config['gateways']['gateway_item'][$i]);
}
}
# set the config and reload everything to get a working DHCP
write_config_and_restart_services($wanInterface);
echo_write_log("Done setting WAN to DHCP");
# DHCP ip address and gateway address loop
echo_write_log("Getting DHCP and Gateway IP Addresses");
# get DHCP wan address and subnet
$iflist = legacy_config_get_interfaces(array('enable' => true, 'virtual' => false));
$ifdetails = legacy_interfaces_details();
if (!count($iflist)) {
echo "\n\tNo network interfaces are assigned.\n";
return;
}
$wanInfo = null;
foreach ($iflist as $ifname => $ifcfg) {
$class = null;
if ($ifcfg['descr'] == 'WAN') {
# this will have all the information about the WAN interface
$ifcfg['details'] = $ifdetails[$ifcfg['if']];
# this will break out the loop and leave the $ifcfg with the details of the wan
break;
#print_r($ifcfg);
}
}
$wanIP = $ifcfg['details']['ipv4'][0]['ipaddr'];
$wanSubnet = $ifcfg['details']['ipv4'][0]['subnetbits'];
echo_write_log("WAN DHCP IP: " . $wanIP);
echo_write_log("WAN DHCP Sbunet Bits: " . $wanSubnet);
$gatewayIP = trim(shell_exec('netstat -rn | grep default | awk \'{print $2;}\''));
echo_write_log("Gateway IP: " . $gatewayIP);
echo_write_log("Done getting DHCP and Gateway IP Addresses");
if (filter_var($wanIP, FILTER_VALIDATE_IP) and is_int($wanSubnet) and filter_var($gatewayIP, FILTER_VALIDATE_IP)) {
echo_write_log("WAN IP, Subnet Bits, and Gateway IP are okay");
break;
} else {
echo_write_log("Warning: Missing WAN IP, Subnet Bits, or Gateway IP. Trying again...");
}
} while (true);
echo_write_log("Setting WAN to Static based on the DHCP information");
# Config for WAN Static
$config['interfaces'][$wanInterface]['ipaddr'] = $wanStaticIP;
$config['interfaces'][$wanInterface]['subnet'] = $wanStaticIPSubnet;
$config['interfaces'][$wanInterface]['gateway'] = $gatewayName;
# setup gateway
echo_write_log("Adding static WAN gateway");
$gwCount = count($config['gateways']['gateway_item']);
$config['gateways']['gateway_item'][$gwCount]['gateway'] = $gatewayIP;
$config['gateways']['gateway_item'][$gwCount]['interface'] = $wanInterface;
$config['gateways']['gateway_item'][$gwCount]['name'] = $gatewayName;
$config['gateways']['gateway_item'][$gwCount]['ipprotocol'] = 'inet';
$config['gateways']['gateway_item'][$gwCount]['monitor_disable'] = 1;
$config['gateways']['gateway_item'][$gwCount]['defaultgw'] = 1;
$config['gateways']['gateway_item'][$gwCount]['fargw'] = 1;
# Loop through outbound NAT and update the wan ip
echo_write_log("Loopiong through NAT outbound connections...");
$interface_names= array();
// add this hosts ips
foreach ($config['interfaces'] as $intf => $intfdata) {
if (isset($intfdata['ipaddr']) && $intfdata['ipaddr'] != 'dhcp') {
$interface_names[$intfdata['ipaddr']] = sprintf(gettext('%s address'), !empty($intfdata['descr']) ? $intfdata['descr'] : $intf );
}
}
foreach ($config['nat']['outbound']['rule'] as $i => $rule) {
if ($rule['interface'] == $wanInterface ) {
# NAT Source
if (isset($rule['source']['network']) && is_alias($rule['source']['network'])) {
$natSource = get_alias_description($natent['source']['network']);
} elseif (is_specialnet($rule['source']['network'])) {
$natSource = get_specialnets()[$rule['source']['network']];
} else {
$natSource = $rule['source']['network'] == "(self)" ? gettext("This Firewall") : $rule['source']['network'];
}# NAT Address
if (isset($rule['nonat'])) {
$nat_address = '<I>NO NAT</I>';
} elseif (empty($rule['target'])) {
$nat_address = gettext("Interface address");
} elseif (is_specialnet($rule['target'])) {
$nat_address = htmlspecialchars(get_specialnets()[$rule['target']]);
} elseif ($rule['target'] == "other-subnet") {
$nat_address = $rule['targetip'] . '/' . $rule['targetip_subnet'];
} else {
$nat_address = htmlspecialchars($rule['target']);
}
# NAT Target
if (isset($rule['target']) && is_alias($rule['target'])) {
$natTarget = get_alias_description($rule['target']);
} elseif (!empty($interface_names[$nat_address])){
$natTarget = $interface_names[$nat_address];
} else {
$natTarget = $nat_address;
}
echo_write_log("Found NAT rule on the WAN interface");
echo_write_log("Source: " . $natSource);
echo_write_log("Description: " . $rule['descr']);
echo_write_log("Current NAT rule target: " . $natTarget);
echo_write_log("Setting NAT rule target to: " . $wanIP);
$config['nat']['outbound']['rule'][$i]['target'] = $wanIP;
}
}
# loop through CARP addresses and update the wan ip address
echo_write_log("Loopiong through VIP interfaces...");
foreach ($config['virtualip']['vip'] as $i => $vip) {
if ($vip['interface'] == $wanInterface) {
echo_write_log("Updating VIP CARP WAN interface: ". $vip['interface']);
echo_write_log("Updating VIP CARP WAN interface IP: ". $wanIP);
echo_write_log("Updating VIP CARP WAN interface Subnit Bits: ". $wanSubnet);
echo_write_log("Updating VIP CARP WAN interface Description: VIP WAN (GW: $gatewayIP)");
$config['virtualip']['vip'][$i]['subnet_bits'] = $wanSubnet;
$config['virtualip']['vip'][$i]['subnet'] = $wanIP;
$config['virtualip']['vip'][$i]['descr'] = "VIP WAN (GW: $gatewayIP)";
}
}
# set the config and reload everything to get a working DHCP
write_config_and_restart_services($wanInterface);
echo_write_log("Done Setting WAN to Static based on the DHCP information");
echo_write_log("Testing to see if this router is the HA sync master");
if (filter_var($config['hasync']['synchronizetoip'], FILTER_VALIDATE_IP)) {
echo_write_log("Sleeping for 30 seconds");
sleep(30);
# try to sync CARP settings to backup node/router
echo_write_log("Starting the CARP Sync");
echo_write_log("Trying to ping sync host, " . $config['hasync']['synchronizetoip']);
do {
exec("ping -c 4 " . $config['hasync']['synchronizetoip'], $output, $result);
if ($result == 0) {
echo_write_log("Ping was successful");
break;
} else {
echo_write_log("Ping was unsuccessful");
}
} while (true);
configd_run('filter sync');
xmlrpc_exec('opnsense.configd_reload_all_templates');
echo_write_log("CARP Sync Status: " . $output);
echo_write_log("finished the CARP Sync");
} else {
echo_write_log("Router is not the HA sync master");
}
} else {
echo_write_log("Router is not currently CARP master, not updating");
}
echo_write_log("End of Script " . $argv[0]);