VPN: OpenVPN: Instances - add carp vhid tracking for clients. Offers the ability to track the carp status of a vhid to determine if a client should be active or not.

This commit is contained in:
Ad Schellevis 2023-08-25 22:28:29 +02:00
parent c7f0f43515
commit f56c6e2a0b
5 changed files with 70 additions and 2 deletions

View File

@ -0,0 +1,3 @@
#!/bin/sh
configctl -dq openvpn configure

View File

@ -129,6 +129,14 @@
my.remote.local dead:beaf:: my.remote.local:1494 [dead:beaf::]:1494 192.168.1.1:1494
</help>
</field>
<field>
<id>instance.carp_depend_on</id>
<label>Depend on (carp)</label>
<type>dropdown</type>
<style>role role_client</style>
<help>The carp VHID to depend on, when this virtual address is not in master state,
the instance will be shutdown.</help>
</field>
<field>
<type>header</type>
<label>Trust</label>

View File

@ -41,6 +41,11 @@ class VirtualIPField extends BaseListField
*/
private $vipType = "*";
/**
* @var boolean legacy key usage
*/
private $isLegacyKey = true;
/**
* @var array cached collected certs
*/
@ -55,6 +60,18 @@ class VirtualIPField extends BaseListField
$this->vipType = $value;
}
/**
* as this field type is used to hook legacy fields and MVC ones, specify a key here.
* default it uses a legacy (subnet) key.
* @param $value string vip type
*/
public function setKey($value)
{
if (strtolower($value) == 'mvc') {
$this->isLegacyKey = false;
}
}
/**
* generate validation data (list of virtual ips)
*/
@ -83,7 +100,12 @@ class VirtualIPField extends BaseListField
} else {
$caption = sprintf(gettext("[%s] %s on %s"), $vip->subnet, $vip->descr, $intf_name);
}
self::$internalStaticOptionList[$this->vipType][(string)$vip->subnet] = $caption;
if ($this->isLegacyKey) {
$key = (string)$vip->subnet;
} else {
$key = (string)$vip->attributes()['uuid'];
}
self::$internalStaticOptionList[$this->vipType][$key] = $caption;
}
}
natcasesort(self::$internalStaticOptionList[$this->vipType]);

View File

@ -381,6 +381,11 @@
<FieldSeparator>,</FieldSeparator>
<asList>Y</asList>
</ntp_servers>
<carp_depend_on type="VirtualIPField">
<type>carp</type>
<Required>N</Required>
<key>mvc</key>
</carp_depend_on>
<description type="TextField">
<Required>N</Required>
</description>

View File

@ -91,6 +91,27 @@ function ovpn_instance_stats($instance, $fhandle)
return $data;
}
function get_vhid_status()
{
$vhids = [];
$uuids = [];
foreach ((new OPNsense\Interfaces\Vip())->vip->iterateItems() as $id => $item) {
if ($item->mode == 'carp') {
$uuids[(string)$item->vhid] = $id;
}
}
foreach (legacy_interfaces_details() as $ifdata) {
if (!empty($ifdata['carp'])) {
foreach ($ifdata['carp'] as $data) {
if (isset($uuids[$data['vhid']])) {
$vhids[$uuids[$data['vhid']]] = $data['status'];
}
}
}
}
return $vhids;
}
$opts = getopt('ah', [], $optind);
$args = array_slice($argv, $optind);
@ -109,6 +130,7 @@ if (isset($opts['h']) || empty($args) || !in_array($args[0], ['start', 'stop', '
if ($action != 'stop') {
$mdl->generateInstanceConfig($instance_id);
}
$vhids = $action == 'configure' ? get_vhid_status() : [];
$instance_ids = [];
foreach ($mdl->Instances->Instance->iterateItems() as $key => $node) {
if (empty((string)$node->enabled)) {
@ -133,7 +155,15 @@ if (isset($opts['h']) || empty($args) || !in_array($args[0], ['start', 'stop', '
ovpn_start($node, $statHandle);
break;
case 'configure':
if ($instance_stats['has_changed'] || !isvalidpid($node->pidFilename)) {
$carp_down = false;
if ((string)$node->role == 'client' && !empty($vhids[(string)$node->carp_depend_on])) {
$carp_down = $vhids[(string)$node->carp_depend_on] != 'MASTER';
}
if ($carp_down) {
if (isvalidpid($node->pidFilename)) {
ovpn_stop($node);
}
} elseif ($instance_stats['has_changed'] || !isvalidpid($node->pidFilename)) {
ovpn_stop($node);
ovpn_start($node, $statHandle);
}