Created
November 29, 2016 13:54
-
-
Save danielkza/9c151c97d1b2c53b66ae1d190464bc9d to your computer and use it in GitHub Desktop.
Strongswan IPSec init script with UCI support
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh /etc/rc.common | |
START=90 | |
STOP=10 | |
NAME=ipsec-uci | |
USE_PROCD=1 | |
IPSEC_BIN=/usr/sbin/ipsec | |
IPSEC_SECRETS=/var/run/ipsec/ipsec.secrets | |
IPSEC_CONF=/var/run/ipsec/ipsec.conf | |
STRONGSWAN_CONF=/var/run/ipsec/strongswan.conf | |
IPSEC_D=/etc/ipsec.d | |
. /lib/functions.sh | |
. /lib/functions/network.sh | |
clear_ipsec_options() { | |
ipsec_options= | |
} | |
set_ipsec_option() { | |
if [ -n "$ipsec_options" ]; then | |
ipsec_options="$(echo "$ipsec_options" | sed "/^$1=/d")"$'\n' | |
fi | |
ipsec_options="${ipsec_options}$1=$2" | |
} | |
write_ipsec_options() { | |
echo "$ipsec_options" | sed 's/^/ /' | sort >> "$IPSEC_CONF" | |
echo >> "$IPSEC_CONF" | |
clear_ipsec_options | |
} | |
parse_custom_opt() { | |
local key value | |
key="${1%%=*}" | |
value="${1##*=}" | |
set_ipsec_option "$key" "$value" | |
} | |
parse_common_opts() { | |
config_get key_exchange "$1" key_exchange | |
config_get left_auth "$1" left_auth | |
config_get left_auth_2 "$1" left_auth_2 | |
config_get right_auth "$1" right_auth | |
config_get right_auth_2 "$1" right_auth_2 | |
config_get auto "$1" auto | |
config_get local_subnet "$1" local_subnet | |
config_get remote_subnet "$1" remote_subnet | |
config_get remote_virtual_subnet "$1" remote_virtual_subnet | |
config_get p1_proposal "$1" p1_proposal | |
config_get p2_proposal "$1" p2_proposal | |
p1_proposal=$(echo "$p1_proposal" | sed 's/ /,/g') | |
p2_proposal=$(echo "$p2_proposal" | sed 's/ /,/g') | |
if [ -n "$site_to_site" ]; then | |
if [ "$site_to_site" -eq 1 ]; then | |
set_ipsec_option xauth client | |
set_ipsec_option auto route | |
else | |
set_ipsec_option xauth server | |
if [ -n "$remote_virtual_subnet" ]; then | |
set_ipsec_option rightsourceip "$remote_virtual_subnet" | |
fi | |
set_ipsec_option auto add | |
fi | |
fi | |
[ -n "$left_auth" ] && set_ipsec_option leftauth "$left_auth" | |
[ -n "$left_auth_2" ] && set_ipsec_option leftauth2 "$left_auth_2" | |
[ -n "$right_auth" ] && set_ipsec_option rightauth "$right_auth" | |
[ -n "$right_auth_2" ] && set_ipsec_option rightauth2 "$right_auth_2" | |
[ -n "$auto" ] && set_ipsec_option auto "$auto" | |
[ -n "$key_exchange" ] && set_ipsec_option keyexchange "$key_exchange" | |
[ -n "$local_subnet" ] && set_ipsec_option leftsubnet "$local_subnet" | |
[ -n "$remote_subnet" ] && set_ipsec_option rightsubnet "$remote_subnet" | |
[ -n "$p1_proposal" ] && set_ipsec_option ike "$p1_proposal" | |
[ -n "$p2_proposal" ] && set_ipsec_option esp "$p2_proposal" | |
config_list_foreach "$1" custom parse_custom_opt | |
} | |
route_get_src() { | |
head -n1 | awk -F"src" '/src/{gsub(/ /,"");print $2}' | |
} | |
parse_remote_opts() { | |
config_get_bool site_to_site "$1" site_to_site "$site_to_site" | |
config_get local_address "$1" local_address | |
config_get remote_gateway "$1" gateway | |
config_get local_id "$1" local_id | |
config_get remote_id "$1" remote_id | |
config_get pre_shared_key "$1" pre_shared_key | |
[ "$remote_gateway" = any ] && remote_gateway='%any' | |
[ -n "$local_address" ] && set_ipsec_option left "$local_address" | |
[ -n "$local_id" ] && set_ipsec_option leftid "$local_id" | |
[ -n "$remote_gateway" ] && set_ipsec_option right "$remote_gateway" | |
[ -n "$remote_id" ] && set_ipsec_option rightid "$remote_id" | |
} | |
config_defaults() { | |
clear_ipsec_options | |
parse_common_opts "$1" | |
if [ -n "$ipsec_options" ]; then | |
echo 'conn %default' >> "$IPSEC_CONF" | |
write_ipsec_options | |
fi | |
} | |
config_remote() { | |
clear_ipsec_options | |
site_to_site=0 | |
parse_remote_opts "$1" | |
parse_common_opts "$1" | |
remote_opts="$ipsec_options" | |
if [ -n "$pre_shared_key" ]; then | |
psk_left="$local_id" | |
[ -z "$psk_left" ] && psk_left="$local_address" | |
psk_right="$remote_id" | |
[ -z "$psk_right" ] && psk_right="$remote_gateway" | |
echo "$psk_left $psk_right : PSK \"$pre_shared_key\"" >> "$IPSEC_SECRETS" | |
fi | |
config_get_bool remote_enabled "$1" enabled 0 | |
config_list_foreach "$1" tunnel config_tunnel "$1" "$ipsec_options" | |
} | |
config_tunnel() { | |
ipsec_options="$3" | |
parse_common_opts "$1" | |
set_ipsec_option type tunnel | |
config_get_bool tunnel_enabled "$1" enabled 0 | |
if [[ "$remote_enabled" -eq 0 || "$tunnel_enabled" -eq 0 ]]; then | |
set_ipsec_option auto ignored | |
fi | |
echo "conn $2-$1" >> "$IPSEC_CONF" | |
write_ipsec_options | |
} | |
config_key() { | |
local key_enabled key_id key_type password key_file key_pass | |
config_get_bool key_enabled "$1" enabled 1 | |
[ "$key_enabled" -eq 0 ] && return | |
config_get key_id "$1" id | |
config_get key_type "$1" type | |
config_get password "$1" password | |
config_get key_file "$1" key_file | |
config_get key_pass "$1" key_pass | |
[ -z "$key_id" ] && key_id="$1" | |
if [ -n "$key_type" ]; then | |
key_type=$(echo "$key_type" | awk '{print toupper($0);}') | |
elif [ -z "$key_file" ]; then | |
key_type=XAUTH | |
else | |
key_type=RSA | |
fi | |
echo "key $key_type $password $key_enabled" | |
case "$key_type" in | |
XAUTH|EAP|NTLM|PSK) | |
echo "$key_id : $key_type \"$password\"" >> "$IPSEC_SECRETS" | |
;; | |
RSA|ECDSA|BLISS|P12) | |
case "$key_file" in | |
"") ;; | |
/*) ;; | |
*) key_file="$IPSEC_D/private/$key_file" ;; | |
esac | |
[ -f "$key_file" ] || echo "warning: missing private key file $key_file" >&2 | |
if [ -n "$key_pass" ]; then | |
echo "$key_id : $key_type $key_file \"$key_pass\"" >> "$IPSEC_SECRETS" | |
else | |
echo "$key_id : $key_type $key_file" >> "$IPSEC_SECRETS" | |
fi | |
;; | |
*) | |
echo "warning: unsupported key type \"$key_type\", skipping user \"$key_id\"" >&2 | |
;; | |
esac | |
} | |
config_ca() { | |
clear_ipsec_options | |
config_get cert "$1" cert | |
config_get crluri1 "$1" revocation_uri | |
config_get crluri2 "$1" revocation_alt_uri | |
config_get ocspuri1 "$1" pinning_uri | |
config_get ocspuri2 "$1" pinning_alt_uri | |
config_get baseuri "$1" base_uri | |
config_get also "$1" include | |
config_get_bool ca_enabled "$1" enabled 0 | |
if [ "$ca_enabled" -eq 1 ]; then | |
set_ipsec_option auto add | |
else | |
set_ipsec_option auto ignored | |
fi | |
set_ipsec_option cacert "$cert" | |
[ -n "$crluri1" ] && set_ipsec_option crluri1 "$crluri1" | |
[ -n "$crluri2" ] && set_ipsec_option crluri2 "$crluri2 " | |
[ -n "$ocspuri1" ] && set_ipsec_option ocspuri1 "$ocspuri1" | |
[ -n "$ocspuri2" ] && set_ipsec_option ocspuri2 "$ocspuri2" | |
[ -n "$baseuri" ] && set_ipsec_option baseuri "$baseuri" | |
[ -n "$also" ] && set_ipsec_option also "$also" | |
echo "ca $2" >> "$IPSEC_CONF" | |
write_ipsec_options | |
} | |
config_user() { | |
local user_enabled xauth name password | |
config_get_bool user_enabled "$1" enabled 0 | |
[ "$user_enabled" -eq 0 ] && return | |
config_get name "$1" name | |
config_get password "$1" password | |
config_get_bool xauth "$1" xauth | |
if [ $xauth -eq 1 -a -n "$name" -a -n "$password" ]; then | |
echo "$name : XAUTH \"$password\"" >> "$IPSEC_SECRETS" | |
fi | |
} | |
prepare_environment() { | |
local debug | |
mkdir -p "$(dirname "$IPSEC_CONF")" | |
for d in cacerts aacerts ocspcerts crls acerts private; do | |
mkdir -p "$IPSEC_D/$d" | |
chmod 700 "$IPSEC_D/$d" | |
done | |
if [ "$(readlink /etc/strongswan.conf 2>/dev/null)" != "$STRONGSWAN_CONF" ]; then | |
[ -f /etc/strongswan.conf ] && mv /etc/strongswan.conf /etc/strongswan.user.conf | |
ln -sf "$STRONGSWAN_CONF" /etc/strongswan.conf | |
fi | |
# ipsec.conf | |
cat > "$IPSEC_CONF" <<EOF | |
# generated by /etc/init.d/$NAME | |
version 2 | |
EOF | |
# ipsec.secrets | |
cat > "$IPSEC_SECRETS" <<EOF | |
# generated by /etc/init.d/$NAME | |
include /etc/ipsec.secrets | |
EOF | |
# strongswan.conf | |
config_get debug "$1" debug 0 | |
cat > "$STRONGSWAN_CONF" <<EOF | |
# generated by /etc/init.d/$NAME | |
charon { | |
filelog { | |
/var/log/charon.log { | |
time_format = %b %e %T | |
ike_name = yes | |
append = yes | |
default = $debug | |
flush_line = yes | |
} | |
} | |
load_modular = yes | |
plugins { | |
include /etc/strongswan.d/charon/*.conf | |
stroke { | |
secrets_file = "$IPSEC_SECRETS" | |
} | |
} | |
} | |
include /etc/strongswan.user.conf | |
include /etc/strongswan.d/*.conf | |
EOF | |
} | |
check_installation() { | |
if ! command -v ip >/dev/null; then | |
echo "ip command missing" >&2 | |
echo 'install with "opkg install ip"' >&2 | |
exit 1 | |
fi | |
for f in aes cbc hmac md5 sha1 sha256; do | |
if ! grep -qF "$f" /proc/crypto; then | |
echo "kmod-crypto-$f missing" >&2 | |
echo "install with \"opkg install kmod-crypto-$f\"" >&2 | |
exit 1 | |
fi | |
done | |
for m in authenc echainiv; do | |
if ! lsmod | grep -qF "$m"; then | |
echo "kmod-crypto-$f missing" >&2 | |
echo "install with \"opkg install kmod-crypto-$f\"" >&2 | |
exit 1 | |
fi | |
done | |
for f in aes gmp hmac kernel-netlink md5 random sha1 sha2 updown attr resolve; do | |
if [ ! -f /usr/lib/ipsec/plugins/libstrongswan-${f}.so ]; then | |
echo "/usr/lib/ipsec/plugins/$f missing" >&2 | |
echo "install with \"opkg install strongswan-mod-$f\"" >&2 | |
exit 1 | |
fi | |
done | |
} | |
config_all() | |
{ | |
config_load ipsec | |
config_foreach prepare_environment ipsec | |
config_foreach config_defaults defaults | |
config_foreach config_remote remote | |
config_foreach config_key key | |
config_load users | |
config_foreach config_user user | |
} | |
start_service() { | |
check_installation | |
config_all | |
procd_open_instance | |
procd_set_param respawn | |
procd_set_param command "$IPSEC_BIN" starter --nofork --conf "$IPSEC_CONF" | |
procd_set_param file \ | |
"$IPSEC_SECRETS" "$IPSEC_CONF" "$STRONGSWAN_CONF" /etc/config/ipsec | |
procd_close_instance | |
} | |
reload_service() { | |
config_all | |
"$IPSEC_BIN" rereadsecrets | |
"$IPSEC_BIN" update | |
killall -HUP charon | |
} | |
service_triggers() { | |
local wan_iface | |
network_find_wan wan_iface | |
if [ -n "$wan_iface" ]; then | |
procd_add_reload_interface_trigger "$wan_iface" | |
fi | |
procd_add_reload_trigger ipsec | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
How can I use this script?