]> git.ipfire.org Git - people/stevee/network.git/blobdiff - src/functions/functions.ipsec
wpa_supplicant: Doesn't like spaces here
[people/stevee/network.git] / src / functions / functions.ipsec
index d75d920dc94d30c4110270eca3bcd80aae4bb7df..a15ff468010527db9419a096d9b721d8755e9fd0 100644 (file)
@@ -30,10 +30,13 @@ IPSEC_CONNECTION_CONFIG_SETTINGS="\
        LOCAL_PREFIX \
        MODE \
        PEER \
+       POOLS \
        PSK \
        REMOTE_ID \
        REMOTE_PREFIX \
        SECURITY_POLICY \
+       START_ACTION \
+       TYPE \
        ENABLED"
 
 # Default values
@@ -46,6 +49,7 @@ 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"
@@ -56,7 +60,10 @@ cli_ipsec() {
 
        case "${action}" in
                connection)
-                       cli_ipsec_connection $@
+                       cli_ipsec_connection "$@"
+                       ;;
+               pool)
+                       cli_ipsec_pool "$@"
                        ;;
                *)
                        error "Unrecognized argument: ${action}"
@@ -73,8 +80,14 @@ cli_ipsec_connection() {
                shift 2
 
                case "${key}" in
-                       authentication|down|disable|dpd|enable|inactivity_timeout|local|mode|peer|remote|security_policy|start_action|up)
-                               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} "$@"
+                               ;;
+                       color)
+                               color_cli "ipsec-connection" "${connection}" "$@"
+                               ;;
+                       description)
+                               description_cli "ipsec-connection" ${connection} $@
                                ;;
                        show)
                                cli_ipsec_connection_show "${connection}"
@@ -91,10 +104,10 @@ cli_ipsec_connection() {
 
                case "${action}" in
                        new)
-                               ipsec_connection_new $@
+                               ipsec_connection_new "$@"
                                ;;
                        destroy)
-                               ipsec_connection_destroy $@
+                               cli_ipsec_connection_destroy "$@"
                                ;;
                        ""|*)
                                if [ -n "${action}" ]; then
@@ -106,6 +119,35 @@ cli_ipsec_connection() {
        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
+}
+
+ipsec_connection_get_color() {
+       # This function return the color of a zone
+       assert [ $# -eq 1 ]
+
+       local name=${1}
+       color_read "ipsec-connection" ${name}
+}
+
+ipsec_connection_get_description_title() {
+       assert [ $# -eq 1 ]
+
+       local name=${1}
+       description_title_read $(description_format_filename "ipsec-connection" "${name}")
+}
+
 cli_ipsec_connection_show() {
        local connection="${1}"
 
@@ -119,6 +161,10 @@ cli_ipsec_connection_show() {
        cli_headline 0 "IPsec VPN Connection: ${connection}"
        cli_space
 
+       cli_print_fmt1 1 "Color" "$(cli_color_bar $(ipsec_connection_get_color ${connection}))"
+       cli_print_fmt1 1 "Description" "$(ipsec_connection_get_description_title ${connection})"
+       cli_space
+
        # Peer
        if isset PEER; then
                cli_print_fmt1 1 "Peer" "${PEER}"
@@ -208,8 +254,6 @@ ipsec_connection_disable() {
                return ${EXIT_ERROR}
        fi
 
-       ipsec_reload ${connection}
-
        # Configure strongswan autostart
        ipsec_strongswan_autostart
 }
@@ -222,8 +266,6 @@ ipsec_connection_enable() {
                return ${EXIT_ERROR}
        fi
 
-       ipsec_reload "${connection}"
-
        # Configure strongswan autostart
        ipsec_strongswan_autostart
 }
@@ -300,7 +342,7 @@ ipsec_connection_read_config() {
        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"
@@ -366,6 +408,11 @@ ipsec_strongswan_autostart() {
 }
 
 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}
@@ -389,6 +436,7 @@ ipsec_reload() {
                        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
 
@@ -408,10 +456,10 @@ ipsec_connection_authentication() {
 
        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}"
@@ -505,13 +553,13 @@ ipsec_connection_dpd() {
 
        case ${cmd} in
                action)
-                       ipsec_connection_dpd_action "${connection}" $@
+                       ipsec_connection_dpd_action "${connection}" "$@"
                        ;;
                delay)
-                       ipsec_connection_dpd_delay "${connection}" $@
+                       ipsec_connection_dpd_delay "${connection}" "$@"
                        ;;
                timeout)
-                       ipsec_connection_dpd_timeout "${connection}" $@
+                       ipsec_connection_dpd_timeout "${connection}" "$@"
                        ;;
                *)
                        log ERROR "Unrecognized argument: ${cmd}"
@@ -552,7 +600,7 @@ ipsec_connection_dpd_delay() {
        local value=$@
 
        if ! isinteger value; then
-               value=$(parse_time $@)
+               value=$(parse_time "$@")
                if [ ! $? -eq 0 ]; then
                        log ERROR "Parsing the passed time was not sucessful please check the passed values."
                        return ${EXIT_ERROR}
@@ -584,7 +632,7 @@ ipsec_connection_dpd_timeout() {
        local value=$@
 
        if ! isinteger value; then
-               value=$(parse_time $@)
+               value=$(parse_time "$@")
                if [ ! $? -eq 0 ]; then
                        log ERROR "Parsing the passed time was not sucessful please check the passed values."
                        return ${EXIT_ERROR}
@@ -617,13 +665,13 @@ ipsec_connection_local() {
 
        case ${cmd} in
                address)
-                       ipsec_connection_local_address "${connection}" $@
+                       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}"
@@ -714,16 +762,16 @@ ipsec_connection_id() {
                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"
@@ -732,7 +780,7 @@ ipsec_connection_prefix() {
        local connection=${1}
        local type=${2}
        shift 2
-       
+
        local _prefix="${type}_PREFIX"
        local "${_prefix}"
        if ! ipsec_connection_read_config "${connection}" "${_prefix}"; then
@@ -823,6 +871,104 @@ ipsec_connection_prefix() {
        return ${EXIT_OK}
 }
 
+# Set the pools to use
+ipsec_connection_pool() {
+       if [ ! $# -ge 2 ]; then
+               log ERROR "Not enough arguments"
+               return ${EXIT_ERROR}
+       fi
+       local connection=${1}
+       shift
+
+       local POOLS
+       if ! ipsec_connection_read_config "${connection}" "POOLS"; then
+               return ${EXIT_ERROR}
+       fi
+
+       # Remove duplicated entries to proceed the list safely
+       assign "POOLS" "$(list_unique ${POOLS})"
+
+       local pools_added
+       local pools_removed
+       local pools_set
+
+       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
@@ -836,11 +982,11 @@ ipsec_connection_remote() {
 
        case ${cmd} in
                id)
-                       ipsec_connection_id "${connection}" "REMOTE" $@
+                       ipsec_connection_id "${connection}" "REMOTE" "$@"
                        ;;
 
                prefix)
-                       ipsec_connection_prefix "${connection}" "REMOTE" $@
+                       ipsec_connection_prefix "${connection}" "REMOTE" "$@"
                        ;;
                *)
                        log ERROR "Unrecognized argument: ${cmd}"
@@ -863,7 +1009,7 @@ ipsec_connection_inactivity_timeout() {
        local value=$@
 
        if ! isinteger value; then
-               value=$(parse_time $@)
+               value=$(parse_time "$@")
                if [ ! $? -eq 0 ]; then
                        log ERROR "Parsing the passed time was not sucessful please check the passed values."
                        return ${EXIT_ERROR}
@@ -960,12 +1106,14 @@ ipsec_connection_check_name() {
 
 # 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}
@@ -983,6 +1131,16 @@ ipsec_connection_new() {
                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
@@ -999,6 +1157,7 @@ ipsec_connection_new() {
        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}
@@ -1015,34 +1174,33 @@ ipsec_connection_new() {
 # 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
 
-       # Configure strongswan autostart
-       ipsec_strongswan_autostart
+       done
 }
 
 # List all ipsec connections
 ipsec_list_connections() {
-       local connection
-       for connection in ${NETWORK_IPSEC_CONNS_DIR}/*; do
-               [ -d ${connection} ] || continue
-               basename ${connection}
-       done
+       list_directory "${NETWORK_IPSEC_CONNS_DIR}"
 }
 
 ipsec_connection_to_strongswan() {
        local connection="${1}"
+       log DEBUG "Generating IPsec configuration for ${connection}"
 
        # Read the config settings
        local ${IPSEC_CONNECTION_CONFIG_SETTINGS}
@@ -1143,6 +1301,19 @@ _ipsec_connection_to_strongswan_connection() {
        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 {"
 
@@ -1214,10 +1385,14 @@ _ipsec_connection_to_strongswan_connection() {
        print
 
        # Netfilter Marks
-       print_indent 4 "# Netfilter Marks"
-       print_indent 4 "mark_in = %unique"
-       print_indent 4 "mark_out = %unique"
-       print
+       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
@@ -1265,23 +1440,28 @@ _ipsec_connection_to_strongswan_connection() {
                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"
+       # 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
 
        print_indent 3 "}"
        print_indent 2 "}"