]> git.ipfire.org Git - people/ms/network.git/blobdiff - src/functions/functions.ipsec
security-policies: Rename AH proposals to IKE proposals
[people/ms/network.git] / src / functions / functions.ipsec
index cd1a50a1d7fc73cdf9d19400f4bfa0e966758379..61bdcb28460ce880e71d298868fb67b3a2ddaee6 100644 (file)
 #                                                                             #
 ###############################################################################
 
-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 \
+       PSK \
+       REMOTE_ID \
+       REMOTE_PREFIX \
+       SECURITY_POLICY"
 
 # 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_INACTIVITY_TIMEOUT="0"
+IPSEC_DEFAULT_MODE="tunnel"
 IPSEC_DEFAULT_SECURITY_POLICY="system"
+IPSEC_DEFAULT_START_ACTION="on-demand"
 
 IPSEC_VALID_MODES="gre-transport tunnel vti"
 IPSEC_VALID_AUTH_MODES="PSK"
@@ -56,7 +71,7 @@ cli_ipsec_connection() {
                shift 2
 
                case "${key}" in
-                       authentication|inactivity-timout|local|mode|peer|remote|security-policy)
+                       authentication|down|dpd|inactivity_timeout|local|mode|peer|remote|security_policy|start_action|up)
                                ipsec_connection_${key} ${connection} $@
                                ;;
                        show)
@@ -334,12 +349,157 @@ ipsec_connection_authentication_psk() {
                log ERROR "Not enough arguments"
                return ${EXIT_ERROR}
        fi
+
        local connection=${1}
        local psk=${2}
 
-       # TODO Check if psk is valid 
+       local length=${#psk}
+
+       if [ ${length} -lt 4 ]; then
+               error "The PSK must be longer than four characters"
+               return ${EXIT_ERROR}
+       fi
+
+       if [ ${length} -gt 128 ]; then
+               error "The PSK cannot be longer than 128 characters"
+               return ${EXIT_ERROR}
+       fi
+
+       if ! ipsec_connection_write_config_key "${connection}" "PSK" "${psk}"; then
+               log ERROR "Could not write configuration settings"
+               return ${EXIT_ERROR}
+       fi
+
+       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
 
-       if ! ipsec_connection_write_config_key "${connection}" "PSK" ${psk}; then
+       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
@@ -359,6 +519,9 @@ ipsec_connection_local() {
        shift 2
 
        case ${cmd} in
+               address)
+                       ipsec_connection_local_address "${connection}" $@
+                       ;;
                id)
                        ipsec_connection_id "${connection}" "LOCAL" $@
                        ;;
@@ -396,6 +559,28 @@ ipsec_connection_mode() {
        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
@@ -522,7 +707,7 @@ ipsec_connection_prefix() {
                                        warning "${prefix} is already on the prefix list"
                                fi
                        else
-                               warning "${prefix} is not a valiv IP net and could not be added"
+                               warning "${prefix} is not a valid IP network and could not be added"
                        fi
                done
        fi
@@ -601,6 +786,25 @@ ipsec_connection_inactivity_timeout() {
        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() {
@@ -691,8 +895,13 @@ ipsec_connection_new() {
 
        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}
+       MODE=${IPSEC_DEFAULT_MODE}
+       START_ACTION=${IPSEC_DEFAULT_START_ACTION}
+
        INACTIVITY_TIMEOUT=${IPSEC_DEFAULT_INACTIVITY_TIMEOUT}
        SECURITY_POLICY=${IPSEC_DEFAULT_SECURITY_POLICY}
 
@@ -718,3 +927,279 @@ ipsec_connection_destroy() {
                fi
        done
 }
+
+# List all ipsec connections
+ipsec_list_connections() {
+       local connection
+       for connection in ${NETWORK_IPSEC_CONNS_DIR}/*; do
+               [ -d ${connection} ] || continue
+               basename ${connection}
+       done
+}
+
+ipsec_connection_to_strongswan() {
+       local connection="${1}"
+
+       # Read the config settings
+       local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
+       if ! ipsec_connection_read_config "${connection}"; then
+               error "Could not read the connection ${connection}"
+               return ${EXIT_ERROR}
+       fi
+
+       local path="${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf"
+
+       (
+               # Write the connection section
+               _ipsec_connection_to_strongswan_connection "${connection}"
+
+               # Write the secrets section
+               _ipsec_connection_to_strongswan_secrets "${connection}"
+
+       ) > ${path}
+}
+
+_ipsec_connection_to_strongswan_connection() {
+       local connection="${1}"
+
+       # Read the security policy
+       local ${VPN_SECURITY_POLICIES_CONFIG_SETTINGS}
+       if ! vpn_security_policies_read_config "${SECURITY_POLICY}"; then
+               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
+
+       print_indent 0 "connections {"
+       print_indent 1 "${connection} {"
+
+       # IKE Version
+       print_indent 2 "# IKE Version"
+       case "${KEY_EXCHANGE^^}" in
+               IKEV1)
+                       print_indent 2 "version = 1"
+                       ;;
+
+               # Fall back to IKEv2 for any random values
+               IKEV2|*)
+                       print_indent 2 "version = 2"
+                       ;;
+       esac
+       print # empty line
+
+       # 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"
+       if isset PEER; then
+               print_indent 2 "remote_addrs = ${PEER}"
+       else
+               print_indent 2 "remote_addrs = %any"
+       fi
+       print
+
+       # IKE Proposals
+       print_indent 2 "# IKE Proposals"
+       print_indent 2 "proposals = $(vpn_security_policies_make_ike_proposal ${SECURITY_POLICY})"
+       print
+
+       # 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
+
+       # Local
+       print_indent 2 "local {"
+
+       # Local ID
+       if isset LOCAL_ID; then
+               print_indent 3 "id = ${LOCAL_ID}"
+       fi
+
+       # Authentication
+       case "${AUTH_MODE}" in
+               PSK)
+                       print_indent 3 "auth = psk"
+                       ;;
+       esac
+
+       print_indent 2 "}"
+       print
+
+       # Remote
+       print_indent 2 "remote {"
+
+       # Remote ID
+       if isset REMOTE_ID; then
+               print_indent 3 "id = ${REMOTE_ID}"
+       fi
+
+       # Authentication
+       case "${AUTH_MODE}" in
+               PSK)
+                       print_indent 3 "auth = psk"
+                       ;;
+       esac
+
+       print_indent 2 "}"
+       print
+
+       # Children
+
+       print_indent 2 "children {"
+       print_indent 3 "${connection} {"
+
+       print_indent 4 "# ESP Proposals"
+       print_indent 4 "esp_proposals = $(vpn_security_policies_make_esp_proposal ${SECURITY_POLICY})"
+       print
+
+       # Traffic Selectors
+
+       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
+                       ;;
+       esac
+       print
+
+       # Netfilter Marks
+       print_indent 4 "# Netfilter Marks"
+       print_indent 4 "mark_in = %unique"
+       print_indent 4 "mark_out = %unique"
+       print
+
+       # 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_indent 4 "rekey_time = ${LIFETIME}"
+               print
+       fi
+
+       # Updown Script
+       print_indent 4 "updown = ${NETWORK_HELPERS_DIR}/ipsec-updown"
+       print
+
+       # Mode
+       print_indent 4 "# Mode"
+       case "${MODE}" in
+               gre-transport)
+                       print_indent 4 "mode = transport"
+                       ;;
+               tunnel|vti|*)
+                       print_indent 4 "mode = tunnel"
+                       ;;
+       esac
+       print
+
+       # Compression
+       print_indent 4 "# Compression"
+       if enabled COMPRESSION; then
+               print_indent 4 "ipcomp = yes"
+       else
+               print_indent 4 "ipcomp = no"
+       fi
+       print
+
+       # Inactivity Timeout
+       if isset INACTIVITY_TIMEOUT; then
+               print_indent 4 "# Inactivity Timeout"
+               print_indent 4 "inactivity = ${INACTIVITY_TIMEOUT}"
+               print
+       fi
+
+       # 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
+
+       print_indent 3 "}"
+       print_indent 2 "}"
+       print
+
+       print_indent 1 "}"
+       print_indent 0 "}"
+       print
+}
+
+_ipsec_connection_to_strongswan_secrets() {
+       local connection="${1}"
+
+       print_indent 0 "secrets {"
+
+       case "${AUTH_MODE}" in
+               PSK)
+                       print_indent 1 "ike {"
+
+                       # Secret
+                       print_indent 2 "secret = ${PSK}"
+
+                       # ID
+                       if isset REMOTE_ID; then
+                               print_indent 2 "id = ${REMOTE_ID}"
+                       fi
+
+                       print_indent 1 "}"
+                       ;;
+       esac
+
+       print_indent 0 "}"
+}