--- /dev/null
+#!/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
+
+STRONGSWAN_CONF_FILE=/etc/strongswan.conf
+STRONGSWAN_VAR_CONF_FILE=/var/ipsec/strongswan.conf
+
+SWANCTL_CONF_FILE=/etc/swanctl/swanctl.conf
+SWANCTL_VAR_CONF_FILE=/var/swanctl/swanctl.conf
+
+WAIT_FOR_INTF=0
+
+time2seconds()
+{
+ local timestring="$1"
+ local multiplier number suffix
+
+ suffix="${timestring//[0-9 ]}"
+ number="${timestring%%$suffix}"
+ [ "$number$suffix" != "$timestring" ] && return 1
+ case "$suffix" in
+ ""|s)
+ multiplier=1 ;;
+ m)
+ multiplier=60 ;;
+ h)
+ multiplier=3600 ;;
+ d)
+ multiplier=86400 ;;
+ *)
+ return 1 ;;
+ esac
+ echo $(( number * multiplier ))
+}
+
+seconds2time()
+{
+ local seconds="$1"
+
+ if [ $seconds -eq 0 ]; then
+ echo "0s"
+ elif [ $((seconds % 86400)) -eq 0 ]; then
+ echo "$((seconds / 86400))d"
+ elif [ $((seconds % 3600)) -eq 0 ]; then
+ echo "$((seconds / 3600))h"
+ elif [ $((seconds % 60)) -eq 0 ]; then
+ echo "$((seconds / 60))m"
+ else
+ echo "${seconds}s"
+ fi
+}
+
+file_reset() {
+ : > "$1"
+}
+
+xappend() {
+ local file="$1"
+ shift
+
+ echo "$@" >> "$file"
+}
+
+swan_reset() {
+ file_reset "$STRONGSWAN_VAR_CONF_FILE"
+}
+
+swan_xappend() {
+ xappend "$STRONGSWAN_VAR_CONF_FILE" "$@"
+}
+
+swan_xappend0() {
+ swan_xappend "$@"
+}
+
+swan_xappend1() {
+ swan_xappend " ""$@"
+}
+
+swan_xappend2() {
+ swan_xappend " ""$@"
+}
+
+swan_xappend3() {
+ swan_xappend " ""$@"
+}
+
+swan_xappend4() {
+ swan_xappend " ""$@"
+}
+
+swanctl_reset() {
+ file_reset "$SWANCTL_VAR_CONF_FILE"
+}
+
+swanctl_xappend() {
+ xappend "$SWANCTL_VAR_CONF_FILE" "$@"
+}
+
+swanctl_xappend0() {
+ swanctl_xappend "$@"
+}
+
+swanctl_xappend1() {
+ swanctl_xappend " ""$@"
+}
+
+swanctl_xappend2() {
+ swanctl_xappend " ""$@"
+}
+
+swanctl_xappend3() {
+ swanctl_xappend " ""$@"
+}
+
+swanctl_xappend4() {
+ swanctl_xappend " ""$@"
+}
+
+warning() {
+ echo "WARNING: $@" >&2
+}
+
+is_aead() {
+ local cipher="$1"
+
+ case "$cipher" in
+ aes*gcm*|aes*ccm*|aes*gmac*)
+ return 0 ;;
+ esac
+
+ return 1
+}
+
+add_esp_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
+
+ # check for AEAD and clobber hash_algorithm if set
+ if is_aead "$encryption_algorithm" && [ -n "$hash_algorithm" ]; then
+ warning "Can't have $hash_algorithm with $encryption_algorithm"
+ hash_algorithm=
+ fi
+
+ [ -n "$encryption_algorithm" ] && \
+ crypto="${crypto:+${crypto},}${encryption_algorithm}${hash_algorithm:+-${hash_algorithm}}${dh_group:+-${dh_group}}"
+}
+
+parse_esp_proposal() {
+ local conf="$1"
+ local crypto=""
+
+ config_list_foreach "$conf" crypto_proposal add_esp_proposal
+
+ echo "$crypto"
+}
+
+add_ike_proposal() {
+ local encryption_algorithm
+ local hash_algorithm
+ local dh_group
+ local prf_algorithm
+
+ config_get encryption_algorithm "$1" encryption_algorithm
+ config_get hash_algorithm "$1" hash_algorithm
+ config_get dh_group "$1" dh_group
+ config_get prf_algorithm "$1" prf_algorithm
+
+ # check for AEAD and clobber hash_algorithm if set
+ if is_aead "$encryption_algorithm" && [ -n "$hash_algorithm" ]; then
+ warning "Can't have $hash_algorithm with $encryption_algorithm"
+ hash_algorithm=
+ fi
+
+ [ -n "$encryption_algorithm" ] && \
+ crypto="${crypto:+${crypto},}${encryption_algorithm}${hash_algorithm:+-${hash_algorithm}}${prf_algorithm:+-${prf_algorithm}}${dh_group:+-${dh_group}}"
+}
+
+parse_ike_proposal() {
+ local conf="$1"
+ local crypto=""
+
+ config_list_foreach "$conf" crypto_proposal add_ike_proposal
+
+ echo "$crypto"
+}
+
+config_conn() {
+ # Generic ipsec conn section shared by tunnel and transport
+ local config_name="$1"
+ local mode="$2"
+
+ local local_subnet
+ local local_nat
+ local updown
+ local firewall
+ local remote_subnet
+ local remote_sourceip
+ local lifetime
+ local dpdaction
+ local closeaction
+ local startaction
+ local if_id
+ local rekeytime
+
+ config_get startaction "$1" startaction "route"
+ config_get local_subnet "$1" local_subnet ""
+ config_get local_nat "$1" local_nat ""
+ config_get updown "$1" updown ""
+ config_get firewall "$1" firewall ""
+ config_get remote_subnet "$1" remote_subnet ""
+ config_get remote_sourceip "$1" remote_sourceip ""
+ config_get lifetime "$1" lifetime ""
+ config_get dpdaction "$1" dpdaction "none"
+ config_get closeaction "$1" closeaction "none"
+ config_get if_id "$1" if_id ""
+ config_get rekeytime "$1" rekeytime ""
+
+ local esp_proposal="$(parse_esp_proposal "$1")"
+
+ # translate from ipsec to swanctl
+ case "$startaction" in
+ add)
+ startaction="none" ;;
+ route)
+ startaction="trap" ;;
+ start|none|trap)
+ # already using new syntax
+ ;;
+ *)
+ warning "Startaction $startaction unknown"
+ startaction=
+ ;;
+ esac
+
+ case "$closeaction" in
+ none|clear)
+ closeaction="none" ;;
+ hold)
+ closeaction="trap" ;;
+ restart)
+ closeaction="start" ;;
+ trap|start)
+ # already using new syntax
+ ;;
+ *)
+ warning "Closeaction $closeaction unknown"
+ closeaction=
+ ;;
+ esac
+
+ [ -n "$closeaction" -a "$closeaction" != "none" ] && warning "Closeaction $closeaction can cause instability"
+
+ case "$dpdaction" in
+ none)
+ dpddelay="0s"
+ dpdaction=
+ ;;
+ clear)
+ ;;
+ hold)
+ dpdaction="trap" ;;
+ restart)
+ dpdaction="start" ;;
+ trap|start)
+ # already using new syntax
+ ;;
+ *)
+ warning "Dpdaction $dpdaction unknown"
+ dpdaction=
+ ;;
+ esac
+
+ [ -n "$local_nat" ] && local_subnet="$local_nat"
+
+ swanctl_xappend3 "$config_name {"
+
+ [ -n "$local_subnet" ] && swanctl_xappend4 "local_ts = $local_subnet"
+ [ -n "$remote_subnet" ] && swanctl_xappend4 "remote_ts = $remote_subnet"
+ [ -n "$if_id" ] && { swanctl_xappend4 "if_id_in = $if_id" ; swanctl_xappend4 "if_id_out = $if_id" ; }
+ [ -n "$startaction" -a "$startaction" != "none" ] && swanctl_xappend4 "start_action = $startaction"
+ [ -n "$closeaction" -a "$closeaction" != "none" ] && swanctl_xappend4 "close_action = $closeaction"
+ swanctl_xappend4 "esp_proposals = $esp_proposal"
+ swanctl_xappend4 "mode = $mode"
+
+ if [ -n "$lifetime" ]; then
+ swanctl_xappend4 "life_time = $lifetime"
+ elif [ -n "$rekeytime" ]; then
+ swanctl_xappend4 "life_time = $(seconds2time $(((110 * $(time2seconds $rekeytime)) / 100)))"
+ fi
+ [ -n "$rekeytime" ] && swanctl_xappend4 "rekey_time = $rekeytime"
+
+ [ -n "$updown" ] && swanctl_xappend4 "updown = $updown"
+ [ -n "$dpdaction" ] && swanctl_xappend4 "dpd_action = $dpdaction"
+
+ swanctl_xappend3 "}"
+}
+
+config_tunnel() {
+ config_conn "$1" "tunnel"
+}
+
+config_transport() {
+ config_conn "$1" "transport"
+}
+
+config_remote() {
+ local config_name="$1"
+
+ local enabled
+ local gateway
+ local local_gateway
+ local local_sourceip
+ local local_leftip
+ local remote_gateway
+ local pre_shared_key
+ local auth_method
+ local keyingtries
+ local dpddelay
+ local inactivity
+ local keyexchange
+ local reqid
+ local packet_marker
+ local fragmentation
+ local mobike
+ local local_cert
+ local local_key
+ local ca_cert
+ local rekeytime
+
+ 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 ""
+ config_get local_sourceip "$1" local_sourceip ""
+ config_get local_leftip "$1" local_leftip "%any"
+ config_get keyingtries "$1" keyingtries "3"
+ 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
+ config_get fragmentation "$1" fragmentation "yes"
+ config_get_bool mobike "$1" mobike 1
+ config_get local_cert "$1" local_cert ""
+ config_get local_key "$1" local_key ""
+ config_get ca_cert "$1" ca_cert ""
+ config_get rekeytime "$1" rekeytime
+ config_get overtime "$1" overtime
+
+ case "$fragmentation" in
+ 0)
+ fragmentation="no" ;;
+ 1)
+ fragmentation="yes" ;;
+ yes|accept|force|no)
+ # already using new syntax
+ ;;
+ *)
+ warning "Fragmentation $fragmentation not supported"
+ fragmentation=
+ ;;
+ esac
+
+ [ "$gateway" = "any" ] && remote_gateway="%any" || remote_gateway="$gateway"
+
+ [ -z "$local_gateway" ] && {
+ local ipdest
+
+ [ "$remote_gateway" = "%any" ] && ipdest="1.1.1.1" || ipdest="$remote_gateway"
+ local_gateway=`ip -o route get $ipdest | awk '/ src / { gsub(/^.* src /,""); gsub(/ .*$/, ""); print $0}'`
+ }
+
+ local ike_proposal="$(parse_ike_proposal "$1")"
+
+ [ -n "$firewall" ] && warning "Firewall not supported"
+
+ swanctl_xappend0 "# config for $config_name"
+ swanctl_xappend0 "connections {"
+ swanctl_xappend1 "$config_name {"
+ swanctl_xappend2 "local_addrs = $local_leftip"
+ swanctl_xappend2 "remote_addrs = $remote_gateway"
+
+ [ -n "$local_sourceip" ] && swanctl_xappend2 "vips = $local_sourceip"
+ [ -n "$fragmentation" ] && swanctl_xappend2 "fragmentation = $fragmentation"
+
+ swanctl_xappend2 "local {"
+ swanctl_xappend3 "auth = $auth_method"
+
+ [ -n "$local_identifier" ] && swanctl_xappend3 "id = \"$local_identifier\""
+ [ "$auth_method" = pubkey ] && swanctl_xappend3 "certs = $local_cert"
+ swanctl_xappend2 "}"
+
+ swanctl_xappend2 "remote {"
+ swanctl_xappend3 "auth = $auth_method"
+ [ -n "$remote_identifier" ] && swanctl_xappend3 "id = \"$remote_identifier\""
+ swanctl_xappend2 "}"
+
+ swanctl_xappend2 "children {"
+
+ config_list_foreach "$1" tunnel config_tunnel
+
+ config_list_foreach "$1" transport config_transport
+
+ swanctl_xappend2 "}"
+
+ case "$keyexchange" in
+ ike)
+ ;;
+ ikev1)
+ swanctl_xappend2 "version = 1" ;;
+ ikev2)
+ swanctl_xappend2 "version = 2" ;;
+ *)
+ warning "Keyexchange $keyexchange not supported"
+ keyexchange=
+ ;;
+ esac
+
+ [ $mobike -eq 1 ] && swanctl_xappend2 "mobike = yes" || swanctl_xappend2 "mobike = no"
+
+ if [ -n "$rekeytime" ]; then
+ swanctl_xappend2 "rekey_time = $rekeytime"
+
+ if [ -z "$overtime" ]; then
+ overtime=$(seconds2time $(($(time2seconds $rekeytime) / 10)))
+ fi
+ fi
+ [ -n "$overtime" ] && swanctl_xappend2 "over_time = $overtime"
+
+ swanctl_xappend2 "proposals = $ike_proposal"
+ [ -n "$dpddelay" ] && swanctl_xappend2 "dpd_delay = $dpddelay"
+ [ "$keyingtries" = "%forever" ] && swanctl_xappend2 "keyingtries = 0" || swanctl_xappend2 "keyingtries = $keyingtries"
+
+ swanctl_xappend1 "}"
+ swanctl_xappend0 "}"
+
+ if [ "$auth_method" = pubkey ]; then
+ swanctl_xappend0 ""
+
+ swanctl_xappend0 "secrets {"
+ swanctl_xappend1 "rsa {"
+ swanctl_xappend2 "filename = $local_key"
+ swanctl_xappend1 "}"
+ swanctl_xappend0 "}"
+
+ swanctl_xappend0 ""
+
+ if [ -n "$ca_cert" ]; then
+ swanctl_xappend0 "authorities {"
+ swanctl_xappend1 "$config_name {"
+ swanctl_xappend2 "cacert = $ca_cert"
+ swanctl_xappend1 "}"
+ swanctl_xappend0 "}"
+ fi
+
+ elif [ "$auth_method" = psk ]; then
+ swanctl_xappend0 ""
+
+ swanctl_xappend0 "secrets {"
+ swanctl_xappend1 "ike {"
+ swanctl_xappend2 "secret = $pre_shared_key"
+ if [ -z "$local_id" ]; then
+ swanctl_xappend2 "id1 = $local_id"
+ if [ -z "$remote_id" ]; then
+ swanctl_xappend2 "id2 = $remote_id"
+ fi
+ fi
+ else
+ warning "AuthenticationMode $auth_mode not supported"
+ fi
+
+ swanctl_xappend0 ""
+}
+
+do_preamble() {
+ swanctl_xappend0 "# generated by /etc/init.d/swanctl"
+}
+
+config_ipsec() {
+ local debug
+ local rtinstall_enabled
+ local routing_tables_ignored
+ local routing_table
+ local routing_table_id
+ local interface
+ local device_list
+
+ swan_reset
+ swanctl_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_xappend0 "# generated by /etc/init.d/swanctl"
+ swan_xappend0 "charon {"
+ swan_xappend1 "install_routes = $install_routes"
+ [ -n "$routing_tables_ignored" ] && swan_xappend1 "ignore_routing_tables = $routing_tables_ignored"
+ [ -n "$device_list" ] && swan_xappend1 "interfaces_use = $device_list"
+ swan_xappend1 "start-scripts {"
+ swan_xappend2 "load-all = /usr/sbin/swanctl --load-all --noprompt"
+ swan_xappend1 "}"
+ swan_xappend1 "syslog {"
+ swan_xappend2 "identifier = ipsec"
+ swan_xappend2 "daemon {"
+ swan_xappend3 "default = $debug"
+ swan_xappend2 "}"
+ swan_xappend1 "}"
+ swan_xappend0 "}"
+}
+
+prepare_env() {
+ mkdir -p /var/ipsec /var/swanctl
+ config_load ipsec
+ config_foreach config_ipsec ipsec
+ config_foreach config_remote remote
+}
+
+service_running() {
+ swanctl --stats > /dev/null 2>&1
+}
+
+reload_service() {
+ running && {
+ prepare_env
+ [ $WAIT_FOR_INTF -eq 0 ] && {
+ swanctl --load-all --noprompt
+ return
+ }
+ }
+
+ start
+}
+
+stop_service() {
+ swan_reset
+ swanctl_reset
+}
+
+service_triggers() {
+ procd_add_reload_trigger "ipsec"
+ config load "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 $SWANCTL_CONF_FILE
+ procd_append_param file /etc/swanctl/conf.d/*.conf
+ procd_append_param file $STRONGSWAN_CONF_FILE
+
+ procd_set_param respawn
+
+ procd_close_instance
+}