From fa1e6e427fb11d5ae132f56e2844ba9726687b93 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Wed, 9 Sep 2026 10:34:30 +0200 Subject: [PATCH 01/21] luci-app-strongswan-swanctl: fix globals NamedSection function arguments The function parameters are incorrect. The second argument is the type of the section. It is not 'ipsec' but 'globals'. While we're at it, the section has been expanded with a general help text. Signed-off-by: Florian Eckert --- .../resources/view/strongswan-swanctl/strongswan.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js index e1ce0118f4ad..5f7be4cc40b2 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js @@ -11,8 +11,9 @@ return view.extend({ _('On this page, you can configure the IPsec service.')); m.tabbed = true; - // strongSwan General Settings - s = m.section(form.NamedSection, 'globals', 'ipsec', _('General Settings')); + // general settings + s = m.section(form.NamedSection, 'globals', 'globals', _('General Settings'), + _('Configure global service parameters.')); o = s.option(widgets.NetworkSelect, 'interface', _('Listening Interfaces'), _('Interfaces that accept VPN traffic.') + '
' + From a4934e85a8c8697c00ac0265dc3bae24b1c614fd Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Tue, 8 Sep 2026 15:00:25 +0200 Subject: [PATCH 02/21] luci-app-strongswan-swanctl: migrate section tunnel and transport to child MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This change aligns LuCI ipsec strongswan configuration with the current swanctl initscript implementation by migrating the section type 'tunnel' and 'transport to section type 'child'. To allow the mode used by the ‘child’ to be specified, the new ucioption ‘mode’ has also been added for the uci section type ‘child’. Currently, only the ‘transport’ and 'tunnel' modes are supported. Signed-off-by: Florian Eckert --- .../view/strongswan-swanctl/swanctl.js | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 07288aef5f15..754060d1009b 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -37,14 +37,14 @@ function sectionNameCheck(extra_class) { ui.addValidator(nameEl, 'uciname', true, function(v) { let sections = [ ...uci.sections('ipsec', 'remote'), - ...uci.sections('ipsec', 'tunnel'), + ...uci.sections('ipsec', 'child'), ...uci.sections('ipsec', 'crypto_proposal'), ]; if (sections.find(function(s) { return s['.name'] == v; })) { - return _('Remotes, Encryption Proposals and Tunnels may not share the same names.') + ' ' + - _('Use combinations like tunnel1_phase1 that do not exceed 15 characters.'); + return _('Remotes, Encryption Proposals and Children may not share the same names.') + ' ' + + _('Use combinations like child1_phase1 that do not exceed 15 characters.'); } if (v.length > 15) return _('Name length shall not exceed 15 characters'); return true; @@ -124,18 +124,18 @@ return view.extend({ }; o.rmempty = false; - o = s.taboption('general', form.MultiValue, 'tunnel', _('Tunnel'), - _('The Tunnel containing the ESP (phase 2) section')); + o = s.taboption('general', form.MultiValue, 'child', _('Children'), + _('The Children containing the ESP (phase 2) section')); o.load = function (section_id) { this.keylist = []; this.vallist = []; - var sections = uci.sections('ipsec', 'tunnel'); + var sections = uci.sections('ipsec', 'child'); if (sections.length == 0) { - this.value('', _('Please create a Tunnel first')); + this.value('', _('Please create a Children first')); } else { sections.forEach(L.bind(function (section) { - this.value(section['.name']); + this.value(section['.name'], '%s (%s)'.format(section['.name'], section['mode'])); }, this)); } @@ -269,9 +269,9 @@ return view.extend({ o.default = 'ikev2'; o.modalonly = true; - // Tunnel Configuration - s = m.section(form.GridSection, 'tunnel', _('Tunnel Configuration'), - _('Define Connection Children to be used as Tunnels in Remote Configurations.')); + // Children Configuration + s = m.section(form.GridSection, 'child', _('Children Configuration'), + _('Define Connection Children to be used in Remote Configurations.')); s.addremove = true; s.nodescriptions = true; s.renderSectionAdd = sectionNameCheck; @@ -279,6 +279,12 @@ return view.extend({ o = s.tab('general', _('General')); o = s.tab('advanced', _('Advanced')); + o = s.taboption('general', form.ListValue, 'mode', _('Child mode')); + o.rmempty = false; + o.value('tunnel', _('Tunnel')); + o.value('transport', _('Transport')); + o.default = 'tunnel'; + o = s.taboption('general', form.DynamicList, 'local_subnet', _('Local Subnet'), _('Local network(s)')); o.datatype = 'cidr'; From 337fb54a6342b91b1fec356062ceaa8c49ae4416 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Tue, 8 Sep 2026 16:29:09 +0200 Subject: [PATCH 03/21] luci-app-strongswan-swanctl: sync debug option with swanctl init Add the 'syslog' option to bring the LuCI configuration model back in sync with 'swanctl.init', which already supports configuring syslog output. Remove the 'debug' option from the 'globals' section, as it no longer has any effect and is not evaluated by 'swanctl.init' anymore. Signed-off-by: Florian Eckert --- .../view/strongswan-swanctl/strongswan.js | 75 ++++++++++++++++++- 1 file changed, 71 insertions(+), 4 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js index 5f7be4cc40b2..5b9f87fbb839 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js @@ -3,6 +3,17 @@ 'require view'; 'require tools.widgets as widgets'; +function addLogLevel(o) { + o.value('', _('Use daemon default')); + o.value('-1', _('Absolutely silent')); + o.value('0', _('Very basic auditing logs')); + o.value('1', _('Generic control flow with errors (default)')); + o.value('2', _('More detailed debugging control flow')); + o.value('3', _('Including RAW data dumps in hex')); + o.value('4', _('Also include sensitive material in dumps, e.g. keys')); + o.default = ''; +} + return view.extend({ render: function (result) { let m, s, o; @@ -22,10 +33,66 @@ return view.extend({ o.nocreate = true; o.optional = true; - o = s.option(form.Value, 'debug', _('Debug Level'), - _('Trace level: 0 is least verbose, 4 is most')); - o.default = '0'; - o.datatype = 'range(0,4)'; + // syslog plugin settings + s = m.section(form.NamedSection, 'syslog', 'syslog', _('Syslog Settings'), + _('Configure how strongswan logs events, errors, and debug information.')); + + o = s.option(form.ListValue, 'app', 'app', _('Applications other than daemons')); + addLogLevel(o); + + o = s.option(form.ListValue, 'asn', 'asn', _('Low-level encoding/decoding (ASN.1, X.509 etc.)')); + addLogLevel(o); + + o = s.option(form.ListValue, 'cfg', 'cfg', _('Configuration management and plugins')); + addLogLevel(o); + + o = s.option(form.ListValue, 'chd', 'chd', _('CHILD_SA/IPsec_SA')); + addLogLevel(o); + + o = s.option(form.ListValue, 'dmn', 'dmn', _('Main daemon setup/cleanup/signal handling')); + addLogLevel(o); + + o = s.option(form.ListValue, 'enc', 'enc', _('Packet encoding/decoding encryption/decryption operations')); + addLogLevel(o); + + o = s.option(form.ListValue, 'esp', 'esp', '%s (%s)'.format(_('Library messages'), 'libipsec')); + addLogLevel(o); + + o = s.option(form.ListValue, 'ike', 'ike', _('IKE_SA / ISAKMP SA')); + addLogLevel(o); + + o = s.option(form.ListValue, 'imc', 'imc', _('Integrity Measurement Collector')); + addLogLevel(o); + + o = s.option(form.ListValue, 'imv', 'imv', _('Integrity Measurement Verifier')); + addLogLevel(o); + + o = s.option(form.ListValue, 'job', 'job', _('Jobs queuing/processing and thread pool management')); + addLogLevel(o); + + o = s.option(form.ListValue, 'wch', 'wch', _('File descriptor watcher')); + addLogLevel(o); + + o = s.option(form.ListValue, 'knl', 'knl', _('IPsec/Networking kernel interface')); + addLogLevel(o); + + o = s.option(form.ListValue, 'lib', 'lib', '%s (%s)'.format(_('Library messages'), 'libstrongswan')); + addLogLevel(o); + + o = s.option(form.ListValue, 'mgr', 'mgr', _('IKE_SA manager, handling synchronization for IKE_SA access')); + addLogLevel(o); + + o = s.option(form.ListValue, 'net', 'net', _('IKE network communication')); + addLogLevel(o); + + o = s.option(form.ListValue, 'pts', 'pts', _('Platform Trust Service')); + addLogLevel(o); + + o = s.option(form.ListValue, 'tls', 'tls', '%s (%s)'.format(_('Library messages'), 'libtls')); + addLogLevel(o); + + o = s.option(form.ListValue, 'tnc', 'tnc', _('Trusted Network Connect')); + addLogLevel(o); return m.render(); } From e5abca8ad0c0f37079af9580e5503b1366eac5b6 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Wed, 9 Sep 2026 12:27:20 +0200 Subject: [PATCH 04/21] luci-app-strongswan-swanctl: add support for custom_proposal configuration This commit adds a new checkbox and input field in the LuCI interface, allowing users to enable and define a custom IKE/IPsec proposal. - Added a toggle for `custom_proposal` in the 'crypto_proposal' section. - Added a text input field for the proposal string (visible only when enabled) - Included a warning in the help text about potential risks and lack of upgrade support This enables advanced users to manually configure proposals directly from the LuCI web interface, improving flexibility for specialized setups. Signed-off-by: Florian Eckert --- .../view/strongswan-swanctl/swanctl.js | 20 ++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 754060d1009b..35dde0db5743 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -459,19 +459,32 @@ return view.extend({ o = s.option(form.Flag, 'is_esp', _('ESP Proposal'), _('Whether this is an ESP (phase 2) proposal or not')); + o = s.option(form.Flag, 'use_custom_proposal', _('Use custom proposal'), + _('When enabled, you can specify your own proposal string.')); + o.default = '0'; + o.rmempty = true; + + o = s.option(form.Value, 'custom_proposal', _('Custom proposal'), + _('Using this option only if you know exactly what you are doing.') + '
' + + _('Manually defining a proposal can break compatibility with peers or cause connection failures.') + '
' + + _('Using this setting may prevent future updates or migrations.') + '
' + + _('You are responsible for maintaining compatibility!')); + o.depends('use_custom_proposal', '1'); + o.rmempty = false; + o = s.option(form.ListValue, 'encryption_algorithm', _('Encryption Algorithm'), _('Algorithms marked with * are considered insecure')); o.default = 'aes256gcm128'; + o.depends('use_custom_proposal', '0'); addAlgorithms(o, algorithms.encryption); addAlgorithms(o, algorithms.aead); - const encryptionAlgorithmNames = algorithms.encryption?.map(algorithm => algorithm.name); o = s.option(form.ListValue, 'hash_algorithm', _('Hash Algorithm'), _('Algorithms marked with * are considered insecure')); encryptionAlgorithmNames?.forEach(function (algorithmName) { - o.depends('encryption_algorithm', algorithmName); + o.depends({'encryption_algorithm': algorithmName, 'use_custom_proposal': '0'}); }); o.default = 'sha512'; o.rmempty = false; @@ -480,6 +493,7 @@ return view.extend({ o = s.option(form.ListValue, 'dh_group', _('Diffie-Hellman Group'), _('Algorithms marked with * are considered insecure')); o.default = 'modp3072'; + o.depends('use_custom_proposal', '0'); addAlgorithms(o, algorithms.ke); o = s.option(form.ListValue, 'prf_algorithm', _('PRF Algorithm'), @@ -495,7 +509,7 @@ return view.extend({ return true; }; o.optional = true; - o.depends('is_esp', '0'); + o.depends({'is_esp': '0', 'use_custom_proposal': '0'}); addAlgorithms(o, algorithms.prf); return m.render(); From 1096dfc7dab9f5614e7ad2bd8efc3de6d5895c77 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Thu, 10 Sep 2026 11:41:43 +0200 Subject: [PATCH 05/21] luci-app-strongswan-swanctl: rename dpdaction to dpd_action, drop "none" Update form field to match the renamed 'dpd_action' uci option. Remove the 'none' choice from the dropdown, since it has no swanctl equivalent and is no longer accepted by the backend. If nothing is specified, 'clear' is used by default in strongswan. Therefore, this is not included in the configuration. Signed-off-by: Florian Eckert --- .../resources/view/strongswan-swanctl/swanctl.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 35dde0db5743..e4f4d3683ba6 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -360,12 +360,13 @@ return view.extend({ o.datatype = 'file'; o.modalonly = true; - o = s.taboption('advanced', form.ListValue, 'dpdaction', _('DPD Action'), + o = s.taboption('advanced', form.ListValue, 'dpd_action', _('DPD Action'), _('Action when DPD timeout occurs')); - o.value('none'); - o.value('clear'); + o.value('', '%s (%s)'.format('clear', _('default'))); o.value('trap'); o.value('start'); + o.default = 'clear'; + o.rmempty = true; o.optional = true; o.modalonly = true; From 73e0b5c41005ca28117f8c0162d128588d2987cb Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Thu, 10 Sep 2026 12:06:16 +0200 Subject: [PATCH 06/21] luci-app-strongswan-swanctl: rename closeaction to close_action Update form field to match the renamed 'close_action' uci option. An empty field now defaults to 'none', matching the 'swanctl.conf'. An empty value is also not stored in the uci. Signed-off-by: Florian Eckert --- .../resources/view/strongswan-swanctl/swanctl.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index e4f4d3683ba6..a292120a070a 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -325,12 +325,14 @@ return view.extend({ o.default = 'trap'; o.modalonly = true; - o = s.taboption('general', form.ListValue, 'closeaction', _('Close Action'), + o = s.taboption('general', form.ListValue, 'close_action', _('Close Action'), _('Action when CHILD_SA is closed')); - o.value('none'); + o.value('', '%s (%s)'.format('none', _('default'))); o.value('trap'); o.value('start'); o.optional = true; + o.default = ''; + o.rmempty = true; o.modalonly = true; o = s.taboption('general', form.MultiValue, 'crypto_proposal', @@ -365,7 +367,7 @@ return view.extend({ o.value('', '%s (%s)'.format('clear', _('default'))); o.value('trap'); o.value('start'); - o.default = 'clear'; + o.default = ''; o.rmempty = true; o.optional = true; o.modalonly = true; From 10e55ccd721405173afb73ab27aab8fe2f4f6c64 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Thu, 10 Sep 2026 12:41:39 +0200 Subject: [PATCH 07/21] luci-app-strongswan-swanctl: rename startaction to start_action Update form field to match the renamed 'start_action' uci option. An empty field now defaults to 'none', matching the 'swanctl.conf'. An empty value is also not stored in the uci. While we are at it also make this vaule optional. Signed-off-by: Florian Eckert --- .../resources/view/strongswan-swanctl/swanctl.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index a292120a070a..397241a01ecb 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -317,12 +317,14 @@ return view.extend({ o.optional = true; o.modalonly = true; - o = s.taboption('general', form.ListValue, 'startaction', _('Start Action'), + o = s.taboption('general', form.ListValue, 'start_action', _('Start Action'), _('Action on initial configuration load')); - o.value('none'); + o.value('', '%s (%s)'.format('none', _('default'))); o.value('trap'); o.value('start'); - o.default = 'trap'; + o.optional = true; + o.default = ''; + o.rmempty = true; o.modalonly = true; o = s.taboption('general', form.ListValue, 'close_action', _('Close Action'), From 020f59a63f31c7e63c421934e92fb08549130ac4 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:00:04 +0200 Subject: [PATCH 08/21] luci-app-strongswan-swanctl: rename rekeytime to rekey_time in child Rename the 'rekeytime' option to 'rekey_time' in the uci section type 'child' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 397241a01ecb..beef35c3f046 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -374,7 +374,7 @@ return view.extend({ o.optional = true; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'rekeytime', _('Rekey Time'), + o = s.taboption('advanced', form.Value, 'rekey_time', _('Rekey Time'), _('Interval before a CHILD_SA is rekeyed.') + ' ' + _('Also used to derive lifetime (110% of this value).') + '
' + _('If not configured, the default value is "1h".') From 8023e158d95a5e31b5b03cade97fce0bb83ea16f Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:02:11 +0200 Subject: [PATCH 09/21] luci-app-strongswan-swanctl: rename lifetime to life_time in child Rename the 'lifetime' option to 'life_time' in the uci section type 'child' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index beef35c3f046..d5646adf5c5c 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -384,7 +384,7 @@ return view.extend({ o.rmempty = true; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'lifetime', _('Life Time'), + o = s.taboption('advanced', form.Value, 'life_time', _('Life Time'), _('Maximum time before the CHILD_SA gets closed, as a hard limit.') ); o.validate = validateTimeFormat; From 5b0b85fc1221214fceed06b92a561fbbec157c61 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:08:07 +0200 Subject: [PATCH 10/21] luci-app-strongswan-swanctl: rename rekeybytes to rekey_bytes in child Rename the 'rekeybytes' option to 'rekey_bytes' in the uci section type 'child' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index d5646adf5c5c..a8e1b68611d8 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -415,7 +415,7 @@ return view.extend({ o.datatype = 'uinteger'; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'rekeybytes', _('Rekey Bytes'), + o = s.taboption('advanced', form.Value, 'rekey_bytes', _('Rekey Bytes'), _('Number of bytes processed before initiating CHILD_SA rekeying.') + ' ' + _('Also used to derive lifebytes if set (110% of this value).') + ' ' + _('Use "0" to disable byte based rekeying.') From 602d86b44650236d74240f4bcb3fc98c4f12f379 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:08:13 +0200 Subject: [PATCH 11/21] luci-app-strongswan-swanctl: rename lifebytes to life_bytes in child Rename the 'lifebytes' option to 'life_bytes' in the uci section type 'child' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index a8e1b68611d8..d4ceaa8f0677 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -425,7 +425,7 @@ return view.extend({ o.rmempty = true; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'lifebytes', _('Life Bytes'), + o = s.taboption('advanced', form.Value, 'life_bytes', _('Life Bytes'), _('Maximum number of bytes processed before the CHILD_SA gets closed.') + ' ' + _('Use "0" to disable (default).') ); From 49b12223253c779319651ff1282e4b33e3cf2891 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:08:19 +0200 Subject: [PATCH 12/21] luci-app-strongswan-swanctl: rename rekeypackets to rekey_packets in child Rename the 'rekeypackets' option to 'rekey_packets' in the uci section type 'child' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index d4ceaa8f0677..b39a50baee4c 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -434,7 +434,7 @@ return view.extend({ o.rmempty = true; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'rekeypackets', _('Rekey Packets'), + o = s.taboption('advanced', form.Value, 'rekey_packets', _('Rekey Packets'), _('Number of packets processed before initiating CHILD_SA rekeying.') + ' ' + _('Also used to derive lifepackets if set (110% of this value).') + ' ' + _('Use "0" to disable packet based rekeying (default).') From 9feac94226ff271455dadf79be5cf2b99bff737d Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:08:29 +0200 Subject: [PATCH 13/21] luci-app-strongswan-swanctl: rename lifepackets to life_packets in child Rename the 'lifepackets' option to 'life_packets' in the uci section type 'child' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index b39a50baee4c..4a73ee8197d5 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -444,7 +444,7 @@ return view.extend({ o.rmempty = true; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'lifepackets', _('Life Packets'), + o = s.taboption('advanced', form.Value, 'life_packets', _('Life Packets'), _('Maximum number of packets processed before the CHILD_SA gets closed.') + ' ' + _('Use "0" to disable (default).') ); From ecc49340fcc75533954bfc01fc985399aef018cb Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:08:34 +0200 Subject: [PATCH 14/21] luci-app-strongswan-swanctl: rename rekeytime to rekey_time in remote Rename the 'rekeytime' option to 'rekey_time' in the uci section type 'remote' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 4a73ee8197d5..88fbaf1c47f6 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -243,7 +243,7 @@ return view.extend({ o.placeholder = '0s'; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'rekeytime', _('Rekey Time'), + o = s.taboption('advanced', form.Value, 'rekey_time', _('Rekey Time'), _('IKEv2 interval to refresh keying material; also used to compute lifetime')); o.validate = validateTimeFormat; o.modalonly = true; From 655b569ca112320213c3faacb4c154e76c2e5fe8 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:08:38 +0200 Subject: [PATCH 15/21] luci-app-strongswan-swanctl: rename overtime to over_time in remote Rename the 'overtime' option to 'over_time' in the uci section type 'remote' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 88fbaf1c47f6..d4f5bd72a9c7 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -248,7 +248,7 @@ return view.extend({ o.validate = validateTimeFormat; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'overtime', _('Overtime'), + o = s.taboption('advanced', form.Value, 'over_time', _('Overtime'), _('Limit on time to complete rekeying/reauthentication')); o.validate = validateTimeFormat; o.modalonly = true; From c771181b033032eb0f56f39d32c6acf242166522 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 11 Sep 2026 12:08:59 +0200 Subject: [PATCH 16/21] luci-app-strongswan-swanctl: rename dpddelay to dpd_delay in remote Rename the 'dpddelay' option to 'dpd_delay' in the uci section type 'remote' to follow the naming convention and improve consistency with 'swanctl.conf' terminology. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index d4f5bd72a9c7..6b29fa70656a 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -231,7 +231,7 @@ return view.extend({ o.placeholder = '3'; o.modalonly = true; - o = s.taboption('advanced', form.Value, 'dpddelay', _('DPD Delay'), + o = s.taboption('advanced', form.Value, 'dpd_delay', _('DPD Delay'), _('Interval to check liveness of a peer')); o.validate = validateTimeFormat; o.placeholder = '30s'; From 472ea6e8313d1e9a97c9000251485284a4f17f84 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Mon, 21 Sep 2026 09:52:22 +0200 Subject: [PATCH 17/21] luci-app-strongswan-swanctl: add shunt configuration Add a new uci shunt section type for pass | drop policies, independent of remote connections. The uci support for this feature has already been added to the strongswan package, this change adds the matching configuration to LuCI. New supported options: * mode (pass/drop) * local_ts * remote_ts * priority * interface This change also include shunt sections in the section name uniqueness check. Signed-off-by: Florian Eckert --- .../view/strongswan-swanctl/swanctl.js | 37 ++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 6b29fa70656a..560b278240a3 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -38,12 +38,13 @@ function sectionNameCheck(extra_class) { let sections = [ ...uci.sections('ipsec', 'remote'), ...uci.sections('ipsec', 'child'), + ...uci.sections('ipsec', 'shunt'), ...uci.sections('ipsec', 'crypto_proposal'), ]; if (sections.find(function(s) { return s['.name'] == v; })) { - return _('Remotes, Encryption Proposals and Children may not share the same names.') + ' ' + + return _('Remotes, Encryption Proposals, Children and Shunts may not share the same names.') + ' ' + _('Use combinations like child1_phase1 that do not exceed 15 characters.'); } if (v.length > 15) return _('Name length shall not exceed 15 characters'); @@ -453,6 +454,40 @@ return view.extend({ o.rmempty = true; o.modalonly = true; + // Shunt Configuration + s = m.section(form.GridSection, 'shunt', _('Shunt Configuration'), + _('Define Shunt pass/drop policies independent of remote connections.')); + s.addremove = true; + s.nodescriptions = true; + s.renderSectionAdd = sectionNameCheck; + + o = s.option(form.Flag, 'enabled', _('Enabled'), + _('Configuration is enabled or not')); + o.rmempty = false; + + o = s.option(form.ListValue, 'mode', _('Mode'), + _('Shunt policy mode')); + o.value('pass', _('Pass')); + o.value('drop', _('Drop')); + o.rmempty = false; + + o = s.option(form.DynamicList, 'local_ts', _('Local Traffic Selectors'), + _('Local traffic selectors for the shunt policy')); + o.datatype = 'or(cidr,ipaddr)'; + + o = s.option(form.DynamicList, 'remote_ts', _('Remote Traffic Selectors'), + _('Remote traffic selectors for the shunt policy')); + o.datatype = 'or(cidr,ipaddr)'; + + o = s.option(form.Value, 'priority', _('Priority'), + _('Priority of the shunt policy (lower number means higher priority)')); + o.datatype = 'uinteger'; + o.modalonly = true; + + o = s.option(form.Value, 'interface', _('Interface'), + _('Network interface to bind the shunt policy to')); + o.modalonly = true; + // Crypto Proposals s = m.section(form.GridSection, 'crypto_proposal', _('Encryption Proposals'), From 52c2512b97a4b4ca11235ddfb7c79040c3780498 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Mon, 14 Sep 2026 12:01:38 +0200 Subject: [PATCH 18/21] luci-app-strongswan-swanctl: add install_routes_xfrmi option Add support for the 'kernel-netlink' plugin option 'install_routes_xfrmi' to 'luci-app-strongswan-swanctl'. When enabled, charon installs routes for all XFRM interfaces based on the traffic selectors of installed IPsec SAs, which is required for route-based VPN setups using XFRM interfaces. Signed-off-by: Florian Eckert --- .../resources/view/strongswan-swanctl/strongswan.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js index 5b9f87fbb839..02905771bc0f 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js @@ -94,6 +94,14 @@ return view.extend({ o = s.option(form.ListValue, 'tnc', 'tnc', _('Trusted Network Connect')); addLogLevel(o); + // kernel-netlink plugin settings + s = m.section(form.NamedSection, 'netlink', 'netlink', _('Netlink Settings'), + _('Configure the kernel-netlink plugin options.')); + + o = s.option(form.Flag, 'install_routes_xfrmi', _('Install routes via XFRM interfaces'), + _('When this is enabled, the routes for all XFRM interfaces are set automatically.')); + o.default = '0'; + return m.render(); } }); From 97f5a49a76560bdf5db1874a11cee6c7b53e6155 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Mon, 21 Sep 2026 10:13:21 +0200 Subject: [PATCH 19/21] luci-app-strongswan-swanctl: remove 15 char section name limit The 'swanctl.conf' does not impose any length restriction on connection and children (section) names. They are plain strings parsed by strongswan config parser without a fixed-size buffer. Likewise, uci does not enforce a maximum length for named sections. libuci's uci_validate_str() only restricts the allowed character set (alphanumeric and underscore, for shell compatibility) and allocates section names dynamically via strdup(), so there is no built-in buffer size that would truncate or reject longer names. The previous 15-character cap therefore had no basis in either 'swanctl.conf' or uci itself and can be dropped without risking truncation, parsing errors, or incompatibility. Signed-off-by: Florian Eckert --- .../luci-static/resources/view/strongswan-swanctl/swanctl.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 560b278240a3..03cd63e73747 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -45,9 +45,8 @@ function sectionNameCheck(extra_class) { return s['.name'] == v; })) { return _('Remotes, Encryption Proposals, Children and Shunts may not share the same names.') + ' ' + - _('Use combinations like child1_phase1 that do not exceed 15 characters.'); + _('Use combinations like child1_phase1.'); } - if (v.length > 15) return _('Name length shall not exceed 15 characters'); return true; }, 'blur', 'keyup'); return el; From 50f5a69c40f0aa549f2b3e82ba20c5c29e59e4f7 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Thu, 17 Sep 2026 16:11:43 +0200 Subject: [PATCH 20/21] luci-app-strongswan-swanctl: switch from ipsec to swanctl config This updates luci-app-strongswan-swanctl to use the '/etc/config/swanctl' configuration instead of the legacy ipsec configuration. The change is required to align with the '/etc/init.d/swanctl' script. Signed-off-by: Florian Eckert --- .../view/strongswan-swanctl/strongswan.js | 2 +- .../resources/view/strongswan-swanctl/swanctl.js | 16 ++++++++-------- .../rpcd/acl.d/luci-app-strongswan-swanctl.json | 4 ++-- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js index 02905771bc0f..bc4e0aed8b52 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/strongswan.js @@ -18,7 +18,7 @@ return view.extend({ render: function (result) { let m, s, o; - m = new form.Map('ipsec', _('Service configuration'), + m = new form.Map('swanctl', _('Service configuration'), _('On this page, you can configure the IPsec service.')); m.tabbed = true; diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 03cd63e73747..60613e7db71c 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -36,10 +36,10 @@ function sectionNameCheck(extra_class) { nameEl = el.querySelector('.cbi-section-create-name'); ui.addValidator(nameEl, 'uciname', true, function(v) { let sections = [ - ...uci.sections('ipsec', 'remote'), - ...uci.sections('ipsec', 'child'), - ...uci.sections('ipsec', 'shunt'), - ...uci.sections('ipsec', 'crypto_proposal'), + ...uci.sections('swanctl', 'remote'), + ...uci.sections('swanctl', 'child'), + ...uci.sections('swanctl', 'shunt'), + ...uci.sections('swanctl', 'crypto_proposal'), ]; if (sections.find(function(s) { return s['.name'] == v; @@ -66,7 +66,7 @@ return view.extend({ if (error) ui.addNotification(null, E('p', _('Some options are unavailable because swanctl failed to load: %s').format(error)), 'warning'); - m = new form.Map('ipsec', _('Connection configurations'), + m = new form.Map('swanctl', _('Connection configurations'), _('On this page, you can configure the IPsec connections.')); m.tabbed = true; @@ -109,7 +109,7 @@ return view.extend({ this.keylist = []; this.vallist = []; - var sections = uci.sections('ipsec', 'crypto_proposal').filter(function (section) { + var sections = uci.sections('swanctl', 'crypto_proposal').filter(function (section) { return section.is_esp != '1'; }); if (sections.length == 0) { @@ -130,7 +130,7 @@ return view.extend({ this.keylist = []; this.vallist = []; - var sections = uci.sections('ipsec', 'child'); + var sections = uci.sections('swanctl', 'child'); if (sections.length == 0) { this.value('', _('Please create a Children first')); } else { @@ -344,7 +344,7 @@ return view.extend({ this.keylist = []; this.vallist = []; - var sections = uci.sections('ipsec', 'crypto_proposal').filter(function (section) { + var sections = uci.sections('swanctl', 'crypto_proposal').filter(function (section) { return section.is_esp == '1'; }); if (sections.length == 0) { diff --git a/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json b/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json index 7407183247be..e04d516cd7c9 100644 --- a/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json +++ b/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json @@ -9,7 +9,7 @@ "ubus": { "luci.swanctl": [ "list-algs", "map-conns" ] }, - "uci": [ "ipsec" ] + "uci": [ "swanctl" ] }, "write": { "file": { @@ -18,7 +18,7 @@ "/usr/sbin/swanctl --terminate --ike *": [ "exec" ], "/usr/sbin/swanctl --terminate --child *": [ "exec" ] }, - "uci": [ "ipsec" ] + "uci": [ "swanctl" ] } } } From d5d9a4e17d91a12e141c3e23f8fc7a1384e555b0 Mon Sep 17 00:00:00 2001 From: Florian Eckert Date: Fri, 18 Sep 2026 13:48:06 +0200 Subject: [PATCH 21/21] luci-app-strongswan-swanctl: add legacy ipsec config migration overlay The strongswan-swanctl view now checks on load whether a legacy ipsec configuration exists in '/etc/config/ipsec'. If the file is present, a blocking overlay is shown on the connection page which offers to run the command '/etc/init.d/swanctl migrate'. While the migration is pending, the page action footer (Save & Apply, Apply and Revert buttons) is disabled and the main content area is not clickable, so that no changes can be made to the empty swanctl configuration before the migration has finished. A successful migration reloads the page, while a failed migration is reported with the option to retry. To allow the view to detect the legacy configuration and trigger the migration, the rpc ACLs are extended with a list permission on '/etc/config/ipsec' and the exec permission for the migration command. Signed-off-by: Florian Eckert --- .../view/strongswan-swanctl/swanctl.js | 85 ++++++++++++++++++- .../acl.d/luci-app-strongswan-swanctl.json | 2 + 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js index 60613e7db71c..09c857d9c1b8 100644 --- a/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js +++ b/applications/luci-app-strongswan-swanctl/htdocs/luci-static/resources/view/strongswan-swanctl/swanctl.js @@ -4,6 +4,7 @@ 'require rpc'; 'require uci'; 'require ui'; +'require fs'; const callListAlgorithms = rpc.declare({ object: 'luci.swanctl', @@ -52,16 +53,87 @@ function sectionNameCheck(extra_class) { return el; }; +let migrationOverlay = null; + +function renderMigrationContent(errorMessage) { + const dialog = migrationOverlay.firstElementChild; + const migrateButton = E('button', { + 'class': 'btn cbi-button cbi-button-apply', + 'click': handleMigrate + }, [_('Migrate')]); + + const content = E([], [ + E('h4', _('Migrate IPsec configuration')), + E('p', _('A legacy IPsec configuration was found.') + ' ' + + _('It must be migrated from the uci config \'/etc/config/ipsec\' ' + + 'to \'/etc/config/swanctl\' before it can be managed here.')), + E('p', _('After a successful migration, the file \'/etc/config/ipsec\' is moved to \'/etc/config/ipsec.bak\'.') + ' ' + + _('The migration may require manual intervention.') + ' ' + + _('Therefore, the VPN is not restarted.')), + E('p', _('Warning: The migration will drop all IPsec VPN connections.')), + E('p', _('This will execute the command \'/etc/init.d/swanctl migrate\'.')) + ]); + + if (errorMessage) + content.appendChild(E('p', errorMessage)); + + content.appendChild(E('div', { 'class': 'right' }, [migrateButton])); + + dialog.replaceChildren(content); +} + +function showMigrationOverlay(viewNode) { + if (migrationOverlay) + return; + + const dialog = E('div', { 'class': 'modal', 'style': 'margin:0;' }); + migrationOverlay = E('div', { + 'class': 'migration-overlay', + 'style': 'position:absolute;top:0;right:0;bottom:0;left:0;z-index:900;display:flex;align-items:center;justify-content:center;padding:1em;pointer-events:all;' + }, [dialog]); + + viewNode.style.position = 'relative'; + viewNode.appendChild(migrationOverlay); + + const maincontent = document.getElementById('maincontent'); + if (maincontent) + maincontent.style.pointerEvents = 'none'; + + renderMigrationContent(null); +} + +function handleMigrate() { + const dialog = migrationOverlay.firstElementChild; + + dialog.replaceChildren(E([], [ + E('h4', _('Migrate IPsec configuration')), + E('p', _('Migrating IPsec configuration…')) + ])); + + fs.exec('/etc/init.d/swanctl', ['migrate']).then(function (result) { + if (result.code != 0) + renderMigrationContent(_('Migration failed: %s').format(result.stderr || result.stdout || _('unknown error'))); + else + window.location.reload(); + }).catch(function (e) { + renderMigrationContent(_('Migration failed: %s').format(e.message)); + }); +} + return view.extend({ load: async function () { await uci.load('network'); - return await callListAlgorithms(); + const algorithms = await callListAlgorithms(); + const legacyConfig = await L.resolveDefault(fs.stat('/etc/config/ipsec'), null); + + return { algorithms, legacyConfig }; }, render: function (result) { let m, s, o; - const algorithms = result.data ?? {}; - const error = result.error; + const legacyConfig = !!result.legacyConfig; + const algorithms = result.algorithms.data ?? {}; + const error = result.algorithms.error; if (error) ui.addNotification(null, E('p', _('Some options are unavailable because swanctl failed to load: %s').format(error)), 'warning'); @@ -551,6 +623,11 @@ return view.extend({ o.depends({'is_esp': '0', 'use_custom_proposal': '0'}); addAlgorithms(o, algorithms.prf); - return m.render(); + return m.render().then(function (node) { + if (legacyConfig) + showMigrationOverlay(node); + + return node; + }); } }); diff --git a/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json b/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json index e04d516cd7c9..22290c45c005 100644 --- a/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json +++ b/applications/luci-app-strongswan-swanctl/root/usr/share/rpcd/acl.d/luci-app-strongswan-swanctl.json @@ -3,6 +3,7 @@ "description": "Grant access to luci-app-strongswan-swanctl", "read": { "file": { + "/etc/config/ipsec": [ "list" ], "/usr/sbin/swanmon version": [ "exec" ], "/usr/sbin/swanmon stats": [ "exec" ] }, @@ -13,6 +14,7 @@ }, "write": { "file": { + "/etc/init.d/swanctl migrate": [ "exec" ], "/usr/sbin/swanctl --initiate --ike *": [ "exec" ], "/usr/sbin/swanctl --initiate --child *": [ "exec" ], "/usr/sbin/swanctl --terminate --ike *": [ "exec" ],