Skip to content

Commit

Permalink
VPN: OpenVPN: Instances - add carp vhid tracking for clients. Offers …
Browse files Browse the repository at this point in the history
…the ability to track the carp status of a vhid to determine if a client should be active or not.
  • Loading branch information
AdSchellevis committed Aug 25, 2023
1 parent c7f0f43 commit f56c6e2
Show file tree
Hide file tree
Showing 5 changed files with 70 additions and 2 deletions.
3 changes: 3 additions & 0 deletions src/etc/rc.syshook.d/carp/20-openvpn-instances
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#!/bin/sh

configctl -dq openvpn configure
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ class VirtualIPField extends BaseListField
*/
private $vipType = "*";

/**
* @var boolean legacy key usage
*/
private $isLegacyKey = true;

/**
* @var array cached collected certs
*/
Expand All @@ -55,6 +60,18 @@ public function setType($value)
$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)
*/
Expand Down Expand Up @@ -83,7 +100,12 @@ protected function actionPostLoadingEvent()
} 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]);
Expand Down
5 changes: 5 additions & 0 deletions src/opnsense/mvc/app/models/OPNsense/OpenVPN/OpenVPN.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
32 changes: 31 additions & 1 deletion src/opnsense/scripts/openvpn/ovpn_service_control.php
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -109,6 +130,7 @@ function ovpn_instance_stats($instance, $fhandle)
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)) {
Expand All @@ -133,7 +155,15 @@ function ovpn_instance_stats($instance, $fhandle)
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);
}
Expand Down

0 comments on commit f56c6e2

Please sign in to comment.