]> git.ipfire.org Git - people/ms/network.git/blobdiff - src/functions/functions.ip-tunnel
util: Add abort() which will stop the program immediately
[people/ms/network.git] / src / functions / functions.ip-tunnel
index 195ee9320366b7c7fa11e07a649776449f52d562..11eb3c7f451b457d0180b175ea04ca9dc4c48e4e 100644 (file)
 #                                                                             #
 ###############################################################################
 
-IP_TUNNEL_MODES="sit vti"
+IP_TUNNEL_MODES="gre gretap sit vti"
+
+ip_tunnel_protocol_to_name() {
+       local protocol="${1}"
+
+       case "${protocol}" in
+               gre)
+                       print "Generic Routing Encapsulation"
+                       ;;
+               sit)
+                       print "Simple Internet Transition"
+                       ;;
+               vti)
+                       print "Virtual Tunnel Interface"
+                       ;;
+               *)
+                       print "${protocol}"
+                       ;;
+       esac
+}
+
+# This function converts our modes into the type
+# the iproute2 tool uses
+ip_tunnel_convert_mode_to_iproute2_mode() {
+       local mode=${1}
+       local protocol=${2}
+
+       if ! isset mode || ! isset protocol; then
+               log ERROR "Did not get mode and/or protocol"
+               return ${EXIT_ERROR}
+       fi
+
+       if [[ "${protocol}" = "ipv4" ]]; then
+               # When we use IPv4 we can use our modes
+               echo "${mode}"
+       fi
+
+       if [[ "${protocol}" = "ipv6" ]]; then
+               # When we use IPv6 we have to convert
+               case "${mode}" in
+                       "vti")
+                               echo "vti6"
+                               ;;
+                       "gre")
+                               echo "ip6gre"
+                               ;;
+                       "gretap")
+                               echo "ip6gretap"
+                               ;;
+               esac
+       fi
+}
 
 ip_tunnel_add() {
-       local device=${1}
+       local device="${1}"
        shift
 
        local mode
-       local ttl
+       local ttl=255
 
+       local address
        local remote_address
        local local_address
 
@@ -36,25 +88,34 @@ ip_tunnel_add() {
 
        while [ $# -gt 0 ]; do
                case "${1}" in
+                       --address=*)
+                               address="$(cli_get_val "${1}")"
+
+                               # Validate input
+                               if ! isset address || ! mac_is_valid "${address}"; then
+                                       error "Invalid MAC address: ${address}"
+                                       return ${EXIT_ERROR}
+                               fi
+                               ;;
                        --mode=*)
-                               mode="$(cli_get_val ${1})"
+                               mode="$(cli_get_val "${1}")"
                                ;;
                        --ttl=*)
-                               ttl="$(cli_get_val ${1})"
+                               ttl="$(cli_get_val "${1}")"
                                ;;
                        --remote-address=*)
-                               remote_address="$(cli_get_val ${1})"
+                               remote_address="$(cli_get_val "${1}")"
                                ;;
                        --local-address=*)
-                               local_address="$(cli_get_val ${1})"
+                               local_address="$(cli_get_val "${1}")"
                                ;;
 
                        # Keys for VTI
                        --ikey=*)
-                               ikey="$(cli_get_val ${1})"
+                               ikey="$(cli_get_val "${1}")"
                                ;;
                        --okey=*)
-                               okey="$(cli_get_val ${1})"
+                               okey="$(cli_get_val "${1}")"
                                ;;
                esac
                shift
@@ -70,44 +131,71 @@ ip_tunnel_add() {
                return ${EXIT_ERROR}
        fi
 
+       # We cannot mix IPv6 and IPv4
+       if isset local_address && ! ip_protocol_match "${remote_address}" "${local_address}"; then
+               log ERROR "Local and remote address are not of the same IP protocol"
+               return ${EXIT_ERROR}
+       fi
+
        # ikey and okey must be set for VTI devices
        if [ "${mode}" = "vti" ] && (! isset ikey || ! isset okey); then
                error "--ikey= and --okey= must be set for VTI device"
                return ${EXIT_ERROR}
        fi
 
+       # Custom checks for certain modes
+       case "${mode}" in
+               gretap)
+                       # Generate a random MAC address if none was passed
+                       if ! isset address; then
+                               address="$(mac_generate)"
+                       fi
+                       ;;
+       esac
+
        # If TTL is set, make sure it is an integer.
        if isset ttl && ! isinteger ttl; then
                error "TTL must be an integer: ${ttl}"
                return ${EXIT_ERROR}
        fi
 
-       local cmd_args
+       # Determine the mode based on the IP protocol
+       local remote_address_protocol="$(ip_detect_protocol "${remote_address}")"
+       mode=$(ip_tunnel_convert_mode_to_iproute2_mode "${mode}" "${remote_address_protocol}")
+
+       local cmd_args=( name "${device}" )
+
+       if isset address; then
+               cmd_args=( "${cmd_args[@]}" "address" "${address}" )
+       fi
+
+       # Mode
+       cmd_args=( "${cmd_args[@]}" "type" "${mode}" )
 
        # Apply TTL if a value has been set.
        if isset ttl; then
-               cmd_args="${cmd_args} ttl ${ttl}"
+               cmd_args=( "${cmd_args[@]}" "ttl" "${ttl}" )
        fi
 
        # Apply local address if a value has been set.
        if isset local_address; then
-               cmd_args="${cmd_args} local ${local_address}"
+               cmd_args=( "${cmd_args[@]}" "local" "${local_address}" )
        fi
 
        # Apply remote address if a value has been set.
        if isset remote_address; then
-               cmd_args="${cmd_args} remote ${remote_address}"
+               cmd_args=( "${cmd_args[@]}" "remote" "${remote_address}" )
        fi
 
        # Add ikey and okey for VTI devices
        if [ "${mode}" = "vti" ]; then
-               cmd_args="${cmd_args} ikey ${ikey} okey ${okey}"
+               cmd_args=( "${cmd_args[@]}" "ikey" "${ikey}" "okey" "${okey}" )
        fi
 
        log DEBUG "Creating tunnel device '${device}' (mode=${mode})..."
 
        # Create the device.
-       if ! cmd ip tunnel add ${device} mode ${mode} ${cmd_args}; then
+       if ! cmd ip link add "${cmd_args[@]}"; then
                error "Could not create tunnel device ${device}"
                return ${EXIT_ERROR}
        fi
@@ -121,14 +209,75 @@ ip_tunnel_add() {
 }
 
 ip_tunnel_del() {
-       local device=${1}
-       assert device_exists ${device}
+       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}")"
 
-       # Make sure the device has been shut down.
-       device_set_down ${device}
+                               if ! ip_is_valid "${remote}"; then
+                                       error "Invalid IP address for --remote: ${remote}"
+                                       return ${EXIT_ERROR}
+                               fi
 
-       log DEBUG "Removing tunnel device '${device}'..."
+                               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
 
-       ip tunnel del ${device}
-       assert [ $? -eq 0 ]
+       # Run ip command
+       cmd ip link change dev "${device}" type "${type}" ${cmd_args}
 }