From: Michael Tremer Date: Fri, 10 Aug 2012 13:27:23 +0000 (+0000) Subject: Add commands to manage static routes. X-Git-Tag: 005~53 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=cb96534876d92615a4d92b6e6985ab4a42582343;p=network.git Add commands to manage static routes. --- diff --git a/functions.constants b/functions.constants index 2cb11452..1fcc3a7d 100644 --- a/functions.constants +++ b/functions.constants @@ -43,6 +43,10 @@ ROUTING_DB_DIR=${RUN_DIR}/routing DB_CONNECTION_FILE="${LOG_DIR}/connections.db" +# (Static) route settings. +NETWORK_CONFIG_ROUTES="${NETWORK_CONFIG_DIR}/routes" +NETWORK_CONFIG_ROUTES_PARAMS="network gateway unreachable" + # Proper error codes EXIT_OK=0 EXIT_ERROR=1 diff --git a/functions.ip b/functions.ip index 2fa2d762..d19c9cfa 100644 --- a/functions.ip +++ b/functions.ip @@ -73,6 +73,48 @@ function ip_is_valid() { isset proto && return ${EXIT_TRUE} || return ${EXIT_FALSE} } +function ip_is_network() { + local network=${1} + assert isset network + + # Get the address part. + local address=$(ip_split_prefix ${network}) + isset address || return ${EXIT_FALSE} + + # Get the prefix. + local prefix=$(ip_get_prefix ${network}) + isset prefix || return ${EXIT_FALSE} + + # Detect the protocol. + local proto=$(ip_detect_protocol ${address}) + assert isset proto + + # Check if the prefix is correct. + ip_prefix_is_valid ${proto} ${prefix} || return ${EXIT_FALSE} + + return ${EXIT_TRUE} +} + +function ip_prefix_is_valid() { + local proto=${1} + assert isset proto + + local prefix=${2} + + case "${proto}" in + ipv4) + ipv4_prefix_is_valid ${prefix} + return $? + ;; + ipv6) + ipv6_prefix_is_valid ${prefix} + return $? + ;; + esac + + assert ip_protocol_is_supported ${proto} +} + function ip_address_add() { local device=${1} local address=${2} diff --git a/functions.ipv4 b/functions.ipv4 index a3b3ce46..a48839db 100644 --- a/functions.ipv4 +++ b/functions.ipv4 @@ -34,6 +34,16 @@ function ipv4_is_valid() { esac } +function ipv4_prefix_is_valid() { + local prefix=${1} + assert isset prefix + + [ ${prefix} -le 0 ] && return ${EXIT_FALSE} + [ ${prefix} -gt 32 ] && return ${EXIT_FALSE} + + return ${EXIT_TRUE} +} + function ipv4_detect_duplicate() { local device=${1} local address=${2} diff --git a/functions.ipv6 b/functions.ipv6 index 53c79a07..d1a43e4d 100644 --- a/functions.ipv6 +++ b/functions.ipv6 @@ -150,6 +150,16 @@ function ipv6_is_valid() { esac } +function ipv6_prefix_is_valid() { + local prefix=${1} + assert isset prefix + + [ ${prefix} -le 0 ] && return ${EXIT_FALSE} + [ ${prefix} -gt 128 ] && return ${EXIT_FALSE} + + return ${EXIT_TRUE} +} + function ipv6_implode() { local address=${1} diff --git a/functions.route b/functions.route new file mode 100644 index 00000000..65782fb5 --- /dev/null +++ b/functions.route @@ -0,0 +1,232 @@ +#!/bin/bash +############################################################################### +# # +# IPFire.org - A linux based firewall # +# Copyright (C) 2012 IPFire Network Development Team # +# # +# This program is free software: you can redistribute it and/or modify # +# it under the terms of the GNU General Public License as published by # +# the Free Software Foundation, either version 3 of the License, or # +# (at your option) any later version. # +# # +# This program is distributed in the hope that it will be useful, # +# but WITHOUT ANY WARRANTY; without even the implied warranty of # +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # +# GNU General Public License for more details. # +# # +# You should have received a copy of the GNU General Public License # +# along with this program. If not, see . # +# # +############################################################################### +# +# Functions for static routing. +# + +function route_add() { + local ${NETWORK_CONFIG_ROUTES_PARAMS} + + while [ $# -gt 0 ]; do + case "${1}" in + --gateway=*) + gateway=$(cli_get_val ${1}) + ;; + --unreachable) + unreachable="true" + ;; + *) + network=${1} + ;; + esac + shift + done + + assert isset network + + if ! ip_is_valid ${network}; then + error "The given network is invalid: ${network}" + return ${EXIT_ERROR} + fi + + if route_find_duplicate ${network}; then + error "A route to ${network} does already exist." + return ${EXIT_ERROR} + fi + + # Check if gateway and unreachable are both enabled. + if isset gateway && enabled unreachable; then + error "You cannot use both, --gateway=${gateway} and --unreachable at the same time." + return ${EXIT_ERROR} + fi + + if ! ip_is_valid ${gateway}; then + error "--gateway= is not a valid IP address." + return ${EXIT_ERROR} + fi + + # Check if network and gateway IP protocol version match. + if isset gateway; then + local network_proto=$(ip_detect_protocol ${network}) + local gateway_proto=$(ip_detect_protocol ${gateway}) + + if [ "${network_proto}" != "${gateway_proto}" ]; then + error "The IP protocol version of the given network and gateway did not match." + return ${EXIT_ERROR} + fi + fi + + local line + list_append line "network=\"${network}\"" + + # Add gateway to configuration entry when it is set. + if isset gateway; then + list_append line "gateway=\"${gateway}\"" + fi + + # Add unreachable to configuration entry when it is set. + if enabled unreachable; then + list_append line "unreachable=\"true\"" + fi + + # Write line to file. + print "${line}" >> ${NETWORK_CONFIG_ROUTES} + + log INFO "New route to network '${network}' has been added." + return ${EXIT_OK} +} + +function route_remove() { + local _network=${1} + assert isset _network + + local found="false" + + local ${NETWORK_CONFIG_ROUTES_PARAMS} + local line + while read line; do + route_parse_line ${line} + [ $? -eq ${EXIT_OK} ] || continue + + # Skip the rule, we want to delete. + if [ "${network}" = "${_network}" ]; then + found="true" + continue + fi + + print "${line}" + done < ${NETWORK_CONFIG_ROUTES} > ${NETWORK_CONFIG_ROUTES}.tmp + mv ${NETWORK_CONFIG_ROUTES}{.tmp,} + + if enabled found; then + log INFO "Route to network '${_network}' has been removed." + else + error "No route to network '${_network}' was found." + return ${EXIT_ERROR} + fi + + return ${EXIT_OK} +} + +function route_list() { + local protocol + + while [ $# -gt 0 ]; do + case "${1}" in + --protocol=*) + protocol=$(cli_get_val ${1}) + ;; + *) + warning "Unrecognized argument: ${1}" + ;; + esac + shift + done + + if [ ! -r "${NETWORK_CONFIG_ROUTES}" ]; then + print "No static routes defined." + return ${EXIT_OK} + fi + + local format="%-40s %-20s" + print "${format}" "NETWORK/HOST" "GATEWAY" + + local ${NETWORK_CONFIG_ROUTES_PARAMS} + local line + while read line; do + route_parse_line ${line} + [ $? -eq ${EXIT_OK} ] || continue + + if enabled unreachable; then + gateway="" + fi + + # Filter all entries with a wrong protocol. + if isset protocol; then + local proto=$(ip_detect_protocol ${network}) + [ "${protocol}" = "${proto}" ] || continue + fi + + print "${format}" "${network}" "${gateway}" + done < ${NETWORK_CONFIG_ROUTES} +} + +function route_find_duplicate() { + local _network=${1} + + [ -r "${NETWORK_CONFIG_ROUTES}" ] || return ${EXIT_FALSE} + + local ${NETWORK_CONFIG_ROUTES_PARAMS} + local line + while read line; do + route_parse_line ${line} + + # Check if the network is already in use. + [ "${network}" = "${_network}" ] && return ${EXIT_TRUE} + done < ${NETWORK_CONFIG_ROUTES} + + return ${EXIT_FALSE} +} + +function route_parse_line() { + local arg + + # Reset all possible settings. + for arg in ${NETWORK_CONFIG_ROUTES_PARAMS}; do + printf -v ${arg} "%s" "" + done + + while read arg; do + case "${arg}" in + network=*) + network=$(cli_get_val ${arg}) + ;; + gateway=*) + gateway=$(cli_get_val ${arg}) + ;; + unreachable=*) + unreachable=$(cli_get_val ${arg}) + ;; + esac + done <<< "$(args $@)" + + ### Check if all values are correctly set. + + # network must be set. + isset network || return ${EXIT_ERROR} + + # network must be a valid. + ip_is_network ${network} || return ${EXIT_ERROR} + + # Check gateway settings. + if isset gateway; then + # When gateway is set, unreachable cannot be set. + isset unreachable && return ${EXIT_ERROR} + + # Must be a valid IP address. + ip_is_valid ${gateway} || return ${EXIT_ERROR} + else + # Either gateway or unreachable must be set. + isset unreachable || return ${EXIT_ERROR} + fi + + return ${EXIT_OK} +} diff --git a/functions.util b/functions.util index 76e5ba12..98c80d88 100644 --- a/functions.util +++ b/functions.util @@ -26,6 +26,13 @@ function print() { printf -- "${fmt}\n" "$@" } +# The args() function takes a number of arguments like +# var1="abc d" var2="abc" var3="abcd e" +# and splits them into several arguments, devided by newline +function args() { + echo "$@" | xargs printf "%s\n" +} + # Print a pretty error message function error() { echo -e " ${COLOUR_ERROR}ERROR${COLOUR_NORMAL} : $@" >&2 diff --git a/network b/network index c22b23f8..a393d357 100755 --- a/network +++ b/network @@ -558,6 +558,39 @@ function cli_list_hooks() { done | sort -u } +function cli_route() { + if cli_help_requested $@; then + cli_show_man network-route + exit ${EXIT_OK} + fi + + local action=${1} + shift + + case "${action}" in + # Add a new route. + add) + route_add $@ + ;; + # Remove an existing route. + remove) + route_remove $@ + ;; + # List all routes. + list) + route_list $@ + ;; + *) + error "Unrecognized action: ${action}" + cli_run_help network route + + exit ${EXIT_ERROR} + ;; + esac + + exit ${EXIT_OK} +} + function cli_start() { if cli_help_requested $@; then cli_show_man network @@ -752,7 +785,7 @@ case "${action}" in init_run ;; - config|hostname|port|device|zone|start|stop|restart|status|reset|dns) + config|hostname|port|device|zone|start|stop|restart|status|reset|dns|route) cli_${action} $@ ;;