#!/bin/sh /etc/rc.common . "${IPKG_INSTROOT}/lib/functions/network.sh" START=90 STOP=10 USE_PROCD=1 PROG="/usr/libexec/ipsec/pluto" IPSEC_BIN="/usr/sbin/ipsec" IPSEC_DIR="/var/run/ipsec" IPSEC_CONF="$IPSEC_DIR/setup.conf" IPSEC_CONF_DIR="$IPSEC_DIR/conf.d" IPSEC_AUTO="${IPSEC_BIN} auto" extra_command "start_tunnel" "Start ipsec tunnel" extra_command "stop_tunnel" "Stop ipsec tunnel" extra_command "reload_tunnel" "Reload/restart ipsec tunnel" set_var() { export "$1=$2" } get_var() { local var var=$(eval echo "\"\${${1}}\"") [ "$var" = "1" ] && return 0 return 1 } set_restart_flag() { set_var "RESTART_IPSEC" 1 } restart_flag() { get_var RESTART_IPSEC } set_replace_flag() { set_var "REPLACE_${1}" 1 } replace_flag() { get_var "REPLACE_${1}" } checkconfig() { ${IPSEC_BIN} addconn --checkconfig || return 1 mkdir -p /var/run/pluto } expand_ike() { local id="$1" local encryption_algorithm hash_algorithm dh_group proposal config_get encryption_algorithm "${id}" encryption_algorithm config_get hash_algorithm "${id}" hash_algorithm config_get dh_group "${id}" dh_group encryption_algorithm="${encryption_algorithm% *}" proposal="${encryption_algorithm:+${encryption_algorithm}${hash_algorithm:+-${hash_algorithm}${dh_group:+;${dh_group%% *}}}}" append ike_proposal "$proposal" "," } expand_phase2alg() { local id="$1" local encryption_algorithm hash_algorithm dh_group config_get encryption_algorithm "${id}" encryption_algorithm config_get hash_algorithm "${id}" hash_algorithm config_get dh_group "${id}" dh_group phase2alg_proposal="${encryption_algorithm:+${encryption_algorithm// /+}${hash_algorithm:+-${hash_algorithm// /+}${dh_group:+-${dh_group// /+}}}}" } generate_tunnel_config() { local id=$1 local config_file="$IPSEC_CONF_DIR/$id.conf" local secret_file="$IPSEC_CONF_DIR/$id.secret" local tmp_config_file="/tmp/$id.conf" local tmp_secret_file="/tmp/$id.secret" local ikey mark_in okey mark_out ifid config_get auto "$id" auto config_get left "$id" left config_get left_interface "$id" left_interface [ -n "$left_interface" ] && network_get_ipaddr left "$left_interface" config_get right "$id" right config_get leftid "$id" leftid "$left" config_get rightid "$id" rightid "$right" config_get leftsourceip "$id" leftsourceip config_get rightsourceip "$id" rightsourceip config_get leftsubnets "$id" leftsubnets config_get rightsubnets "$id" rightsubnets config_get_bool ikev2 "$id" ikev2 [ "$ikev2" = "1" ] && ikev2=yes || ikev2=no config_get_bool rekey "$id" rekey [ "$rekey" = "1" ] && rekey=yes || rekey=no config_get ikelifetime "$id" ikelifetime config_get rekeymargin "$id" rekeymargin config_get dpdaction "$id" dpdaction config_get dpdtimeout "$id" dpdtimeout config_get dpddelay "$id" dpddelay config_get phase2 "$id" phase2 config_get phase2alg "$id" phase2alg config_get nflog "$id" nflog 0 [ "$nflog" = "0" ] && unset nflog config_list_foreach "$id" ike expand_ike config_list_foreach "$id" phase2alg expand_phase2alg config_get authby "$id" authby config_get psk "$id" psk if [ -n "$leftsubnets" ]; then [[ "$leftsubnets" =~ 0.0.0.0* ]] && leftsubnets="0.0.0.0/0" leftsubnets="{${leftsubnets// /,}}" fi if [ -n "$rightsubnets" ]; then [[ "$rightsubnets" =~ 0.0.0.0* ]] && rightsubnets="0.0.0.0/0" rightsubnets="{${rightsubnets// /,}}" fi config_get interface "$id" interface cat << EOF > "$tmp_secret_file" $leftid $rightid : PSK "$psk" EOF cat << EOF > "$tmp_config_file" conn $id auto=${auto} authby=${authby} ikev2=${ikev2} left=${left%% *} ${leftid:+leftid=${leftid}} ${leftsourceip:+leftsourceip=${leftsourceip}} ${leftsubnets:+leftsubnets=${leftsubnets}} right=${right%% *} ${rightid:+rightid=${rightid}} ${rightsourceip:+rightsourceip=${rightsourceip}} ${rightsubnets:+rightsubnets=${rightsubnets}} ${dpdaction:+dpdaction=${dpdaction}} ${dpdtimeout:+dpdtimeout=${dpdtimeout}} ${dpddelay:+dpddelay=${dpddelay}} ${ikelifetime:+ikelifetime=${ikelifetime}} ${rekey:+rekey=${rekey}} ${rekeymargin:+rekeymargin=${rekeymargin}} ${rekeyfuzz:+rekeyfuzz=${rekeyfuzz}} ${phase2:+phase2=${phase2}} ${ike_proposal:+ike=${ike_proposal}} ${phase2alg_proposal:+phase2alg=${phase2alg_proposal}} ${nflog:+nflog=${nflog}} EOF if [ -n "$interface" ]; then proto=$(uci_get network "$interface" proto) case "$proto" in vti) ikey=$(uci_get network "$interface" ikey) okey=$(uci_get network "$interface" okey) mark_in=$(printf "0x%x" $ikey) mark_out=$(printf "0x%x" $okey) echo -e "${mark_in:+\tmark-in=${mark_in}}" >> "$tmp_config_file" echo -e "${mark_out:+\tmark-out=${mark_out}}" >> "$tmp_config_file" echo -e "${interface:+\tvti-interface=${interface}}" >> "$tmp_config_file" ;; xfrm) ifid=$(uci_get network "$interface" ifid) echo -e "${ifid:+\tipsec-interface=${ifid}}" >> "$tmp_config_file" ;; esac fi [ -f "$config_file" ] && { cmp "$config_file" "$tmp_config_file" 2>/dev/null && rm -f "$tmp_config_file" } [ -f "$secret_file" ] && { cmp "$secret_file" "$tmp_secret_file" 2>/dev/null && rm -f "$tmp_secret_file" } [ -f "$tmp_config_file" ] && mv "$tmp_config_file" "$config_file" && set_replace_flag "$id" [ -f "$tmp_secret_file" ] && mv "$tmp_secret_file" "$secret_file" && set_replace_flag "$id" unset ike_proposal phase2alg_proposal } generate_daemon_config() { local tmp_config_file="/tmp/setup.conf" config_get_bool debug globals debug 0 [ "$debug" = "0" ] && debug=none || debug=all config_get_bool uniqueids globals uniqueids 0 [ "$uniqueids" = "0" ] && uniqueids=no || uniqueids=yes config_get listen globals listen config_get listen_interface globals listen_interface [ -n "$listen_interface" ] && network_get_ipaddr listen "$listen_interface" config_get virtual_private globals virtual_private [ -z "$virtual_private" ] && virtual_private='10.0.0.0/8 192.168.0.0/16 172.16.0.0/12 25.0.0.0/8 100.64.0.0/10 !100.64.0.0/24' config_get nflog_all globals nflog_all 0 [ "$nflog_all" = "0" ] && unset nflog_all [ ! -d $IPSEC_DIR ] && mkdir -p $IPSEC_DIR [ ! -d $IPSEC_CONF_DIR ] && mkdir -p $IPSEC_CONF_DIR cat << EOF > "$tmp_config_file" config setup ${debug:+plutodebug=${debug}} ${uniqueids:+uniqueids=${uniqueids}} ${listen:+listen=${listen}} ${virtual_private:+virtual-private=%v4:${virtual_private// /,%v4:}} ${nflog_all:+nflog-all=${nflog_all}} EOF if ! cmp "$IPSEC_CONF" "$tmp_config_file" 2>/dev/null; then mv "$tmp_config_file" "$IPSEC_CONF" set_restart_flag 1 else rm -f "$tmp_config_file" fi return 0 } clean_config() { rm -f $IPSEC_CONF_DIR/*.conf $IPSEC_CONF_DIR/*.secret } config_cb() { local var="CONFIG_${1}_SECTIONS" export $var append "$var" "$2" } generate_config() { config_load libreswan generate_daemon_config config_foreach generate_tunnel_config tunnel } regenerate_config() { clean_config generate_config } active_conns() { local active_conns file _file active_conns=$(${IPSEC_BIN} --trafficstatus | awk -F'[":/]' '{print $3}' | sort -u) for file in $IPSEC_CONF_DIR/*.conf; do _file="${file##*/}" list_contains active_conns "${_file%%.*}" || append active_conns "${_file%%.*}" done echo "$active_conns" } start_service() { generate_config checkconfig || return 1 ${IPSEC_BIN} _stackmanager start procd_open_instance procd_set_param command $PROG --nofork procd_set_param respawn procd_close_instance } stop_service() { ${IPSEC_BIN} whack --shutdown ${IPSEC_BIN} _stackmanager stop } stop_tunnel() { ${IPSEC_AUTO} --delete "$1" > /dev/null 2>&1 rm -f ${IPSEC_CONF_DIR}/$1.* } start_tunnel() { generate_tunnel_config "$1" ${IPSEC_AUTO} --add "$1" > /dev/null 2>&1 ${IPSEC_AUTO} --rereadsecrets ${IPSEC_AUTO} --up "$1" > /dev/null 2>&1 & } reload_tunnel() { generate_tunnel_config "$1" replace_flag "$1" || return 0 ${IPSEC_AUTO} --rereadsecrets ${IPSEC_AUTO} --replace "$1" > /dev/null 2>&1 ${IPSEC_AUTO} --up "$1" > /dev/null 2>&1 & } reload_service() { local active_tunnels uci_tunnels uci_tunnels="$@" config_load libreswan generate_daemon_config if restart_flag; then restart return 0 fi [ -z "$uci_tunnels" ] && config_get uci_tunnels tunnel SECTIONS active_tunnels="$(active_conns)" for tunnel in $active_tunnels; do list_contains uci_tunnels "$tunnel" || stop_tunnel "$tunnel" done for tunnel in $uci_tunnels; do if list_contains active_tunnels "$tunnel"; then reload_tunnel "$tunnel" else start_tunnel "$tunnel" fi done } service_triggers() { procd_add_reload_trigger 'libreswan' }