# #
###############################################################################
-IPSEC_CONNECTION_CONFIG_SETTINGS="AUTH_MODE INACTIVITY_TIMEOUT LOCAL_ID LOCAL_PREFIX"
-IPSEC_CONNECTION_CONFIG_SETTINGS="${IPSEC_CONNECTION_CONFIG_SETTINGS} MODE PEER PSK"
-IPSEC_CONNECTION_CONFIG_SETTINGS="${IPSEC_CONNECTION_CONFIG_SETTINGS} REMOTE_ID REMOTE_PREFIX"
-IPSEC_CONNECTION_CONFIG_SETTINGS="${IPSEC_CONNECTION_CONFIG_SETTINGS} SECURITY_POLICY"
+IPSEC_CONNECTION_CONFIG_SETTINGS="\
+ AUTH_MODE \
+ DPD_ACTION \
+ DPD_DELAY \
+ DPD_TIMEOUT \
+ INACTIVITY_TIMEOUT \
+ LOCAL_ADDRESS \
+ LOCAL_ID \
+ LOCAL_PREFIX \
+ MODE \
+ PEER \
+ POOLS \
+ PSK \
+ REMOTE_ID \
+ REMOTE_PREFIX \
+ SECURITY_POLICY \
+ START_ACTION \
+ TYPE \
+ ENABLED"
+
+IPSEC_POOL_CONFIG_SETTINGS="\
+ DNS_SERVER \
+ NETWORK \
+ TYPE"
# Default values
-IPSEC_DEFAULT_MODE="tunnel"
IPSEC_DEFAULT_AUTH_MODE="PSK"
+IPSEC_DEFAULT_DPD_ACTION="restart"
+IPSEC_DEFAULT_DPD_DELAY="30"
+IPSEC_DEFAULT_DPD_TIMEOUT="120"
+IPSEC_DEFAULT_ENABLED="true"
IPSEC_DEFAULT_INACTIVITY_TIMEOUT="0"
+IPSEC_DEFAULT_MODE="tunnel"
IPSEC_DEFAULT_SECURITY_POLICY="system"
+IPSEC_DEFAULT_START_ACTION="on-demand"
+IPSEC_DEFAULT_TYPE="net-to-net"
IPSEC_VALID_MODES="gre-transport tunnel vti"
IPSEC_VALID_AUTH_MODES="PSK"
case "${action}" in
connection)
- cli_ipsec_connection $@
+ cli_ipsec_connection "$@"
+ ;;
+ pool)
+ cli_ipsec_pool "$@"
;;
*)
error "Unrecognized argument: ${action}"
shift 2
case "${key}" in
- authentication|inactivity_timeout|local|mode|peer|remote|security_policy)
- ipsec_connection_${key} ${connection} $@
+ authentication|down|disable|dpd|enable|inactivity_timeout|local|mode|peer|pool|remote|security_policy|start_action|up)
+ ipsec_connection_${key} ${connection} "$@"
;;
show)
cli_ipsec_connection_show "${connection}"
case "${action}" in
new)
- ipsec_connection_new $@
+ ipsec_connection_new "$@"
+ ;;
+ destroy)
+ cli_ipsec_connection_destroy "$@"
+ ;;
+ ""|*)
+ if [ -n "${action}" ]; then
+ error "Unrecognized argument: '${action}'"
+ fi
+ exit ${EXIT_ERROR}
+ ;;
+ esac
+ fi
+}
+
+cli_ipsec_pool() {
+ if ipsec_pool_exists ${1}; then
+ local pool=${1}
+ local key=${2}
+ key=${key//-/_}
+ shift 2
+
+ case "${key}" in
+ dns_server|network)
+ ipsec_pool_${key} ${pool} "$@"
+ ;;
+ show)
+ cli_ipsec_pool_show "${pool}"
+ exit $?
+ ;;
+ *)
+ error "Unrecognized argument: ${key}"
+ exit ${EXIT_ERROR}
+ ;;
+ esac
+ else
+ local action=${1}
+ shift
+
+ case "${action}" in
+ new)
+ ipsec_pool_new "$@"
;;
destroy)
- ipsec_connection_destroy $@
+ ipsec_pool_destroy "$@"
;;
""|*)
if [ -n "${action}" ]; then
fi
}
+cli_ipsec_connection_destroy() {
+ local connection="${1}"
+
+ if ! ipsec_connection_destroy "${connection}"; then
+ return ${EXIT_ERROR}
+ fi
+
+ # Inform strongswan about the changes
+ ipsec_strongswan_load
+
+ # Configure strongswan autostart
+ ipsec_strongswan_autostart
+}
+
cli_ipsec_connection_show() {
local connection="${1}"
return ${EXIT_OK}
}
+ipsec_connection_disable() {
+ local connection=${1}
+
+ if ! ipsec_connection_write_config_key "${connection}" "ENABLED" "false"; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+
+ # Configure strongswan autostart
+ ipsec_strongswan_autostart
+}
+
+ipsec_connection_enable() {
+ local connection=${1}
+
+ if ! ipsec_connection_write_config_key "${connection}" "ENABLED" "true"; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+
+ # Configure strongswan autostart
+ ipsec_strongswan_autostart
+}
+
# This function writes all values to a via ${connection} specificated VPN IPsec configuration file
ipsec_connection_write_config() {
assert [ $# -ge 1 ]
if [ $# -eq 0 ] && [ -n "${IPSEC_CONNECTION_CONFIG_SETTINGS}" ]; then
list_append args ${IPSEC_CONNECTION_CONFIG_SETTINGS}
else
- list_append args $@
+ list_append args "$@"
fi
local path="${NETWORK_IPSEC_CONNS_DIR}/${connection}/settings"
[ -d "${path}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
}
+# Determines if strongswan should be automatically started
+# when the system boots up.
+ipsec_strongswan_autostart() {
+ local autostart_needed="false"
+
+ local connection
+ for connection in $(ipsec_list_connections); do
+ local ENABLED
+
+ if ! ipsec_connection_read_config "${connection}" "ENABLED"; then
+ log WARNING "Could not read configuation"
+ continue
+ fi
+
+ if enabled ENABLED; then
+ autostart_needed="true"
+ break
+ fi
+ done
+
+ # Start strongswan when we need it and when it is not yet enabled
+ if ${autostart_needed}; then
+ if ! service_is_enabled "strongswan"; then
+ service_enable "strongswan"
+ fi
+
+ if ! service_is_active "strongswan"; then
+ service_start "strongswan"
+ fi
+
+ # Disable strongswan when we do not need it but it is enabled
+ elif ! ${autostart_needed}; then
+ if service_is_enabled "strongswan"; then
+ service_disable "strongswan"
+ fi
+
+ if service_is_active "strongswan"; then
+ service_stop "strongswan"
+ fi
+ fi
+}
+
+ipsec_strongswan_load() {
+ # Do nothing if strongswan is not running
+ if ! service_is_active "strongswan"; then
+ return ${EXIT_OK}
+ fi
+
+ if ! cmd swanctl --load-all; then
+ log ERROR "Could not reload strongswan config"
+ return ${EXIT_ERROR}
+ fi
+}
+
# Reloads the connection after config changes
ipsec_reload() {
- return ${EXIT_TRUE}
+ local connection=${1}
+
+ local ENABLED
+
+ if ! ipsec_connection_read_config "${connection}" "ENABLED"; then
+ log ERROR "Could not read configuration for IPsec connection ${connection}"
+ return ${EXIT_ERROR}
+ fi
+
+ if enabled ENABLED; then
+ if ! ipsec_connection_to_strongswan ${connection}; then
+ log ERROR "Could not generate strongswan config for ${connnection}"
+ return ${EXIT_ERROR}
+ fi
+ else
+ log DEBUG "Deleting strongswan config ${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
+ unlink "${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
+ fi
+
+ ipsec_strongswan_load
}
# Handle the cli after authentification
case ${cmd} in
mode)
- ipsec_connection_authentication_mode "${connection}" $@
+ ipsec_connection_authentication_mode "${connection}" "$@"
;;
pre-shared-key)
- ipsec_connection_authentication_psk "${connection}" $@
+ ipsec_connection_authentication_psk "${connection}" "$@"
;;
*)
log ERROR "Unrecognized argument: ${cmd}"
return ${EXIT_OK}
}
+ipsec_connection_up() {
+ local connection="${1}"
+
+ if ! ipsec_connection_exists "${connection}"; then
+ error "No such VPN IPsec connection: ${connection}"
+ return ${EXIT_ERROR}
+ fi
+
+ cmd swanctl --initiate --child "${connection}"
+}
+
+ipsec_connection_down() {
+ local connection="${1}"
+
+ if ! ipsec_connection_exists "${connection}"; then
+ error "No such VPN IPsec connection: ${connection}"
+ return ${EXIT_ERROR}
+ fi
+
+ cmd swanctl --terminate --ike "${connection}"
+}
+
+# Handle the cli after authentification
+ipsec_connection_dpd() {
+ if [ ! $# -gt 1 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+
+ local connection=${1}
+ local cmd=${2}
+ shift 2
+
+ case ${cmd} in
+ action)
+ ipsec_connection_dpd_action "${connection}" "$@"
+ ;;
+ delay)
+ ipsec_connection_dpd_delay "${connection}" "$@"
+ ;;
+ timeout)
+ ipsec_connection_dpd_timeout "${connection}" "$@"
+ ;;
+ *)
+ log ERROR "Unrecognized argument: ${cmd}"
+ return ${EXIT_ERROR}
+ ;;
+ esac
+}
+
+# Set the default dpd action
+ipsec_connection_dpd_action() {
+ if [ ! $# -eq 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+ local connection=${1}
+ local action=${2}
+
+ if ! isoneof action "restart" "clear"; then
+ log ERROR "dpd action '${action}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipsec_connection_write_config_key "${connection}" "DPD_ACTION" ${action}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+}
+
+# Set the dpd delay
+ipsec_connection_dpd_delay() {
+ if [ ! $# -ge 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+
+ local connection=${1}
+ shift 1
+ local value=$@
+
+ if ! isinteger value; then
+ value=$(parse_time "$@")
+ if [ ! $? -eq 0 ]; then
+ log ERROR "Parsing the passed time was not sucessful please check the passed values."
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ if [ ${value} -lt 0 ]; then
+ log ERROR "The passed time value must be in the sum greater or equal zero seconds."
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipsec_connection_write_config_key "${connection}" "DPD_DELAY" ${value}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+
+ return ${EXIT_OK}
+}
+
+# Set the dpd timeout
+ipsec_connection_dpd_timeout() {
+ if [ ! $# -ge 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+
+ local connection=${1}
+ shift 1
+ local value=$@
+
+ if ! isinteger value; then
+ value=$(parse_time "$@")
+ if [ ! $? -eq 0 ]; then
+ log ERROR "Parsing the passed time was not sucessful please check the passed values."
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ if [ ${value} -le 0 ]; then
+ log ERROR "The passed time value must be in the sum greater or equal zero seconds."
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipsec_connection_write_config_key "${connection}" "DPD_TIMEOUT" ${value}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+
+ return ${EXIT_OK}
+}
+
# Handle the cli after local
ipsec_connection_local() {
if [ ! $# -ge 2 ]; then
shift 2
case ${cmd} in
+ address)
+ ipsec_connection_local_address "${connection}" "$@"
+ ;;
id)
- ipsec_connection_id "${connection}" "LOCAL" $@
+ ipsec_connection_id "${connection}" "LOCAL" "$@"
;;
prefix)
- ipsec_connection_prefix "${connection}" "LOCAL" $@
+ ipsec_connection_prefix "${connection}" "LOCAL" "$@"
;;
*)
log ERROR "Unrecognized argument: ${cmd}"
return ${EXIT_OK}
}
+# Set the local address
+ipsec_connection_local_address() {
+ if [ ! $# -eq 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+ local connection=${1}
+ local local_address=${2}
+
+ if ! ipsec_connection_check_peer ${local_address}; then
+ log ERROR "Local address '${local_address}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipsec_connection_write_config_key "${connection}" "LOCAL_ADDRESS" ${local_address}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+
+ return ${EXIT_OK}
+}
+
# Set the peer to connect to
ipsec_connection_peer() {
if [ ! $# -eq 2 ]; then
log ERROR "Id '${id}' is invalid"
return ${EXIT_ERROR}
fi
-
+
if ! ipsec_connection_write_config_key "${connection}" "${type}_ID" ${id}; then
log ERROR "Could not write configuration settings"
return ${EXIT_ERROR}
fi
-
+
return ${EXIT_OK}
}
-# Set the local or remote prefix
+# Set the local or remote prefix
ipsec_connection_prefix() {
if [ ! $# -ge 3 ]; then
log ERROR "Not enough arguments"
local connection=${1}
local type=${2}
shift 2
-
+
local _prefix="${type}_PREFIX"
local "${_prefix}"
if ! ipsec_connection_read_config "${connection}" "${_prefix}"; then
return ${EXIT_OK}
}
-# Handle the cli after remote
-ipsec_connection_remote() {
+# Set the pools to use
+ipsec_connection_pool() {
if [ ! $# -ge 2 ]; then
log ERROR "Not enough arguments"
return ${EXIT_ERROR}
fi
-
local connection=${1}
- local cmd=${2}
- shift 2
-
- case ${cmd} in
- id)
- ipsec_connection_id "${connection}" "REMOTE" $@
- ;;
-
- prefix)
- ipsec_connection_prefix "${connection}" "REMOTE" $@
- ;;
- *)
- log ERROR "Unrecognized argument: ${cmd}"
- return ${EXIT_ERROR}
- ;;
- esac
-
- return ${EXIT_OK}
-}
+ shift
-# Set the inactivity timeout
-ipsec_connection_inactivity_timeout() {
- if [ ! $# -ge 2 ]; then
- log ERROR "Not enough arguments"
+ local POOLS
+ if ! ipsec_connection_read_config "${connection}" "POOLS"; then
return ${EXIT_ERROR}
fi
- local connection=${1}
- shift 1
- local value=$@
+ # Remove duplicated entries to proceed the list safely
+ assign "POOLS" "$(list_unique ${POOLS})"
- if ! isinteger value; then
- value=$(parse_time $@)
- if [ ! $? -eq 0 ]; then
- log ERROR "Parsing the passed time was not sucessful please check the passed values."
- return ${EXIT_ERROR}
- fi
- fi
+ local pools_added
+ local pools_removed
+ local pools_set
- if [ ${value} -le 0 ]; then
+ while [ $# -gt 0 ]; do
+ local arg="${1}"
+
+ case "${arg}" in
+ +*)
+ list_append pools_added "${arg:1}"
+ ;;
+ -*)
+ list_append pools_removed "${arg:1}"
+ ;;
+ [A-Za-z0-9]*)
+ list_append pools_set "${arg}"
+ ;;
+ *)
+ error "Invalid argument: ${arg}"
+ return ${EXIT_ERROR}
+ ;;
+ esac
+ shift
+ done
+
+ # Check if the user is trying a mixed operation
+ if ! list_is_empty pools_set && (! list_is_empty pools_added || ! list_is_empty pools_removed); then
+ error "You cannot reset the pools list and add or remove pools at the same time"
+ return ${EXIT_ERROR}
+ fi
+
+ # Set new pools list
+ if ! list_is_empty pools_set; then
+ # Check if all pools are valid
+ local pool
+ for pool in ${pools_set}; do
+ if ! ipsec_pool_exists ${pool} || ! ipsec_pool_check_config ${pool}; then
+ error "Pool ${pool} is not valid"
+ return ${EXIT_ERROR}
+ fi
+ done
+
+ assign "POOLS" "${pools_set}"
+
+ # Perform incremental updates
+ else
+ local pool
+
+ # Perform all removals
+ for pool in ${pools_removed}; do
+ if ! list_remove "POOLS" ${pool}; then
+ warning "${pool} was not on the list and could not be removed"
+ fi
+ done
+
+
+ for pool in ${pools_added}; do
+ if ipsec_pool_exists ${pool} && ipsec_pool_check_config ${pool}; then
+ if ! list_append_unique "POOLS" ${pool}; then
+ warning "${pool} is already on the prefix list"
+ fi
+ else
+ warning "${pool} is not a valid pool"
+ fi
+ done
+ fi
+
+ # Check if the list contain at least one valid pool
+ if list_is_empty POOLS; then
+ error "Cannot save an empty pool list"
+ return ${EXIT_ERROR}
+ fi
+
+ # Save everything
+ if ! ipsec_connection_write_config_key "${connection}" "POOLS" ${POOLS}; then
+ log ERROR "Could not write configuration settings"
+ fi
+
+ return ${EXIT_OK}
+}
+
+# Handle the cli after remote
+ipsec_connection_remote() {
+ if [ ! $# -ge 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+
+ local connection=${1}
+ local cmd=${2}
+ shift 2
+
+ case ${cmd} in
+ id)
+ ipsec_connection_id "${connection}" "REMOTE" "$@"
+ ;;
+
+ prefix)
+ ipsec_connection_prefix "${connection}" "REMOTE" "$@"
+ ;;
+ *)
+ log ERROR "Unrecognized argument: ${cmd}"
+ return ${EXIT_ERROR}
+ ;;
+ esac
+
+ return ${EXIT_OK}
+}
+
+# Set the inactivity timeout
+ipsec_connection_inactivity_timeout() {
+ if [ ! $# -ge 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+
+ local connection=${1}
+ shift 1
+ local value=$@
+
+ if ! isinteger value; then
+ value=$(parse_time "$@")
+ if [ ! $? -eq 0 ]; then
+ log ERROR "Parsing the passed time was not sucessful please check the passed values."
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ if [ ${value} -le 0 ]; then
log ERROR "The passed time value must be in the sum greater zero seconds."
return ${EXIT_ERROR}
fi
return ${EXIT_OK}
}
+# Set the default start action
+ipsec_connection_start_action() {
+ if [ ! $# -eq 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+ local connection=${1}
+ local action=${2}
+
+ if ! isoneof action "on-demand" "always-on"; then
+ log ERROR "Start action '${action}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipsec_connection_write_config_key "${connection}" "START_ACTION" ${action}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+}
# Set the security policy to use
ipsec_connection_security_policy() {
# Function that creates one VPN IPsec connection
ipsec_connection_new() {
- if [ $# -gt 1 ]; then
+ if [ $# -gt 2 ]; then
error "Too many arguments"
return ${EXIT_ERROR}
fi
local connection="${1}"
+ local type="${2}"
+
if ! isset connection; then
error "Please provide a connection name"
return ${EXIT_ERROR}
return ${EXIT_ERROR}
fi
+ # Set TYPE to default if not set by the user
+ if ! isset type; then
+ type="${IPSEC_DEFAULT_TYPE}"
+ fi
+
+ if ! isoneof "type" "net-to-net" "host-to-net"; then
+ error "Type is invalid"
+ return ${EXIT_ERROR}
+ fi
+
log DEBUG "Creating VPN IPsec connection ${connection}"
if ! mkdir -p "${NETWORK_IPSEC_CONNS_DIR}/${connection}"; then
local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
- MODE=${IPSEC_DEFAULT_MODE}
AUTH_MODE=${IPSEC_DEFAULT_AUTH_MODE}
+ DPD_ACTION=${IPSEC_DEFAULT_DPD_ACTION}
+ DPD_DELAY=${IPSEC_DEFAULT_DPD_DELAY}
+ DPD_TIMEOUT=${IPSEC_DEFAULT_DPD_TIMEOUT}
+ ENABLED=${IPSEC_DEFAULT_ENABLED}
+ MODE=${IPSEC_DEFAULT_MODE}
+ START_ACTION=${IPSEC_DEFAULT_START_ACTION}
+ TYPE="${type}"
+
INACTIVITY_TIMEOUT=${IPSEC_DEFAULT_INACTIVITY_TIMEOUT}
SECURITY_POLICY=${IPSEC_DEFAULT_SECURITY_POLICY}
log ERROR "Could not write new config file"
return ${EXIT_ERROR}
fi
+
+ # Configure strongswan autostart
+ ipsec_strongswan_autostart
}
# Function that deletes based on the passed parameters one ore more vpn security policies
ipsec_connection_destroy() {
local connection
- for connection in $@; do
+ for connection in "$@"; do
if ! ipsec_connection_exists "${connection}"; then
log ERROR "The VPN IPsec connection ${connection} does not exist."
continue
fi
log DEBUG "Deleting VPN IPsec connection ${connection}"
+
+ # Delete strongswan configuration file
+ file_delete "${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
+
if ! rm -rf "${NETWORK_IPSEC_CONNS_DIR}/${connection}"; then
log ERROR "Deleting the VPN IPsec connection ${connection} was not sucessful"
return ${EXIT_ERROR}
fi
+
done
}
ipsec_connection_to_strongswan() {
local connection="${1}"
+ log DEBUG "Generating IPsec configuration for ${connection}"
# Read the config settings
local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
return ${EXIT_ERROR}
fi
+ # Is DPD enabled?
+ local dpd="false"
+ if isset DPD_DELAY && isinteger DPD_DELAY && [ ${DPD_DELAY} -gt 0 ]; then
+ dpd="true"
+ fi
+
+ # Write configuration header
+ config_header "strongSwan configuration for ${connection}"
+
print_indent 0 "connections {"
print_indent 1 "${connection} {"
esac
print # empty line
- # XXX Local Address
+ # Always only keep one connection open at a time
+ print_indent 2 "# Unique IDs"
+ print_indent 2 "unique = replace"
+ print
+
+ # Local Address
+ print_indent 2 "# Local Address"
+ if isset LOCAL_ADDRESS; then
+ print_indent 2 "local_addrs = ${LOCAL_ADDRESS}"
+ else
+ print_indent 2 "local_addrs = %any"
+ fi
+ print
# Remote Address
print_indent 2 "# Remote Address"
# IKE Proposals
print_indent 2 "# IKE Proposals"
- print_indent 2 "proposals = $(vpn_security_policies_make_ah_proposal ${SECURITY_POLICY})"
+ print_indent 2 "proposals = $(vpn_security_policies_make_ike_proposal ${SECURITY_POLICY})"
print
- # XXX DPD Settings
+ # DPD Settings
+ if enabled dpd; then
+ print_indent 2 "# Dead Peer Detection"
+ print_indent 2 "dpd_delay = ${DPD_DELAY}"
+
+ if isset DPD_TIMEOUT; then
+ print_indent 2 "dpd_timeout = ${DPD_TIMEOUT}"
+ fi
+
+ print
+ fi
# Fragmentation
print_indent 2 "# Fragmentation"
print_indent 2 "fragmentation = yes"
print
+
+ # Host-to-Net specific settings
+ case "${TYPE}" in
+ host-to-net)
+ # Pools
+ if isset POOLS; then
+ print_indent 2 "# Pools"
+ print_indent 2 "pools = $(list_join POOLS ", ")"
+ print
+ fi
+ ;;
+ esac
+
# Local
print_indent 2 "local {"
# Traffic Selectors
- # Local Prefixes
- if isset LOCAL_PREFIX; then
- print_indent 4 "local_ts = $(list_join LOCAL_PREFIX ,)"
- else
- print_indent 4 "local_ts = dynamic"
- fi
+ case "${MODE}" in
+ gre-*)
+ print_indent 4 "local_ts = dynamic[gre]"
+ print_indent 4 "remote_ts = dynamic[gre]"
+ ;;
+ *)
+ # Local Prefixes
+ if isset LOCAL_PREFIX; then
+ print_indent 4 "local_ts = $(list_join LOCAL_PREFIX ,)"
+ else
+ print_indent 4 "local_ts = dynamic"
+ fi
- # Remote Prefixes
- if isset REMOTE_PREFIX; then
- print_indent 4 "remote_ts = $(list_join REMOTE_PREFIX ,)"
- else
- print_indent 4 "remote_ts = dynamic"
- fi
+ # Remote Prefixes
+ if isset REMOTE_PREFIX; then
+ print_indent 4 "remote_ts = $(list_join REMOTE_PREFIX ,)"
+ else
+ print_indent 4 "remote_ts = dynamic"
+ fi
+ ;;
+ esac
print
+ # Netfilter Marks
+ case "${MODE}" in
+ vti)
+ print_indent 4 "# Netfilter Marks"
+ print_indent 4 "mark_in = %unique"
+ print_indent 4 "mark_out = %unique"
+ print
+ ;;
+ esac
+
+ # Dead Peer Detection
+ if enabled dpd; then
+ print_indent 4 "# Dead Peer Detection"
+ print_indent 4 "dpd_action = ${DPD_ACTION}"
+ print
+ fi
+
# Rekeying
if isset LIFETIME; then
print_indent 4 "# Rekey Time"
print
fi
- # XXX Always-On
- print_indent 4 "start_action = start"
- print_indent 4 "close_action = start"
+ # Net-to-Net specific settings
+ case "${TYPE}" in
+ net-to-net)
+ # Start Action
+ print_indent 4 "# Start Action"
+ case "${START_ACTION}" in
+ on-demand)
+ print_indent 4 "start_action = trap"
+ print_indent 4 "close_action = trap"
+ ;;
+ wait)
+ print_indent 4 "start_action = none"
+ print_indent 4 "close_action = none"
+ ;;
+ always-on|*)
+ print_indent 4 "start_action = start"
+ print_indent 4 "close_action = start"
+ ;;
+ esac
+ print
+ ;;
+ esac
print_indent 3 "}"
print_indent 2 "}"
print_indent 0 "}"
}
+
+# This function writes all values to a via ${pool} specificated VPN IPsec pool configuration file
+ipsec_pool_write_config() {
+ assert [ $# -ge 1 ]
+
+ local pool="${1}"
+
+ if ! ipsec_pool_exists "${pool}"; then
+ log ERROR "No such VPN IPsec pool: ${pool}"
+ return ${EXIT_ERROR}
+ fi
+
+ local path="${NETWORK_IPSEC_POOLS_DIR}/${pool}/settings"
+
+ if ! settings_write "${path}" ${IPSEC_POOL_CONFIG_SETTINGS}; then
+ log ERROR "Could not write configuration settings for VPN IPsec pool ${pool}"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipsec_pool_reload ${pool}; then
+ log WARNING "Could not reload IPsec pool ${pool}"
+ fi
+
+ # When we get here the writing of the config file was successful
+ return ${EXIT_OK}
+}
+
+# This funtion writes the value for one key to a via ${connection} specificated
+# VPN IPsec pool configuration file
+ipsec_pool_write_config_key() {
+ assert [ $# -ge 3 ]
+
+ local pool=${1}
+ local key=${2}
+ shift 2
+
+ local value="$@"
+
+ if ! ipsec_pool_exists "${pool}"; then
+ log ERROR "No such VPN IPsec pool: ${pool}"
+ return ${EXIT_ERROR}
+ fi
+
+ log DEBUG "Set '${key}' to new value '${value}' in VPN IPsec pool '${pool}'"
+
+ local ${IPSEC_POOL_CONFIG_SETTINGS}
+
+ # Read the config settings
+ if ! ipsec_pool_read_config "${pool}"; then
+ return ${EXIT_ERROR}
+ fi
+
+ # Set the key to a new value
+ assign "${key}" "${value}"
+
+ if ! ipsec_pool_write_config "${pool}"; then
+ return ${EXIT_ERROR}
+ fi
+
+ return ${EXIT_TRUE}
+}
+
+# Reads one or more keys out of a settings file or all if no key is provided.
+ipsec_pool_read_config() {
+ assert [ $# -ge 1 ]
+
+ local pool="${1}"
+ shift 1
+
+ if ! ipsec_pool_exists "${pool}"; then
+ log ERROR "No such VPN IPsec pool : ${pool}"
+ return ${EXIT_ERROR}
+ fi
+
+ local args
+ if [ $# -eq 0 ] && [ -n "${IPSEC_POOL_CONFIG_SETTINGS}" ]; then
+ list_append args ${IPSEC_POOL_CONFIG_SETTINGS}
+ else
+ list_append args "$@"
+ fi
+
+ local path="${NETWORK_IPSEC_POOLS_DIR}/${pool}/settings"
+
+ if ! settings_read "${path}" ${args}; then
+ log ERROR "Could not read settings for VPN IPsec pool ${pool}"
+ return ${EXIT_ERROR}
+ fi
+}
+
+# This function checks if a vpn IPsec pool exists
+# Returns True when yes and false when not
+ipsec_pool_exists() {
+ assert [ $# -eq 1 ]
+
+ local pool=${1}
+
+ local path="${NETWORK_IPSEC_POOLS_DIR}/${pool}"
+
+ [ -d "${path}" ] && return ${EXIT_TRUE} || return ${EXIT_FALSE}
+}
+
+# This function checks if a VPN IPsec pool name is valid
+# Allowed are only A-Za-z0-9
+ipsec_pool_check_name() {
+ assert [ $# -eq 1 ]
+
+ local pool=${1}
+
+ # These are special words in strongswan
+ if isoneof pool dhcp radius; then
+ return ${EXIT_ERROR}
+ fi
+
+ [[ "${pool}" =~ [^[:alnum:]$] ]]
+}
+
+ipsec_pool_new() {
+ if [ $# -gt 1 ]; then
+ error "Too many arguments"
+ return ${EXIT_ERROR}
+ fi
+
+ local pool="${1}"
+ if ! isset pool; then
+ error "Please provide a pool name"
+ return ${EXIT_ERROR}
+ fi
+
+ # Check for duplicates
+ if ipsec_pool_exists "${pool}"; then
+ error "The VPN IPsec pool ${pool} already exists"
+ return ${EXIT_ERROR}
+ fi
+
+ # Check if the name of the connection is valid
+ if ipsec_pool_check_name "${pool}"; then
+ error "'${pool}' contains illegal characters"
+ return ${EXIT_ERROR}
+ fi
+
+ log DEBUG "Creating VPN IPsec pool ${pool}"
+
+ if ! mkdir -p "${NETWORK_IPSEC_POOLS_DIR}/${pool}"; then
+ log ERROR "Could not create config directory for ${pool}"
+ return ${EXIT_ERROR}
+ fi
+
+ local ${IPSEC_POOL_CONFIG_SETTINGS}
+
+ if ! ipsec_pool_write_config "${pool}"; then
+ log ERROR "Could not write new config file"
+ return ${EXIT_ERROR}
+ fi
+}
+
+# Function that deletes based on the passed parameters
+# one ore more vpn ipsec pools
+ipsec_pool_destroy() {
+ local pool
+ for pool in "$@"; do
+ if ! ipsec_pool_exists "${pool}"; then
+ log ERROR "The VPN IPsec pool ${pool} does not exist."
+ continue
+ fi
+
+ log DEBUG "Deleting VPN IPsec pool ${pool}"
+
+ if ! rm -rf "${NETWORK_IPSEC_POOLS_DIR}/${pool}"; then
+ log ERROR "Deleting the VPN IPsec pool ${pool} was not sucessful"
+ return ${EXIT_ERROR}
+ fi
+ done
+}
+
+ipsec_pool_set_type() {
+ local pool=${1}
+ local ip=${2}
+ assert isset pool
+ assert isset ip
+
+ local type=$(ip_detect_protocol ${ip})
+
+ if ! isset type; then
+ error "Cannot detect IP protocol of ${ip}"
+ return ${EXIT_ERROR}
+ else
+ log DEBUG "IP protocol of ${ip} is ${type}"
+ if ! ipsec_pool_write_config_key "${pool}" "TYPE" ${type}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+ fi
+}
+
+ipsec_pool_network() {
+ if [ ! $# -eq 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+ local pool=${1}
+ local network=${2}
+
+ local TYPE
+ if ! ipsec_pool_read_config ${pool} "TYPE"; then
+ error "Failed to read configuration settings for pool '${pool}'"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! isset TYPE; then
+ if ! ip_net_is_valid ${network}; then
+ log ERROR "Network '${network}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipsec_pool_set_type ${pool} ${network}; then
+ log ERROR "Could not set type for IPsec pool ${pool}"
+ return ${EXIT_ERROR}
+ fi
+ else
+ if ! ${TYPE}_net_is_valid ${network}; then
+ log ERROR "Network '${network}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ if ! ipsec_pool_write_config_key "${pool}" "NETWORK" ${network}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+}
+
+ipsec_pool_dns_server() {
+ if [ ! $# -eq 2 ]; then
+ log ERROR "Not enough arguments"
+ return ${EXIT_ERROR}
+ fi
+ local pool=${1}
+ local dns_server=${2}
+
+ local TYPE
+ if ! ipsec_pool_read_config ${pool} "TYPE"; then
+ error "Failed to read configuration settings for pool '${pool}'"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! isset TYPE; then
+ if ! ip_is_valid ${dns_server}; then
+ log ERROR "DNS server '${dns_server}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! ipsec_pool_set_type ${pool} ${dns_server}; then
+ log ERROR "Could not set type for IPsec pool ${pool}"
+ return ${EXIT_ERROR}
+ fi
+ else
+ if ! ${TYPE}_is_valid ${dns_server}; then
+ log ERROR "DNS server '${dns_server}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ if ! ipsec_pool_write_config_key "${pool}" "DNS_SERVER" ${dns_server}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+}
+
+ipsec_pool_check_config() {
+ local pool=${1}
+ assert isset pool
+
+ local ${IPSEC_POOL_CONFIG_SETTINGS}
+ if ! ipsec_pool_read_config "${pool}"; then
+ log ERROR "Could not read configuration settings"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! isset NETWORK; then
+ log ERROR "Network for IPSec pool ${pool} is not set"
+ return ${EXIT_ERROR}
+ fi
+
+ if ! isset TYPE; then
+ TYPE=$(ip_detect_protocol ${NETWORK})
+ log DEBUG "IP protocol of ${NETWORK} is ${TYPE}"
+ if ! isset TYPE; then
+ error "Cannot detect IP protocol of ${NETWORK}"
+ return ${EXIT_ERROR}
+ else
+ if ! ipsec_pool_write_config_key "${pool}" "TYPE" ${TYPE}; then
+ log ERROR "Could not write configuration settings"
+ return ${EXIT_ERROR}
+ fi
+ fi
+ else
+ if ! ${TYPE}_net_is_valid ${NETWORK}; then
+ log ERROR "NETWORK '${NETWORK}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+
+ if isset DNS_SERVER && ! ${TYPE}_is_valid ${DNS_SERVER}; then
+ log ERROR "DNS server '${DNS_SERVER}' is invalid"
+ return ${EXIT_ERROR}
+ fi
+ fi
+
+ return ${EXIT_OK}
+}
+
+ipsec_pool_reload() {
+ local pool=${1}
+
+ if ! ipsec_pool_to_strongswan ${pool}; then
+ log ERROR "Could not generate strongswan config for ${pool}"
+ return ${EXIT_ERROR}
+ fi
+
+ ipsec_strongswan_load
+}
+
+ipsec_pool_to_strongswan() {
+ local pool=${1}
+
+ log DEBUG "Generating IPsec pool config for ${pool}"
+
+ local ${IPSEC_POOL_CONFIG_SETTINGS}
+ if ! ipsec_pool_read_config "${pool}"; then
+ return ${EXIT_ERROR}
+ fi
+
+ if isset NETWORK && ! ipsec_pool_check_config "${pool}"; then
+ log ERROR "Configuration of ${pool} seems to be invalid"
+ return ${EXIT_ERROR}
+ fi
+
+ local path="${NETWORK_IPSEC_SWANCTL_POOLS_DIR}/${pool}.conf"
+
+ (
+ config_header "strongSwan pool configuration"
+
+ if isset NETWORK; then
+ print_indent 0 "pools {"
+
+ print_indent 1 "${pool} {"
+ print_indent 2 "addrs = ${NETWORK}"
+
+ if isset DNS_SERVER; then
+ print_indent 2 "dns = ${DNS_SERVER}"
+ fi
+
+ print_indent 1 "}"
+ print_indent 0 "}"
+ fi
+ ) > ${path}
+}