From 6b4694282c59ecdd0b4ded6bec802656c5bc4173 Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Thu, 31 Aug 2023 16:19:57 +0200 Subject: [PATCH] net/wireguard - make our service control a bit smarted in case of a [re]configure. If the endresult from the interface perspective is guaranteed the same as we used the last time, just omit the stop() operation and reload the configuration. This should warrant a fluent reload when only peers are added. for https://github.com/opnsense/plugins/pull/3358 --- .../scripts/Wireguard/wg-service-control.php | 51 +++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/net/wireguard/src/opnsense/scripts/Wireguard/wg-service-control.php b/net/wireguard/src/opnsense/scripts/Wireguard/wg-service-control.php index 7e6c57a09..f6777a02c 100755 --- a/net/wireguard/src/opnsense/scripts/Wireguard/wg-service-control.php +++ b/net/wireguard/src/opnsense/scripts/Wireguard/wg-service-control.php @@ -94,7 +94,7 @@ function wg_start($server, $fhandle) // flush checksum to ease change detection fseek($fhandle, 0); ftruncate($fhandle, 0); - fwrite($fhandle, @md5_file($server->cnfFilename)); + fwrite($fhandle, @md5_file($server->cnfFilename) . "|". wg_reconfigure_hash($server)); syslog(LOG_NOTICE, "Wireguard interface {$server->name} ({$server->interface}) started"); } @@ -110,6 +110,43 @@ function wg_stop($server) } +/** + * Calculate a hash which determines if we are able to reconfigure without a restart of the tunnel. + * We currently assume if something changed on the interface or peer routes are being pushed, it's safer to + * restart then reload. + */ +function wg_reconfigure_hash($server) +{ + if (empty((string)$server->disableroutes)) { + return md5(uniqid('', true)); // random hash, should always reconfigure + } + return md5( + sprintf( + '%s|%s|%s', + $server->tunneladdress, + $server->mtu, + $server->gateway + ) + ); +} + +/** + * The stat hash file answers two questions, [1] has anything changed, which is answered using an md5 hash of the + * configuration file. The second question, if something has changed, is it safe to only reload the configuration. + * This is answered by wg_reconfigure_hash() for the instance in question. + */ +function get_stat_hash($fhandle) +{ + fseek($fhandle, 0); + $payload = stream_get_contents($fhandle) ?? ''; + $parts = explode('|', $payload); + return [ + 'file' => $parts[0] ?? '', + 'interface' => $parts[1] ?? '' + ]; + +} + $opts = getopt('ah', [], $optind); $args = array_slice($argv, $optind); @@ -148,10 +185,18 @@ if (isset($opts['h']) || empty($args) || !in_array($args[0], ['start', 'stop', ' break; case 'configure': if ( - @md5_file($node->cnfFilename) != @file_get_contents($node->statFilename) || + @md5_file($node->cnfFilename) != get_stat_hash($statHandle)['file'] || !does_interface_exist((string)$node->interface) ) { - wg_stop($node); + if (get_stat_hash($statHandle)['interface'] != wg_reconfigure_hash($node)) { + // Fluent reloading not supported for this instance, make sure the user is informed + syslog( + LOG_NOTICE, + "Wireguard interface {$node->name} ({$node->interface}) ". + "can not reconfigure without stopping it first." + ); + wg_stop($node); + } wg_start($node, $statHandle); } break;