From 670a7b3b0ebee25b76d78d6387be1bcb7ae9e676 Mon Sep 17 00:00:00 2001 From: Hauke Mehrtens Date: Sat, 3 Oct 2026 22:54:31 +0200 Subject: [PATCH] strongswan: stage the migration in the LuCI session through ubus When LuCI passes a session id, migrate-ipsec-to-swanctl moves its uci delta into /tmp/run/rpcd/uci-, rpcd's private save directory of that session. rpcd stops naming this directory after the session id, as the id is a bearer credential that leaked through directory listings, so the migrated configuration would no longer show up as pending changes in LuCI. Stage the migration through rpcd's uci ubus API instead: revert the session's ipsec changes, delete all sections and add the sections of the migrated configuration. Then revert the changes of the uci command line tool, which the old code moved away. This works with old and new rpcd versions. If staging fails, both are reverted and the script exits with an error. Fixes: d5f33e6410cf ("strongswan: support optional UCI session staging in migrate-ipsec-to-swanctl") Assisted-by: Claude:claude-opus-5-5 Signed-off-by: Hauke Mehrtens --- net/strongswan/Makefile | 2 +- .../strongswan/migrate-ipsec-to-swanctl | 103 ++++++++++++++++-- 2 files changed, 96 insertions(+), 9 deletions(-) diff --git a/net/strongswan/Makefile b/net/strongswan/Makefile index ad1b034b4b..85076d4fc9 100644 --- a/net/strongswan/Makefile +++ b/net/strongswan/Makefile @@ -9,7 +9,7 @@ include $(TOPDIR)/rules.mk PKG_NAME:=strongswan PKG_VERSION:=6.0.7 -PKG_RELEASE:=8 +PKG_RELEASE:=9 PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.bz2 PKG_SOURCE_URL:=https://download.strongswan.org/ https://download2.strongswan.org/ diff --git a/net/strongswan/files/usr/libexec/strongswan/migrate-ipsec-to-swanctl b/net/strongswan/files/usr/libexec/strongswan/migrate-ipsec-to-swanctl index f610382397..68c4d6d488 100644 --- a/net/strongswan/files/usr/libexec/strongswan/migrate-ipsec-to-swanctl +++ b/net/strongswan/files/usr/libexec/strongswan/migrate-ipsec-to-swanctl @@ -1,6 +1,8 @@ #!/bin/sh . /lib/functions.sh +. /usr/share/libubox/jshn.sh + migrate_ipsec() { # Skip migration if the 'globals' section already exists uci show ipsec.globals 1>/dev/null 2>/dev/null @@ -569,14 +571,89 @@ migrate_child_subnet_to_ts() { config_foreach migrate_subnet_to_ts child remote_subnet remote_ts } -main() { +session_uci() { + local session="$1" + local method="$2" + + json_add_string config ipsec + json_add_string ubus_rpc_session "$session" + ubus call uci "$method" "$(json_dump)" 2>/dev/null +} + +# Stage the migrated configuration as pending changes of the given LuCI +# session. rpcd does not expose where it keeps the changes of a session, +# so replace the configuration section by section through its uci ubus +# API. +stage_session() { local session="$1" - #If LuCI provides a session ID, it can be marked 'staging,' allowing - # migration without an immediate restart. - [ -n "$session" ] && { - mkdir -p /tmp/run/rpcd/uci-${session} - } + local data section sections + + # The migrated configuration including the changes staged above. + # Do not name anonymous sections, so that they stay anonymous. + data="$(uci -q -S -N export ipsec)" || return 1 + + json_init + session_uci "$session" revert >/dev/null || return 1 + + json_init + sections="$(session_uci "$session" get)" || return 1 + json_load "$sections" + json_select values + json_get_keys sections + + for section in $sections; do + json_init + json_add_string section "$section" + session_uci "$session" delete >/dev/null || return 1 + done + + # Add the sections of the migrated configuration. Run in a subshell, + # as the config, option and list handlers of /lib/functions.sh are + # replaced for evaluating the export. + ( + sec_type= + cur_list= + + add_section() { + [ -n "$sec_type" ] || return 0 + [ -n "$cur_list" ] && json_close_array + json_close_object + session_uci "$session" add >/dev/null || exit 1 + } + + config() { + add_section + sec_type="$1" + cur_list= + json_init + json_add_string type "$1" + [ -n "$2" ] && json_add_string name "$2" + json_add_object values + } + + option() { + [ -n "$cur_list" ] && json_close_array + cur_list= + json_add_string "$1" "$2" + } + + list() { + [ "$cur_list" = "$1" ] || { + [ -n "$cur_list" ] && json_close_array + cur_list="$1" + json_add_array "$1" + } + json_add_string "" "$2" + } + + eval "$data" + add_section + ) +} + +main() { + local session="$1" [ -f /etc/config/ipsec ] || { echo "File '/etc/config/ipsec' does not exists." @@ -606,9 +683,19 @@ main() { migrate_connections_local_remote migrate_child_subnet_to_ts - # Move staged migration changes to LuCI + # If LuCI provides a session ID, hand the migration over to it as + # pending changes, allowing to review and apply it in LuCI without an + # immediate restart. [ -n "$session" ] && { - mv /tmp/.uci/ipsec /tmp/run/rpcd/uci-${session} + if ! stage_session "$session"; then + json_init + session_uci "$session" revert >/dev/null + uci -q revert ipsec + echo "Failed to stage the migrated configuration in the LuCI session." >&2 + exit 1 + fi + + uci -q revert ipsec } exit 0