]> git.ipfire.org Git - people/ms/network.git/commitdiff
ipsec: GRE/VTI connections are now possible as on-demand
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 19 Sep 2018 11:43:58 +0000 (13:43 +0200)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 19 Sep 2018 11:43:58 +0000 (13:43 +0200)
This change implements using zones as GRE/VTI devices so that
we can use IPsec connections in on-demand mode, too.

The device will be created first (as a zone) and might trigger
an IPsec connection. If that happens, the settings of the device
will be updated automatically.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/functions/functions.ip-tunnel
src/functions/functions.ipsec
src/helpers/ipsec-updown

index 302a11c3bd8e3bda7f4a2706ef7905912ee143cc..797a2934f633d6e1b5282e5fc755fb119641635b 100644 (file)
@@ -181,6 +181,76 @@ ip_tunnel_del() {
        device_delete "$@"
 }
 
+ip_tunnel_change() {
+       local device="${1}"
+       shift
+
+       if ! device_exists "${device}"; then
+               log ERROR "No such device: ${device}"
+               return ${EXIT_ERROR}
+       fi
+
+       # Determine the device type
+       local type="$(device_tunnel_get_type ${device})"
+
+       local local
+       local remote
+
+       while [ $# -gt 0 ]; do
+               case "${1}" in
+                       --local=*)
+                               local="$(cli_get_val "${1}")"
+
+                               if ! ip_is_valid "${local}"; then
+                                       error "Invalid IP address for --local: ${local}"
+                                       return ${EXIT_ERROR}
+                               fi
+
+                               if ! isoneof "type" gre gre6 vti vti6; then
+                                       log ERROR "Cannot change --local for devices of type ${type}"
+                                       return ${EXIT_ERROR}
+                               fi
+                               ;;
+                       --remote=*)
+                               remote="$(cli_get_val "${1}")"
+
+                               if ! ip_is_valid "${remote}"; then
+                                       error "Invalid IP address for --remote: ${remote}"
+                                       return ${EXIT_ERROR}
+                               fi
+
+                               if ! isoneof "type" gre gre6 vti vti6; then
+                                       log ERROR "Cannot change --remote for devices of type ${type}"
+                                       return ${EXIT_ERROR}
+                               fi
+                               ;;
+               esac
+               shift
+       done
+
+       # XXX If a device is of an IP protocol and the protocol of remote and local
+       # have changed, we will need to destroy the interface and recreate it with
+       # the correct type
+
+       local cmd_args
+
+       if isset local; then
+               cmd_args="${cmd_args} local ${local}"
+       fi
+
+       if isset remote; then
+               cmd_args="${cmd_args} remote ${remote}"
+       fi
+
+       # Exit if there is nothing to do
+       if ! isset cmd_args; then
+               return ${EXIT_OK}
+       fi
+
+       # Run ip command
+       cmd ip link change dev "${device}" type "${type}" ${cmd_args}
+}
+
 ip_tunnel_change_keys() {
        local device="${1}"
        shift
index e2af52b07d95f9d9b426e51a167b2a244bb3a180..3f215e40da91cbf6e2281d498903441899a9492b 100644 (file)
@@ -529,12 +529,24 @@ ipsec_connection_up() {
                return ${EXIT_ERROR}
        fi
 
+       # Read configuration options
+       local ZONE
+       if ! ipsec_connection_read_config "${connection}" "ZONE"; then
+               log ERROR "Could not read configuration for IPsec connection ${connection}"
+               return ${EXIT_ERROR}
+       fi
+
        if ! [ -f "${NETWORK_IPSEC_SWANCTL_CONNECTIONS_DIR}/${connection}.conf" ]; then
                log DEBUG "Could not find a swanctl config, generating swanctl config"
                ipsec_connection_to_strongswan "${connection}"
                ipsec_strongswan_load
        fi
 
+       # Bring up the zone
+       if isset ZONE; then
+               zone_up "${ZONE}"
+       fi
+
        cmd swanctl --initiate --child "${connection}"
 }
 
@@ -546,7 +558,20 @@ ipsec_connection_down() {
                return ${EXIT_ERROR}
        fi
 
+       # Read configuration options
+       local ZONE
+       if ! ipsec_connection_read_config "${connection}" "ZONE"; then
+               log ERROR "Could not read configuration for IPsec connection ${connection}"
+               return ${EXIT_ERROR}
+       fi
+
+       # Tell strongswan to bring down any tunnels
        cmd swanctl --terminate --ike "${connection}"
+
+       # Bring up the zone
+       if isset ZONE; then
+               zone_down "${ZONE}"
+       fi
 }
 
 # Handle the cli after authentification
@@ -1315,6 +1340,22 @@ _ipsec_connection_to_strongswan_connection() {
                dpd="true"
        fi
 
+       local zone_mode
+
+       # Are we connected to a zone?
+       if isset ZONE; then
+               # Store MODE
+               local mode="${MODE}"
+
+               if ! zone_settings_read "${ZONE}" MARK MODE; then
+                       log ERROR "Could not read zone settings from ${zone}"
+                       return ${EXIT_ERROR}
+               fi
+
+               local zone_mode="${MODE}"
+               MODE="${mode}"
+       fi
+
        # Write configuration header
        config_header "strongSwan configuration for ${connection}"
 
@@ -1439,9 +1480,8 @@ _ipsec_connection_to_strongswan_connection() {
        print
 
        # Traffic Selectors
-
-       case "${MODE}" in
-               gre-*)
+       case "${MODE},${zone_mode}" in
+               *,gre)
                        print_indent 4 "local_ts = dynamic[gre]"
                        print_indent 4 "remote_ts = dynamic[gre]"
                        ;;
@@ -1464,11 +1504,13 @@ _ipsec_connection_to_strongswan_connection() {
        print
 
        # Netfilter Marks
-       case "${MODE}" in
+       case "${zone_mode}" in
                vti)
+                       assert isset MARK
+
                        print_indent 4 "# Netfilter Marks"
-                       print_indent 4 "mark_in = %unique"
-                       print_indent 4 "mark_out = %unique"
+                       print_indent 4 "mark_in = ${MARK}"
+                       print_indent 4 "mark_out = ${MARK}"
                        print
                        ;;
        esac
index 185c2c72b26dcba93aa7a5c12b059f52ce6789a9..1e6c69551110fe8fc27e7e6815da03a0c1aa40ce 100644 (file)
@@ -54,37 +54,24 @@ log DEBUG "${0} called for ${CONNECTION}: ${PLUTO_VERB}"
 
 case "${PLUTO_VERB}" in
        up-client|up-client-v6|up-host|up-host-v6)
-               case "${MODE}" in
-                       gre-*)
-                               if ! device_exists "${INTERFACE}"; then
-                                       ip_tunnel_add "${INTERFACE}" \
-                                               --mode="gre" \
-                                               --local-address="${PLUTO_ME}" \
-                                               --remote-address="${PLUTO_PEER}"
-
-                                       device_set_up "${INTERFACE}"
-                               fi
-                               ;;
-                       vti)
-                               if device_exists "${INTERFACE}"; then
-                                       ip_tunnel_change_keys "${INTERFACE}" \
-                                               --ikey="${PLUTO_MARK_IN%/*}" \
-                                               --okey="${PLUTO_MARK_OUT%/*}"
+               if isset ZONE && zone_exists "${ZONE}"; then
+                       # Bring up the zone if not done, yet
+                       if ! zone_is_up "${ZONE}"; then
+                               zone_up "${ZONE}"
+                       fi
 
-                               else
-                                       if ! ip_tunnel_add "${INTERFACE}" \
-                                               --mode="vti" \
-                                               --local-address="${PLUTO_ME}" \
-                                               --remote-address="${PLUTO_PEER}" \
-                                               --ikey="${PLUTO_MARK_IN%/*}" \
-                                               --okey="${PLUTO_MARK_OUT%/*}"; then
-                                               log ERROR "Could not create VTI device for ${CONNECTION}"
-                                       fi
-                               fi
+                       # Update peer and local address
+                       if ! ip_tunnel_change "${ZONE}" --remote="${PLUTO_PEER}" --local="${PLUTO_ME}"; then
+                               return ${EXIT_ERROR}
+                       fi
 
-                               device_set_up "${INTERFACE}"
-                               ;;
-               esac
+                       # Set keys for VTI devices
+                       if device_is_vti6 "${ZONE}" || device_is_vti "${ZONE}"; then
+                               ip_tunnel_change_keys "${ZONE}" \
+                                       --ikey="${PLUTO_MARK_IN%/*}" \
+                                       --okey="${PLUTO_MARK_OUT%/*}"
+                       fi
+               fi
 
                #Get sources IP for routes
                SRC_IP=($(ip_get_assigned_addresses_from_net \
@@ -131,17 +118,6 @@ case "${PLUTO_VERB}" in
        down-client|down-client-v6|down-host|down-host-v6)
                # Remove routes
                cmd ip route del "${PLUTO_PEER_CLIENT}"
-
-               # Remove interfaces
-               case "${MODE}" in
-                       gre-*|vti)
-                               if device_exists "${INTERFACE}"; then
-                                       device_set_down "${INTERFACE}"
-
-                                       ip_tunnel_del "${INTERFACE}"
-                               fi
-                               ;;
-               esac
                ;;
 esac