Defer configuration by default and manage vpn-router.conf with ucf

Add platform = none as the shipped default so installing the package
changes nothing on the machine until a platform is chosen. Add a mode
setting (manual/interfaces/auto) controlling how much of the network
configuration is supplied versus detected from the system. Manage
/etc/vpn-router/vpn-router.conf with ucf instead of writing it once,
so dpkg-reconfigure can safely reapply debconf answers without
clobbering local edits. Extend NAT/forward rules to all local subnets,
not just the first.
This commit is contained in:
2026-08-23 17:15:49 +02:00
parent 083ad9a596
commit 7cb2f1b8dd
14 changed files with 439 additions and 124 deletions
+35 -3
View File
@@ -2,13 +2,45 @@
set -e
. /usr/share/debconf/confmodule
# Every question has a default, so a non-interactive install with nothing
# preseeded completes without prompting. The defaults are platform "none" and
# mode "manual", which together mean: install the files, configure nothing.
db_input high vpn-router/platform || true
db_input high vpn-router/external_interface || true
db_input high vpn-router/internal_interface || true
db_go || true
db_get vpn-router/platform
if [ "$RET" = "none" ]; then
# Configuration is deferred. Asking anything else would collect answers
# that nothing is going to apply.
exit 0
fi
db_input high vpn-router/mode || true
db_go || true
# The mode says how much the operator supplies, so it decides which interface
# and address questions are worth asking.
db_get vpn-router/mode
case "$RET" in
manual)
db_input high vpn-router/external_interface || true
db_input high vpn-router/internal_interface || true
db_input high vpn-router/int_addr || true
db_input high vpn-router/int_gateway_ip || true
;;
interfaces)
db_input high vpn-router/external_interface || true
db_input high vpn-router/internal_interface || true
;;
auto)
;;
esac
db_go || true
db_input high vpn-router/local_fqdn || true
db_input high vpn-router/local_id_mode || true
db_input high vpn-router/local_cidrs || true
db_input high vpn-router/int_gateway_ip || true
db_input high vpn-router/remote_addrs || true
db_input high vpn-router/remote_id || true
db_input high vpn-router/remote_cidrs || true
+1
View File
@@ -16,6 +16,7 @@ Depends: ${misc:Depends},
wireguard-tools,
ufw,
debconf,
ucf,
openssl,
python3,
python3-jinja2,
+1 -1
View File
@@ -3,7 +3,7 @@ src/usr/lib/vpn-router/vpnrouter.py usr/lib/vpn-router/
src/usr/lib/vpn-router/simple-ca usr/lib/vpn-router/
src/usr/lib/vpn-router/configure usr/lib/vpn-router/
src/usr/lib/vpn-router/setup usr/lib/vpn-router/
src/usr/lib/vpn-router/seed-config usr/lib/vpn-router/
src/usr/lib/vpn-router/generate-config usr/lib/vpn-router/
src/usr/lib/vpn-router/vpnrouter_platforms/*.py usr/lib/vpn-router/vpnrouter_platforms/
src/usr/share/vpn-router/templates/* usr/share/vpn-router/templates/
src/usr/share/doc/vpn-router/vpn-router.conf.example usr/share/doc/vpn-router/
+17 -4
View File
@@ -6,6 +6,8 @@ case "$1" in
configure)
# --- Read the installer's answers ---
db_get vpn-router/platform; VPN_ROUTER_PLATFORM="$RET"
db_get vpn-router/mode; VPN_ROUTER_MODE="$RET"
db_get vpn-router/int_addr; VPN_ROUTER_INT_ADDR="$RET"
db_get vpn-router/external_interface; VPN_ROUTER_EXTERNAL_INTERFACE="$RET"
db_get vpn-router/internal_interface; VPN_ROUTER_INTERNAL_INTERFACE="$RET"
db_get vpn-router/local_fqdn; VPN_ROUTER_LOCAL_FQDN="$RET"
@@ -23,7 +25,8 @@ case "$1" in
db_get vpn-router/wg_address; VPN_ROUTER_WG_ADDRESS="$RET"
db_get vpn-router/wg_listen_port; VPN_ROUTER_WG_LISTEN_PORT="$RET"
export VPN_ROUTER_PLATFORM VPN_ROUTER_EXTERNAL_INTERFACE \
export VPN_ROUTER_PLATFORM VPN_ROUTER_MODE VPN_ROUTER_INT_ADDR \
VPN_ROUTER_EXTERNAL_INTERFACE \
VPN_ROUTER_INTERNAL_INTERFACE VPN_ROUTER_LOCAL_FQDN \
VPN_ROUTER_LOCAL_ID_MODE VPN_ROUTER_LOCAL_CIDRS \
VPN_ROUTER_INT_GATEWAY_IP \
@@ -33,10 +36,20 @@ case "$1" in
VPN_ROUTER_P2S_CA_NAME VPN_ROUTER_WG_ENABLED \
VPN_ROUTER_WG_ADDRESS VPN_ROUTER_WG_LISTEN_PORT
# --- Create the configuration file, only if it does not exist ---
/usr/lib/vpn-router/seed-config
# --- Hand a candidate configuration to ucf ---
# ucf compares it against the file in /etc and decides what to do about
# local changes, prompting through debconf only for a real conflict.
# This is what makes dpkg-reconfigure apply without destroying edits.
CANDIDATE="$(mktemp)"
/usr/lib/vpn-router/generate-config "$CANDIDATE"
ucf --three-way --debconf-ok "$CANDIDATE" /etc/vpn-router/vpn-router.conf
ucfr vpn-router /etc/vpn-router/vpn-router.conf
chmod 0600 /etc/vpn-router/vpn-router.conf
rm -f "$CANDIDATE"
# The key now lives in the configuration file; do not keep a copy.
# The key now lives in the configuration file; do not keep a copy. An
# empty answer means "leave alone" next time, so clearing it here does
# not blank the key on the next dpkg-reconfigure.
db_set vpn-router/psk ""
# Apply the sysctl drop-in shipped by this package so it takes effect
+9
View File
@@ -34,6 +34,15 @@ case "$1" in
purge)
strip_ufw_blocks
# Let ucf forget the file before it is removed, or a reinstall finds a
# stale hash and declines to lay the file down again.
if command -v ucf >/dev/null 2>&1; then
ucf --purge /etc/vpn-router/vpn-router.conf
fi
if command -v ucfr >/dev/null 2>&1; then
ucfr --purge vpn-router /etc/vpn-router/vpn-router.conf
fi
rm -f /etc/swanctl/conf.d/remote-site.conf \
/etc/swanctl/conf.d/road-warrior.conf \
/etc/systemd/resolved.conf.d/p2s-forwarder.conf \
+10 -2
View File
@@ -9,8 +9,16 @@ case "$1" in
if [ -d /run/systemd/system ]; then
swanctl --terminate --ike remote-site >/dev/null 2>&1 || true
swanctl --terminate --ike road-warrior >/dev/null 2>&1 || true
# This package enabled wg-quick@wg0, so it takes it down again.
systemctl disable --now wg-quick@wg0 >/dev/null 2>&1 || true
fi
# This package enabled wg-quick@wg0, so it takes it down again. Use the
# debhelper wrappers rather than systemctl, so the script behaves on a
# machine without systemd.
if command -v deb-systemd-invoke >/dev/null 2>&1; then
deb-systemd-invoke stop wg-quick@wg0.service >/dev/null 2>&1 || true
fi
if command -v deb-systemd-helper >/dev/null 2>&1; then
deb-systemd-helper disable wg-quick@wg0.service >/dev/null 2>&1 || true
fi
;;
esac
+53 -24
View File
@@ -1,34 +1,62 @@
Template: vpn-router/platform
Type: select
Choices: generic, azure, gcp
Default: generic
Description: Platform module
Platform-specific additions to load. The router works without any of them;
a module only adds what makes sense on its platform, such as the platform
DNS resolver for road-warrior clients.
Choices: none, generic, azure, gcp
Default: none
Description: Platform:
Which platform this router runs on. The choice loads platform-specific
additions, such as the provider DNS resolver for road-warrior clients.
.
none defers configuration entirely: the package installs its files and
changes nothing on the machine. Choose it when the router will be configured
later by hand or by a configuration-management tool, then set the platform in
/etc/vpn-router/vpn-router.conf when you are ready.
.
generic configures the router with no platform-specific additions.
Template: vpn-router/mode
Type: select
Choices: manual, interfaces, auto
Default: manual
Description: Network configuration source:
How much of the network configuration you are supplying, and therefore how
much the package works out for itself:
.
manual - you give the interface names, the internal address and the internal
gateway. Nothing is detected.
.
interfaces - you give the two interface names. The internal address and
gateway are read from them.
.
auto - you give nothing. The interfaces are identified from the routing
table and their addresses read from the system. Convenient, but it can pick
the wrong interface and configure the machine incorrectly.
Template: vpn-router/external_interface
Type: string
Default:
Description: External network interface
Description: External network interface:
Name of the interface facing the untrusted network, for example eth0 or
ens4. The addresses strongSwan binds on are read from it, so they are never
configured separately.
.
Leave empty to configure the router later by editing
/etc/vpn-router/vpn-router.conf.
Template: vpn-router/internal_interface
Type: string
Default:
Description: Internal network interface
Description: Internal network interface:
Name of the interface facing the protected network, for example eth1 or
ens5. Routes for the local subnets are applied to it.
Template: vpn-router/int_addr
Type: string
Default:
Description: Internal interface address:
This host's own address on the internal network. Asked only in manual mode;
in the other modes it is read from the internal interface.
Template: vpn-router/local_fqdn
Type: string
Default:
Description: Local router FQDN
Description: Local router FQDN:
Fully-qualified domain name of this router (for example
router.example.com). Used as the road-warrior server identity and
certificate common name.
@@ -37,7 +65,7 @@ Template: vpn-router/local_id_mode
Type: select
Choices: fqdn, public_ip, internal_ip
Default: fqdn
Description: IKE local identity mode
Description: IKE local identity mode:
How to derive the IKE identity advertised to the remote site:
.
fqdn - use the FQDN, which must match what the peer expects.
@@ -49,40 +77,41 @@ Description: IKE local identity mode
Template: vpn-router/local_cidrs
Type: string
Default:
Description: Local subnet CIDR(s)
Description: Local subnet CIDR(s):
Comma-separated list of local subnet CIDRs to advertise into the
site-to-site tunnel (for example 10.0.0.0/24 or 10.0.0.0/24,10.0.1.0/24).
Template: vpn-router/int_gateway_ip
Type: string
Default:
Description: Internal network gateway IP
Description: Internal network gateway address:
Address of the next-hop gateway on the internal side, used to route the
local subnets listed above.
local subnets listed above. Asked only in manual mode; in the other modes it
is derived from the internal interface.
Template: vpn-router/remote_addrs
Type: string
Default:
Description: Remote site WAN IP address(es)
Description: Remote site WAN IP address(es):
Comma-separated list of remote gateway addresses or FQDNs for the
site-to-site IPSec tunnel.
Template: vpn-router/remote_id
Type: string
Default:
Description: Remote site IKE identity
Description: Remote site IKE identity:
IKE identity of the remote peer, without a leading @.
Template: vpn-router/remote_cidrs
Type: string
Default:
Description: Remote subnet CIDR(s)
Description: Remote subnet CIDR(s):
Comma-separated list of remote subnet CIDRs reachable through the
site-to-site tunnel (for example 192.168.0.0/24).
Template: vpn-router/psk
Type: password
Description: Pre-shared key (PSK)
Description: Pre-shared key (PSK):
Pre-shared key for the site-to-site IKEv2 tunnel. Must match the value
configured on the remote peer. Stored base64-encoded in the configuration
file and cleared from the debconf database after installation.
@@ -98,13 +127,13 @@ Description: Enable road-warrior (P2S) access?
Template: vpn-router/p2s_address_pool
Type: string
Default:
Description: Road-warrior address pool
Description: Road-warrior address pool:
CIDR block assigned to road-warrior clients (for example 172.16.0.0/24).
Template: vpn-router/p2s_ca_name
Type: string
Default: VPN Router CA
Description: Road-warrior CA name
Description: Road-warrior CA name:
Common name for the certificate authority created in /etc/vpn-router/pki
when that directory is empty. Ignored when certificates are supplied.
@@ -119,12 +148,12 @@ Description: Enable WireGuard?
Template: vpn-router/wg_address
Type: string
Default:
Description: WireGuard interface address
Description: WireGuard interface address:
Address and prefix length for the wg0 interface (for example
192.168.200.1/24).
Template: vpn-router/wg_listen_port
Type: string
Default: 51820
Description: WireGuard listen port
Description: WireGuard listen port:
UDP port that WireGuard listens on.