Having scripts diddle user written config files seems potentially dangerous. Plus there's really no downside to including some empty files. Best to just make the includes be permanent. Additional feature suggested by Luiz: if a -opkg version of the config file was created unnecessarily, remove it as part of the upgrade process since changes won't be happening to that file as an artifact of the service starting. The include lines are now permanent, which means that (1) additional configuration synthesized by UCI won't be anywhere that opkg (or sysupgrade, for that matter) cares about since it won't be persistent, and (2) if changes are being made, then they're being done by a person with an editor and they really should be distinguished. Signed-off-by: Philip Prindeville <philipp@redfish-solutions.com>
366 lines
9.7 KiB
Bash
366 lines
9.7 KiB
Bash
#!/bin/sh /etc/rc.common
|
|
|
|
START=90
|
|
STOP=10
|
|
|
|
USE_PROCD=1
|
|
PROG=/usr/lib/ipsec/starter
|
|
|
|
. $IPKG_INSTROOT/lib/functions.sh
|
|
. $IPKG_INSTROOT/lib/functions/network.sh
|
|
|
|
IPSEC_SECRETS_FILE=/etc/ipsec.secrets
|
|
IPSEC_CONN_FILE=/etc/ipsec.conf
|
|
STRONGSWAN_CONF_FILE=/etc/strongswan.conf
|
|
|
|
IPSEC_VAR_SECRETS_FILE=/var/ipsec/ipsec.secrets
|
|
IPSEC_VAR_CONN_FILE=/var/ipsec/ipsec.conf
|
|
STRONGSWAN_VAR_CONF_FILE=/var/ipsec/strongswan.conf
|
|
|
|
WAIT_FOR_INTF=0
|
|
|
|
file_reset() {
|
|
: > "$1"
|
|
}
|
|
|
|
xappend() {
|
|
local file="$1"
|
|
shift
|
|
|
|
echo "$@" >> "$file"
|
|
}
|
|
|
|
ipsec_reset() {
|
|
file_reset "$IPSEC_VAR_CONN_FILE"
|
|
}
|
|
|
|
ipsec_xappend() {
|
|
xappend "$IPSEC_VAR_CONN_FILE" "$@"
|
|
}
|
|
|
|
swan_reset() {
|
|
file_reset "$STRONGSWAN_VAR_CONF_FILE"
|
|
}
|
|
|
|
swan_xappend() {
|
|
xappend "$STRONGSWAN_VAR_CONF_FILE" "$@"
|
|
}
|
|
|
|
secret_reset() {
|
|
file_reset "$IPSEC_VAR_SECRETS_FILE"
|
|
}
|
|
|
|
secret_xappend() {
|
|
xappend "$IPSEC_VAR_SECRETS_FILE" "$@"
|
|
}
|
|
|
|
warning() {
|
|
echo "WARNING: $@" >&2
|
|
}
|
|
|
|
add_crypto_proposal() {
|
|
local encryption_algorithm
|
|
local hash_algorithm
|
|
local dh_group
|
|
|
|
config_get encryption_algorithm "$1" encryption_algorithm
|
|
config_get hash_algorithm "$1" hash_algorithm
|
|
config_get dh_group "$1" dh_group
|
|
|
|
[ -n "${encryption_algorithm}" ] && \
|
|
crypto="${crypto:+${crypto},}${encryption_algorithm}${hash_algorithm:+-${hash_algorithm}}${dh_group:+-${dh_group}}"
|
|
}
|
|
|
|
set_crypto_proposal() {
|
|
local conf="$1"
|
|
local proposal
|
|
|
|
crypto=""
|
|
|
|
config_get crypto_proposal "$conf" crypto_proposal ""
|
|
for proposal in $crypto_proposal; do
|
|
add_crypto_proposal "$proposal"
|
|
done
|
|
|
|
[ -n "${crypto}" ] && {
|
|
local force_crypto_proposal
|
|
|
|
config_get_bool force_crypto_proposal "$conf" force_crypto_proposal
|
|
|
|
[ "${force_crypto_proposal}" = "1" ] && crypto="${crypto}!"
|
|
}
|
|
|
|
crypto_proposal="${crypto}"
|
|
}
|
|
|
|
config_conn() {
|
|
# Generic ipsec conn section shared by tunnel and transport
|
|
local mode
|
|
local local_subnet
|
|
local local_nat
|
|
local local_sourceip
|
|
local local_leftip
|
|
local local_updown
|
|
local local_firewall
|
|
local remote_subnet
|
|
local remote_sourceip
|
|
local remote_updown
|
|
local remote_firewall
|
|
local ikelifetime
|
|
local lifetime
|
|
local margintime
|
|
local keyingtries
|
|
local dpdaction
|
|
local dpddelay
|
|
local inactivity
|
|
local keyexchange
|
|
local reqid
|
|
local packet_marker
|
|
|
|
config_get mode "$1" mode "route"
|
|
config_get local_subnet "$1" local_subnet ""
|
|
config_get local_nat "$1" local_nat ""
|
|
config_get local_sourceip "$1" local_sourceip ""
|
|
config_get local_leftip "$1" local_leftip "%any"
|
|
config_get local_updown "$1" local_updown ""
|
|
config_get local_firewall "$1" local_firewall ""
|
|
config_get remote_subnet "$1" remote_subnet ""
|
|
config_get remote_sourceip "$1" remote_sourceip ""
|
|
config_get remote_updown "$1" remote_updown ""
|
|
config_get remote_firewall "$1" remote_firewall ""
|
|
config_get ikelifetime "$1" ikelifetime "3h"
|
|
config_get lifetime "$1" lifetime "1h"
|
|
config_get margintime "$1" margintime "9m"
|
|
config_get keyingtries "$1" keyingtries "3"
|
|
config_get dpdaction "$1" dpdaction "none"
|
|
config_get dpddelay "$1" dpddelay "30s"
|
|
config_get inactivity "$1" inactivity
|
|
config_get keyexchange "$1" keyexchange "ikev2"
|
|
config_get reqid "$1" reqid
|
|
config_get packet_marker "$1" packet_marker
|
|
|
|
[ -n "$local_nat" ] && local_subnet=$local_nat
|
|
|
|
ipsec_xappend "conn $config_name-$1"
|
|
ipsec_xappend " left=$local_leftip"
|
|
ipsec_xappend " right=$remote_gateway"
|
|
|
|
[ -n "$local_sourceip" ] && ipsec_xappend " leftsourceip=$local_sourceip"
|
|
[ -n "$local_subnet" ] && ipsec_xappend " leftsubnet=$local_subnet"
|
|
|
|
[ -n "$local_firewall" ] && ipsec_xappend " leftfirewall=$local_firewall"
|
|
[ -n "$remote_firewall" ] && ipsec_xappend " rightfirewall=$remote_firewall"
|
|
|
|
ipsec_xappend " ikelifetime=$ikelifetime"
|
|
ipsec_xappend " lifetime=$lifetime"
|
|
ipsec_xappend " margintime=$margintime"
|
|
ipsec_xappend " keyingtries=$keyingtries"
|
|
ipsec_xappend " dpdaction=$dpdaction"
|
|
ipsec_xappend " dpddelay=$dpddelay"
|
|
|
|
[ -n "$inactivity" ] && ipsec_xappend " inactivity=$inactivity"
|
|
[ -n "$reqid" ] && ipsec_xappend " reqid=$reqid"
|
|
|
|
if [ "$auth_method" = "psk" ]; then
|
|
ipsec_xappend " leftauth=psk"
|
|
ipsec_xappend " rightauth=psk"
|
|
|
|
[ "$remote_sourceip" != "" ] && ipsec_xappend " rightsourceip=$remote_sourceip"
|
|
[ "$remote_subnet" != "" ] && ipsec_xappend " rightsubnet=$remote_subnet"
|
|
|
|
ipsec_xappend " auto=$mode"
|
|
else
|
|
warning "AuthenticationMethod $auth_method not supported"
|
|
fi
|
|
|
|
[ -n "$local_identifier" ] && ipsec_xappend " leftid=$local_identifier"
|
|
[ -n "$remote_identifier" ] && ipsec_xappend " rightid=$remote_identifier"
|
|
[ -n "$local_updown" ] && ipsec_xappend " leftupdown=$local_updown"
|
|
[ -n "$remote_updown" ] && ipsec_xappend " rightupdown=$remote_updown"
|
|
[ -n "$packet_marker" ] && ipsec_xappend " mark=$packet_marker"
|
|
ipsec_xappend " keyexchange=$keyexchange"
|
|
|
|
set_crypto_proposal "$1"
|
|
[ -n "${crypto_proposal}" ] && ipsec_xappend " esp=$crypto_proposal"
|
|
[ -n "${ike_proposal}" ] && ipsec_xappend " ike=$ike_proposal"
|
|
}
|
|
|
|
config_tunnel() {
|
|
config_conn "$1"
|
|
|
|
# Specific for the tunnel part
|
|
ipsec_xappend " type=tunnel"
|
|
}
|
|
|
|
config_transport() {
|
|
config_conn "$1"
|
|
|
|
# Specific for the transport part
|
|
ipsec_xappend " type=transport"
|
|
}
|
|
|
|
config_remote() {
|
|
local enabled
|
|
local gateway
|
|
local pre_shared_key
|
|
local auth_method
|
|
|
|
config_name=$1
|
|
|
|
config_get_bool enabled "$1" enabled 0
|
|
[ $enabled -eq 0 ] && return
|
|
|
|
config_get gateway "$1" gateway
|
|
config_get pre_shared_key "$1" pre_shared_key
|
|
config_get auth_method "$1" authentication_method
|
|
config_get local_identifier "$1" local_identifier ""
|
|
config_get remote_identifier "$1" remote_identifier ""
|
|
|
|
[ "$gateway" = "any" ] && remote_gateway="%any" || remote_gateway="$gateway"
|
|
|
|
[ -z "$local_identifier" ] && {
|
|
local ipdest
|
|
|
|
[ "$remote_gateway" = "%any" ] && ipdest="1.1.1.1" || ipdest="$remote_gateway"
|
|
local_gateway=$(ip -o route get "$ipdest" | awk '/ src / { print gensub(/^.* src ([^ ]*) .*$/, "\\1", "g"); }')
|
|
}
|
|
|
|
[ -n "$local_identifier" ] && secret_xappend -n "$local_identifier " || secret_xappend -n "$local_gateway "
|
|
[ -n "$remote_identifier" ] && secret_xappend -n "$remote_identifier " || secret_xappend -n "$remote_gateway "
|
|
|
|
secret_xappend ": PSK \"$pre_shared_key\""
|
|
|
|
set_crypto_proposal "$1"
|
|
ike_proposal="$crypto_proposal"
|
|
|
|
config_list_foreach "$1" tunnel config_tunnel
|
|
|
|
config_list_foreach "$1" transport config_transport
|
|
|
|
ipsec_xappend ""
|
|
}
|
|
|
|
do_preamble() {
|
|
ipsec_xappend "# generated by /etc/init.d/ipsec"
|
|
ipsec_xappend "version 2"
|
|
ipsec_xappend ""
|
|
|
|
secret_xappend "# generated by /etc/init.d/ipsec"
|
|
}
|
|
|
|
config_ipsec() {
|
|
local debug
|
|
local rtinstall_enabled
|
|
local routing_tables_ignored
|
|
local routing_table
|
|
local routing_table_id
|
|
local interface
|
|
local device_list
|
|
|
|
ipsec_reset
|
|
secret_reset
|
|
swan_reset
|
|
|
|
do_preamble
|
|
|
|
config_get debug "$1" debug 0
|
|
config_get_bool rtinstall_enabled "$1" rtinstall_enabled 1
|
|
[ $rtinstall_enabled -eq 1 ] && install_routes=yes || install_routes=no
|
|
|
|
# prepare extra charon config option ignore_routing_tables
|
|
for routing_table in $(config_get "$1" "ignore_routing_tables"); do
|
|
if [ "$routing_table" -ge 0 ] 2>/dev/null; then
|
|
routing_table_id=$routing_table
|
|
else
|
|
routing_table_id=$(sed -n '/[ \t]*[0-9]\+[ \t]\+'$routing_table'[ \t]*$/s/[ \t]*\([0-9]\+\).*/\1/p' /etc/iproute2/rt_tables)
|
|
fi
|
|
|
|
[ -n "$routing_table_id" ] && append routing_tables_ignored "$routing_table_id"
|
|
done
|
|
|
|
local interface_list=$(config_get "$1" "interface")
|
|
if [ -z "$interface_list" ]; then
|
|
WAIT_FOR_INTF=0
|
|
else
|
|
for interface in $interface_list; do
|
|
network_get_device device $interface
|
|
[ -n "$device" ] && append device_list "$device" ","
|
|
done
|
|
[ -n "$device_list" ] && WAIT_FOR_INTF=0 || WAIT_FOR_INTF=1
|
|
fi
|
|
|
|
swan_xappend "# generated by /etc/init.d/ipsec"
|
|
swan_xappend "charon {"
|
|
swan_xappend " load_modular = yes"
|
|
swan_xappend " install_routes = $install_routes"
|
|
[ -n "$routing_tables_ignored" ] && swan_xappend " ignore_routing_tables = $routing_tables_ignored"
|
|
[ -n "$device_list" ] && swan_xappend " interfaces_use = $device_list"
|
|
swan_xappend " plugins {"
|
|
swan_xappend " include /etc/strongswan.d/charon/*.conf"
|
|
swan_xappend " }"
|
|
swan_xappend " syslog {"
|
|
swan_xappend " identifier = ipsec"
|
|
swan_xappend " daemon {"
|
|
swan_xappend " default = $debug"
|
|
swan_xappend " }"
|
|
swan_xappend " }"
|
|
swan_xappend "}"
|
|
}
|
|
|
|
prepare_env() {
|
|
mkdir -p /var/ipsec
|
|
config_load ipsec
|
|
config_foreach config_ipsec ipsec
|
|
config_foreach config_remote remote
|
|
}
|
|
|
|
service_running() {
|
|
ipsec status > /dev/null 2>&1
|
|
}
|
|
|
|
reload_service() {
|
|
running && {
|
|
prepare_env
|
|
[ $WAIT_FOR_INTF -eq 0 ] && {
|
|
ipsec rereadall
|
|
ipsec reload
|
|
return
|
|
}
|
|
}
|
|
|
|
start
|
|
}
|
|
|
|
check_ipsec_interface() {
|
|
local intf
|
|
|
|
for intf in $(config_get "$1" interface); do
|
|
procd_add_interface_trigger "interface.*" "$intf" /etc/init.d/ipsec reload
|
|
done
|
|
}
|
|
|
|
service_triggers() {
|
|
procd_add_reload_trigger "ipsec"
|
|
config load "ipsec"
|
|
config_foreach check_ipsec_interface ipsec
|
|
}
|
|
|
|
start_service() {
|
|
prepare_env
|
|
|
|
[ $WAIT_FOR_INTF -eq 1 ] && return
|
|
|
|
procd_open_instance
|
|
|
|
procd_set_param command $PROG --daemon charon --nofork
|
|
|
|
procd_set_param file $IPSEC_CONN_FILE
|
|
procd_append_param file $IPSEC_SECRETS_FILE
|
|
procd_append_param file $STRONGSWAN_CONF_FILE
|
|
procd_append_param file /etc/strongswan.d/*.conf
|
|
procd_append_param file /etc/strongswan.d/charon/*.conf
|
|
|
|
procd_set_param respawn
|
|
|
|
procd_close_instance
|
|
}
|