Project: IPFire
Code Location: git://git.ipfire.org/network.gitmaster
Browse
/
Download File
functions.routing
#!/bin/bash
###############################################################################
#                                                                             #
# IPFire.org - A linux based firewall                                         #
# Copyright (C) 2010  Michael Tremer & Christian Schmidt                      #
#                                                                             #
# 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 <http://www.gnu.org/licenses/>.       #
#                                                                             #
###############################################################################

function routing_has_default() {
	ip route | grep -q "^default"
}

function routing_default_update() {
	local routes

	local zones=$(zones_get_nonlocal)
	if [ -z "${zones}" ]; then
		zones=$(zones_get_local)
	fi

	local gateway
	local proto
	local weight
	local zone
	local cmd

	for proto in ${IP_SUPPORTED_PROTOCOLS}; do
		# Clear routes
		routes=""

		cmd="ip $([ "${proto}" = "ipv6" ] && echo "-6") route"

		for zone in ${zones}; do
			# Skip if zone is not up
			routing_db_exists ${zone} ${proto} || continue

			if [ "$(routing_db_get ${zone} ${proto} active)" = "1" ]; then
				gateway=$(routing_db_get ${zone} ${proto} remote-ip-address)

				# Go on if the device is not there anymore.
				device_exists ${zone} || continue

				# On other devices, we will use the gateway if we got one.
				if isset gateway; then
					routes="${routes} nexthop via ${gateway}"

				# If we have got a Point-to-Point device, we will directly send all
				# packets into the pipe.
				elif device_is_ptp ${zone}; then
					routes="${routes} dev ${zone}"

				# If none of the cases above apply, we cannot go on.
				else
					continue
				fi

				# Apply weight.
				weight=$(routing_db_get ${zone} ${proto} weight)
				if isinteger ${weight}; then
					routes="${routes} weight ${weight}"
				fi
			else
				log DEBUG "Ignoring zone '${zone}' which is not active."
			fi
		done

		# Remove too much spaces.
		routes=$(echo ${routes})

		# Remove all default routes.
		while ${cmd} | grep -q "^default"; do
			${cmd} del default
		done

		if [ -z "${routes}" ]; then
			log INFO "Removed default route for ${proto}."
			return ${EXIT_OK}
		fi

		log INFO "Setting default route for ${proto}: ${routes}"

		cmd ${cmd} add default ${routes}
		assert [ $? -eq 0 ]

		case "${proto}" in
			ipv6)
				# Apply radvd configuration.
				radvd_update
				;;
		esac
	done
}

# XXX deprecated function
function routing_table_exists() {
	route_table_exists $@
}

# XXX deprecated function
function routing_table_create() {
	route_table_create $@
}

function routing_db_path() {
	local zone=${1}
	local proto=${2}

	assert isset zone
	assert isset proto
	assert isoneof proto ${IP_SUPPORTED_PROTOCOLS}

	echo "${ROUTING_DB_DIR}/${zone}/${proto}"
}

function routing_db_exists() {
	[ -d "$(routing_db_path $@)" ]
}

function routing_db_create() {
	routing_db_exists $@ && return ${EXIT_OK}

	mkdir -p $(routing_db_path $@)
}

function routing_db_remove() {
	rm -rf $(routing_db_path $@)
}

function routing_db_set() {
	local zone=${1}
	local proto=${2}
	local parameter=${3}
	shift 3

	local value="$@"

	log INFO "Updating database (${zone} - ${proto}): ${parameter} = ${value}"

	routing_db_create ${zone} ${proto}

	echo "${value}" > $(routing_db_path ${zone} ${proto})/${parameter}
}

function routing_db_get() {
	local zone=${1}
	local proto=${2}
	local parameter=${3}
	shift 3

	cat $(routing_db_path ${zone} ${proto})/${parameter} 2>/dev/null
}

function routing_db_from_ppp() {
	local zone=${1}
	local proto=${2}

	assert isset zone
	assert isset proto

	# Save ppp configuration
	routing_db_set ${zone} ${proto} type "ppp"

	if [ "${proto}" = "ipv6" ]; then
		routing_db_set ${zone} ${proto} local-ip-address ${PPP_LLLOCAL}
		routing_db_set ${zone} ${proto} remote-ip-address ${PPP_LLREMOTE}
	elif [ "${proto}" = "ipv4" ]; then
		routing_db_set ${zone} ${proto} local-ip-address ${PPP_IPLOCAL}
		routing_db_set ${zone} ${proto} remote-ip-address ${PPP_IPREMOTE}
	fi

	routing_db_set ${zone} ${proto} dns ${PPP_DNS1} ${PPP_DNS2}

	routing_db_set ${zone} ${proto} remote-address ${PPP_MACREMOTE,,}
}

function routing_update() {
	local zone=${1}
	assert isset zone

	# Nothing to do for local zones.
	if zone_is_local ${zone}; then
		return ${EXIT_OK}
	fi

	local proto=${2}
	local table=${zone}
	assert isset proto

	local ip_cmd="ip"
	if [ "${proto}" = "ipv6" ]; then
		ip_cmd="${ip_cmd} -6"
	fi

	# Create routing table if not exists
	routing_table_create ${table}

	log DEBUG "Flushing routing table ${table}"
	cmd ${ip_cmd} route flush table ${table}

	# Exit here if there is no routing information.
	if ! routing_db_exists ${zone} ${proto}; then
		return ${EXIT_OK}
	fi

	local local_ip_address=$(routing_db_get ${zone} ${proto} local-ip-address)
	local remote_ip_address=$(routing_db_get ${zone} ${proto} remote-ip-address)

	case "${proto}" in
		ipv4)
			local net_address=$(ipv4_get_netaddress ${local_ip_address})

			log DEBUG "Adding route for subnet ${local_ip_address} to table ${table}"
			cmd ${ip_cmd} route add table ${table} ${net_address} dev ${zone}
			;;
	esac

	log DEBUG "Adding default route for table ${table}"
	local routing_cmd="${ip_cmd} route add table ${table} default"
	if isset remote_ip_address; then
		routing_cmd="${routing_cmd} via ${remote_ip_address}"
	else
		routing_cmd="${routing_cmd} dev ${zone}"
	fi
	cmd ${routing_cmd}

	cmd ${ip_cmd} rule add from ${local_ip_address} lookup ${table}
}