2 ###############################################################################
4 # IPFire.org - A linux based firewall #
5 # Copyright (C) 2012 IPFire Network Development Team #
7 # This program is free software: you can redistribute it and/or modify #
8 # it under the terms of the GNU General Public License as published by #
9 # the Free Software Foundation, either version 3 of the License, or #
10 # (at your option) any later version. #
12 # This program is distributed in the hope that it will be useful, #
13 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
15 # GNU General Public License for more details. #
17 # You should have received a copy of the GNU General Public License #
18 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
20 ###############################################################################
22 # Functions for static routing.
25 function route_init
() {
26 # Apply configured static routes.
30 init_register route_init
32 function route_add
() {
33 local ${NETWORK_CONFIG_ROUTES_PARAMS}
35 while [ $# -gt 0 ]; do
38 gateway
=$
(cli_get_val
${1})
58 if ! ip_is_valid
${network}; then
59 error
"The given network is invalid: ${network}"
63 if route_find_duplicate
${network}; then
64 error
"A route to ${network} does already exist."
68 # Check if gateway and unreachable are both enabled.
69 if isset gateway
; then
70 if enabled unreachable
; then
71 error
"You cannot use both, --gateway=${gateway} and --unreachable at the same time."
75 if enabled prohibit
; then
76 error
"You cannot use both, --gateway=${gateway} and --prohibit at the same time."
80 if enabled blackhole
; then
81 error
"You cannot use both, --gateway=${gateway} and --blackhole at the same time."
85 # Check if network and gateway IP protocol version match.
86 if ! ip_is_valid
${gateway}; then
87 error
"--gateway= is not a valid IP address."
91 local network_proto
=$
(ip_detect_protocol
${network})
92 local gateway_proto
=$
(ip_detect_protocol
${gateway})
94 if [ "${network_proto}" != "${gateway_proto}" ]; then
95 error
"The IP protocol version of the given network and gateway did not match."
100 local counter
=$
(list_count true
${unreachable} ${prohibit} ${blackhole})
101 if [ ${counter} -gt 1 ]; then
102 error
"You can only use one of --unreachable, --prohibit or --blackhole."
108 list_append line
"network=\"${network}\""
110 # Add gateway to configuration entry when it is set.
111 if isset gateway
; then
112 list_append line
"gateway=\"${gateway}\""
115 # Add unreachable to configuration entry when it is set.
117 for arg
in unreachable prohibit blackhole
; do
118 if enabled
${arg}; then
119 list_append line
"${arg}=\"true\""
124 # Write line to file.
125 print
"${line}" >> ${NETWORK_CONFIG_ROUTES}
127 log INFO
"New route to network '${network}' has been added."
131 function route_remove
() {
133 assert isset _network
137 local ${NETWORK_CONFIG_ROUTES_PARAMS}
140 route_parse_line
${line}
141 [ $?
-eq ${EXIT_OK} ] ||
continue
143 # Skip the rule, we want to delete.
144 if [ "${network}" = "${_network}" ]; then
150 done < ${NETWORK_CONFIG_ROUTES} > ${NETWORK_CONFIG_ROUTES}.tmp
151 mv ${NETWORK_CONFIG_ROUTES}{.tmp
,}
153 if enabled found
; then
154 log INFO
"Route to network '${_network}' has been removed."
156 error
"No route to network '${_network}' was found."
163 function route_list
() {
166 while [ $# -gt 0 ]; do
169 protocol
=$
(cli_get_val
${1})
172 warning
"Unrecognized argument: ${1}"
178 if [ ! -r "${NETWORK_CONFIG_ROUTES}" ]; then
179 print
"No static routes defined."
183 local format
="%-40s %-20s"
184 print
"${format}" "NETWORK/HOST" "GATEWAY"
186 local ${NETWORK_CONFIG_ROUTES_PARAMS}
189 route_parse_line
${line}
190 [ $?
-eq ${EXIT_OK} ] ||
continue
193 for arg
in unreachable prohibit blackhole
; do
194 if enabled
${arg}; then
200 # Filter all entries with a wrong protocol.
201 if isset protocol
; then
202 local proto
=$
(ip_detect_protocol
${network})
203 [ "${protocol}" = "${proto}" ] ||
continue
206 print
"${format}" "${network}" "${gateway}"
207 done < ${NETWORK_CONFIG_ROUTES}
210 function route_find_duplicate
() {
213 [ -r "${NETWORK_CONFIG_ROUTES}" ] ||
return ${EXIT_FALSE}
215 local ${NETWORK_CONFIG_ROUTES_PARAMS}
218 route_parse_line
${line}
219 [ $?
-eq ${EXIT_OK} ] ||
continue
221 # Check if the network is already in use.
222 [ "${network}" = "${_network}" ] && return ${EXIT_TRUE}
223 done < ${NETWORK_CONFIG_ROUTES}
228 function route_parse_line() {
231 # Reset all possible settings.
232 for arg in ${NETWORK_CONFIG_ROUTES_PARAMS}; do
233 printf -v ${arg} "%s
" ""
239 network=$(cli_get_val ${arg})
242 gateway=$(cli_get_val ${arg})
245 unreachable=$(cli_get_val ${arg})
248 prohibit=$(cli_get_val ${arg})
251 blackhole=$(cli_get_val ${arg})
254 done <<< "$
(args $@
)"
256 ### Check if all values are correctly set.
258 # network must be set.
259 isset network || return ${EXIT_ERROR}
261 # network must be a valid.
262 ip_is_network ${network} || return ${EXIT_ERROR}
264 # Check gateway settings.
265 if isset gateway; then
266 # When gateway is set, unreachable cannot be set.
267 isset unreachable && return ${EXIT_ERROR}
269 # Must be a valid IP address.
270 ip_is_valid ${gateway} || return ${EXIT_ERROR}
272 # Check if exactly one of unreachable, prohibit or blackhole is set.
273 local counter=$(list_count true ${unreachable} ${prohibit} ${blackhole})
274 [ ${counter} -eq 1 ] || return ${EXIT_ERROR}
280 function route_apply() {
284 log INFO "Applying static routes...
"
286 # Flush the routing table.
287 route_table_flush ${table}
289 local ${NETWORK_CONFIG_ROUTES_PARAMS}
292 route_parse_line ${line}
293 [ $? -eq ${EXIT_OK} ] || continue
297 for arg in unreachable prohibit blackhole; do
298 if enabled ${arg}; then
305 route_entry_add ${network} --table="static
" --proto="static
" \
306 --type="${type}" --gateway="${gateway}"
309 if [ ${ret} -ne ${EXIT_OK} ]; then
310 log WARNING "Could not
set route
'${network}'.
"
312 done < ${NETWORK_CONFIG_ROUTES}
314 # Create a lookup rule for the static routing table.
315 route_rule_add --lookup="static
" --priority=1000
318 function route_entry_add() {
327 while [ $# -gt 0 ]; do
330 gateway=$(cli_get_val ${1})
333 table=$(cli_get_val ${1})
336 type=$(cli_get_val ${1})
339 proto=$(cli_get_val ${1})
342 if isset network; then
343 warning "Unrecognized argument
: ${1}"
353 assert isoneof type unicast broadcast unreachable prohibit blackhole
354 assert ip_is_network ${network}
356 # Detect the protocol of the given network.
357 local protocol=$(ip_detect_protocol ${network})
358 case "${protocol}" in
360 command="ip
-6 route add
"
363 command="ip route add
"
369 list_append command "${type}"
371 # Add network/prefix.
372 list_append command "${network}"
374 if [ "${type}" = "unicast
" ]; then
376 assert ip_is_valid ${gateway}
378 list_append command "via
${gateway}"
381 # Add table (if any).
383 # Create routing table, if it does not exist, yet.
384 route_table_create ${table}
386 list_append command "table
${table}"
391 list_append command "proto
${proto}"
397 function route_table_create() {
401 if route_table_exists ${table}; then
405 # Get the next free id.
406 local id=$(_route_table_next_id)
409 # Write everything to file.
410 print "%d
\t%s
" "${id}" "${table}" >> /etc/iproute2/rt_tables
412 log DEBUG "Created routing table
'${table}'.
"
417 function _route_table_next_id() {
418 # The Linux kernel is able to manage 255 routing tables (1-255).
419 # This function returns the next free id, starting from 255.
422 for next_id in {255..1}; do
423 if ! route_table_exists --id="${next_id}"; then
432 function route_table_flush() {
436 while [ $# -gt 0 ]; do
439 protocol=$(cli_get_val ${1})
448 # If the table does not exists, there is nothing to
450 route_table_exists ${table} || return ${EXIT_OK}
454 for proto in ${IP_SUPPORTED_PROTOCOLS}; do
455 # Skip unwanted protocols.
456 if isset protocol; then
457 [ "${protocol}" = "${proto}" ] || continue
463 command="ip
-6 route flush
"
466 command="ip route flush
"
471 list_append command "table
${table}"
480 function route_table_exists() {
483 while [ $# -gt 0 ]; do
486 _id=$(cli_get_val ${1})
497 while read -r id table; do
499 [ "${id:0:1}" = "#" ] && continue
501 if [ "${_table}" = "${table}" ] || [ "${_id}" = "${id}" ]; then
505 done < /etc
/iproute
2/rt_tables
510 function route_rule_add
() {
512 local protocols
=${IP_SUPPORTED_PROTOCOLS}
515 while [ $# -gt 0 ]; do
518 lookup
=$
(cli_get_val
${1})
521 priority
=$
(cli_get_val
${1})
524 protocols
=$
(cli_get_val
${1})
526 assert isoneof protocols
${IP_SUPPORTED_PROTOCOLS}
529 warning
"Unhandled argument: ${1}"
535 local command options
537 if isset lookup
; then
538 route_table_create
${lookup}
540 list_append options
"lookup ${lookup}"
543 if isset priority
; then
544 assert isinteger priority
546 list_append options
"prio ${priority}"
550 for proto
in ${protocols}; do
554 command="ip -6 rule add ${options}"
557 command="ip rule add ${options}"
562 # Skip, if the rule does already exist.
564 --protocol=${proto} \
566 --priority=${priority} \
573 function route_rule_exists
() {
579 while [ $# -gt 0 ]; do
582 from
=$
(cli_get_val
${1})
585 lookup
=$
(cli_get_val
${1})
588 prio
=$
(cli_get_val
${1})
591 proto
=$
(cli_get_val
${1})
594 warning
"Unrecognized argument: ${1}"
603 command="ip -6 rule show"
606 command="ip rule show"
611 local _lookup _from _prio
613 while read -r line
; do
614 _route_rule_exists_parse
${line}
617 [ "${from}" = "${_from}" ] ||
continue
621 [ "${prio}" = "${_prio}" ] ||
continue
624 if isset lookup
; then
625 [ "${lookup}" = "${_lookup}" ] ||
continue
629 done <<< "$(${command})"
634 function _route_rule_exists_parse
() {
635 # Reset all variables.
640 while [ $# -gt 0 ]; do
655 # Skip unknown arguments.