]> git.ipfire.org Git - people/stevee/network.git/blame - src/functions/functions.route
Remove the function keyword which is a bashism
[people/stevee/network.git] / src / functions / functions.route
CommitLineData
cb965348
MT
1#!/bin/bash
2###############################################################################
3# #
4# IPFire.org - A linux based firewall #
5# Copyright (C) 2012 IPFire Network Development Team #
6# #
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. #
11# #
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. #
16# #
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/>. #
19# #
20###############################################################################
21#
22# Functions for static routing.
23#
24
1c6a4e30 25route_init() {
d2021e87
MT
26 # Apply configured static routes.
27 route_apply
28}
29
30init_register route_init
31
1c6a4e30 32route_add() {
cb965348
MT
33 local ${NETWORK_CONFIG_ROUTES_PARAMS}
34
35 while [ $# -gt 0 ]; do
36 case "${1}" in
37 --gateway=*)
38 gateway=$(cli_get_val ${1})
39 ;;
40 --unreachable)
41 unreachable="true"
42 ;;
55ea0266
MT
43 --prohibit)
44 prohibit="true"
45 ;;
46 --blackhole)
47 blackhole="true"
48 ;;
478de6f9
MT
49 --mtu=*)
50 mtu=$(cli_get_val ${1})
51 ;;
cb965348
MT
52 *)
53 network=${1}
54 ;;
55 esac
56 shift
57 done
58
59 assert isset network
60
61 if ! ip_is_valid ${network}; then
62 error "The given network is invalid: ${network}"
63 return ${EXIT_ERROR}
64 fi
65
66 if route_find_duplicate ${network}; then
67 error "A route to ${network} does already exist."
68 return ${EXIT_ERROR}
69 fi
70
71 # Check if gateway and unreachable are both enabled.
cb965348 72 if isset gateway; then
55ea0266
MT
73 if enabled unreachable; then
74 error "You cannot use both, --gateway=${gateway} and --unreachable at the same time."
75 return ${EXIT_ERROR}
76 fi
77
78 if enabled prohibit; then
79 error "You cannot use both, --gateway=${gateway} and --prohibit at the same time."
80 return ${EXIT_ERROR}
81 fi
82
83 if enabled blackhole; then
84 error "You cannot use both, --gateway=${gateway} and --blackhole at the same time."
85 return ${EXIT_ERROR}
86 fi
87
88 # Check if network and gateway IP protocol version match.
d2021e87
MT
89 if ! ip_is_valid ${gateway}; then
90 error "--gateway= is not a valid IP address."
91 return ${EXIT_ERROR}
92 fi
93
cb965348
MT
94 local network_proto=$(ip_detect_protocol ${network})
95 local gateway_proto=$(ip_detect_protocol ${gateway})
96
97 if [ "${network_proto}" != "${gateway_proto}" ]; then
98 error "The IP protocol version of the given network and gateway did not match."
99 return ${EXIT_ERROR}
100 fi
55ea0266
MT
101
102 else
103 local counter=$(list_count true ${unreachable} ${prohibit} ${blackhole})
104 if [ ${counter} -gt 1 ]; then
105 error "You can only use one of --unreachable, --prohibit or --blackhole."
106 return ${EXIT_ERROR}
107 fi
cb965348
MT
108 fi
109
478de6f9
MT
110 if isset mtu && ! isinteger mtu; then
111 error "MTU must be an integer number: ${mtu}"
112 return ${EXIT_ERROR}
113 fi
114
cb965348
MT
115 local line
116 list_append line "network=\"${network}\""
117
118 # Add gateway to configuration entry when it is set.
119 if isset gateway; then
120 list_append line "gateway=\"${gateway}\""
121 fi
122
123 # Add unreachable to configuration entry when it is set.
55ea0266
MT
124 local arg
125 for arg in unreachable prohibit blackhole; do
126 if enabled ${arg}; then
127 list_append line "${arg}=\"true\""
128 break
129 fi
130 done
cb965348 131
478de6f9
MT
132 # Add MTU (if set).
133 if isset mtu; then
134 list_append line "mtu=\"${mtu}\""
135 fi
136
cb965348
MT
137 # Write line to file.
138 print "${line}" >> ${NETWORK_CONFIG_ROUTES}
139
140 log INFO "New route to network '${network}' has been added."
141 return ${EXIT_OK}
142}
143
1c6a4e30 144route_remove() {
cb965348
MT
145 local _network=${1}
146 assert isset _network
147
148 local found="false"
149
150 local ${NETWORK_CONFIG_ROUTES_PARAMS}
151 local line
152 while read line; do
153 route_parse_line ${line}
154 [ $? -eq ${EXIT_OK} ] || continue
155
156 # Skip the rule, we want to delete.
157 if [ "${network}" = "${_network}" ]; then
158 found="true"
159 continue
160 fi
161
162 print "${line}"
163 done < ${NETWORK_CONFIG_ROUTES} > ${NETWORK_CONFIG_ROUTES}.tmp
164 mv ${NETWORK_CONFIG_ROUTES}{.tmp,}
165
166 if enabled found; then
167 log INFO "Route to network '${_network}' has been removed."
168 else
169 error "No route to network '${_network}' was found."
170 return ${EXIT_ERROR}
171 fi
172
173 return ${EXIT_OK}
174}
175
1c6a4e30 176route_list() {
cb965348
MT
177 local protocol
178
179 while [ $# -gt 0 ]; do
180 case "${1}" in
181 --protocol=*)
182 protocol=$(cli_get_val ${1})
183 ;;
184 *)
185 warning "Unrecognized argument: ${1}"
186 ;;
187 esac
188 shift
189 done
190
191 if [ ! -r "${NETWORK_CONFIG_ROUTES}" ]; then
192 print "No static routes defined."
193 return ${EXIT_OK}
194 fi
195
478de6f9
MT
196 local format="%-40s %-20s %-4s"
197 print "${format}" "NETWORK/HOST" "GATEWAY" "MTU"
cb965348
MT
198
199 local ${NETWORK_CONFIG_ROUTES_PARAMS}
200 local line
201 while read line; do
202 route_parse_line ${line}
203 [ $? -eq ${EXIT_OK} ] || continue
204
55ea0266
MT
205 local arg
206 for arg in unreachable prohibit blackhole; do
207 if enabled ${arg}; then
208 gateway="<${arg}>"
209 break
210 fi
211 done
cb965348
MT
212
213 # Filter all entries with a wrong protocol.
214 if isset protocol; then
215 local proto=$(ip_detect_protocol ${network})
216 [ "${protocol}" = "${proto}" ] || continue
217 fi
218
478de6f9
MT
219 # Print something when no MTU was set.
220 if ! isset mtu; then
221 mtu="-"
222 fi
223
224 print "${format}" "${network}" "${gateway}" "${mtu}"
cb965348
MT
225 done < ${NETWORK_CONFIG_ROUTES}
226}
227
1c6a4e30 228route_find_duplicate() {
cb965348
MT
229 local _network=${1}
230
231 [ -r "${NETWORK_CONFIG_ROUTES}" ] || return ${EXIT_FALSE}
232
233 local ${NETWORK_CONFIG_ROUTES_PARAMS}
234 local line
235 while read line; do
236 route_parse_line ${line}
d2021e87 237 [ $? -eq ${EXIT_OK} ] || continue
cb965348
MT
238
239 # Check if the network is already in use.
240 [ "${network}" = "${_network}" ] && return ${EXIT_TRUE}
241 done < ${NETWORK_CONFIG_ROUTES}
242
243 return ${EXIT_FALSE}
244}
245
1c6a4e30 246route_parse_line() {
cb965348
MT
247 local arg
248
249 # Reset all possible settings.
250 for arg in ${NETWORK_CONFIG_ROUTES_PARAMS}; do
251 printf -v ${arg} "%s" ""
252 done
253
254 while read arg; do
255 case "${arg}" in
256 network=*)
257 network=$(cli_get_val ${arg})
258 ;;
259 gateway=*)
260 gateway=$(cli_get_val ${arg})
261 ;;
262 unreachable=*)
263 unreachable=$(cli_get_val ${arg})
264 ;;
55ea0266
MT
265 prohibit=*)
266 prohibit=$(cli_get_val ${arg})
267 ;;
268 blackhole=*)
269 blackhole=$(cli_get_val ${arg})
270 ;;
478de6f9
MT
271 mtu=*)
272 mtu=$(cli_get_val ${arg})
273 ;;
cb965348
MT
274 esac
275 done <<< "$(args $@)"
276
277 ### Check if all values are correctly set.
278
279 # network must be set.
280 isset network || return ${EXIT_ERROR}
281
282 # network must be a valid.
283 ip_is_network ${network} || return ${EXIT_ERROR}
284
285 # Check gateway settings.
286 if isset gateway; then
287 # When gateway is set, unreachable cannot be set.
288 isset unreachable && return ${EXIT_ERROR}
289
290 # Must be a valid IP address.
291 ip_is_valid ${gateway} || return ${EXIT_ERROR}
292 else
55ea0266
MT
293 # Check if exactly one of unreachable, prohibit or blackhole is set.
294 local counter=$(list_count true ${unreachable} ${prohibit} ${blackhole})
295 [ ${counter} -eq 1 ] || return ${EXIT_ERROR}
cb965348
MT
296 fi
297
478de6f9
MT
298 # mtu must be an integer number.
299 if isset mtu; then
300 isinteger mtu || return ${EXIT_ERROR}
301 fi
302
cb965348
MT
303 return ${EXIT_OK}
304}
d2021e87 305
1c6a4e30 306route_apply() {
d2021e87
MT
307 local table="static"
308 local type
309
6cb149c5
MT
310 log INFO "Applying static routes..."
311
d2021e87
MT
312 # Flush the routing table.
313 route_table_flush ${table}
314
315 local ${NETWORK_CONFIG_ROUTES_PARAMS}
316 local line
317 while read line; do
318 route_parse_line ${line}
319 [ $? -eq ${EXIT_OK} ] || continue
320
321 type="unicast"
55ea0266
MT
322 local arg
323 for arg in unreachable prohibit blackhole; do
324 if enabled ${arg}; then
325 type="${arg}"
326 break
327 fi
328 done
d2021e87
MT
329
330 # Add the route.
331 route_entry_add ${network} --table="static" --proto="static" \
478de6f9 332 --type="${type}" --gateway="${gateway}" --mtu="${mtu}"
d2021e87
MT
333 local ret=$?
334
335 if [ ${ret} -ne ${EXIT_OK} ]; then
336 log WARNING "Could not set route '${network}'."
337 fi
338 done < ${NETWORK_CONFIG_ROUTES}
339
340 # Create a lookup rule for the static routing table.
341 route_rule_add --lookup="static" --priority=1000
342}
343
1c6a4e30 344route_entry_add() {
d2021e87
MT
345 local gateway
346 local network
347 local proto
348 local table
349 local type="unicast"
478de6f9 350 local mtu
d2021e87
MT
351
352 local command
353
354 while [ $# -gt 0 ]; do
355 case "${1}" in
356 --gateway=*)
357 gateway=$(cli_get_val ${1})
358 ;;
359 --table=*)
360 table=$(cli_get_val ${1})
361 ;;
362 --type=*)
363 type=$(cli_get_val ${1})
364 ;;
365 --proto=*)
366 proto=$(cli_get_val ${1})
367 ;;
478de6f9
MT
368 --mtu=*)
369 mtu=$(cli_get_val ${1})
370 ;;
d2021e87
MT
371 *)
372 if isset network; then
373 warning "Unrecognized argument: ${1}"
374 else
375 network=${1}
376 fi
377 ;;
378 esac
379 shift
380 done
381
382 # Validate input.
383 assert isoneof type unicast broadcast unreachable prohibit blackhole
384 assert ip_is_network ${network}
478de6f9
MT
385 if isset mtu; then
386 assert isinteger mtu
387 fi
d2021e87
MT
388
389 # Detect the protocol of the given network.
390 local protocol=$(ip_detect_protocol ${network})
391 case "${protocol}" in
392 ipv6)
393 command="ip -6 route add"
394 ;;
395 ipv4)
396 command="ip route add"
397 ;;
398 esac
399 assert isset command
400
401 # Add type.
402 list_append command "${type}"
403
404 # Add network/prefix.
405 list_append command "${network}"
406
407 if [ "${type}" = "unicast" ]; then
408 assert isset gateway
409 assert ip_is_valid ${gateway}
410
411 list_append command "via ${gateway}"
412 fi
413
414 # Add table (if any).
415 if isset table; then
416 # Create routing table, if it does not exist, yet.
417 route_table_create ${table}
418
419 list_append command "table ${table}"
420 fi
421
422 # Add proto.
423 if isset proto; then
424 list_append command "proto ${proto}"
425 fi
426
478de6f9
MT
427 # Add MTU.
428 if isset mtu; then
429 list_append command "mtu ${mtu}"
430 fi
431
432 cmd_quiet "${command}"
d2021e87
MT
433}
434
1c6a4e30 435route_table_create() {
d2021e87
MT
436 local table=${1}
437 assert isset table
438
439 if route_table_exists ${table}; then
440 return ${EXIT_OK}
441 fi
442
443 # Get the next free id.
444 local id=$(_route_table_next_id)
445 assert isset id
446
447 # Write everything to file.
448 print "%d\t%s" "${id}" "${table}" >> /etc/iproute2/rt_tables
449
450 log DEBUG "Created routing table '${table}'."
451
452 return ${EXIT_OK}
453}
454
1c6a4e30 455_route_table_next_id() {
d2021e87
MT
456 # The Linux kernel is able to manage 255 routing tables (1-255).
457 # This function returns the next free id, starting from 255.
458 local next_id
459
460 for next_id in {255..1}; do
461 if ! route_table_exists --id="${next_id}"; then
462 print "${next_id}"
463 return ${EXIT_OK}
464 fi
465 done
466
467 return ${EXIT_FALSE}
468}
469
1c6a4e30 470route_table_flush() {
d2021e87
MT
471 local protocol
472 local table
473
474 while [ $# -gt 0 ]; do
475 case "${1}" in
476 --protocol=*)
477 protocol=$(cli_get_val ${1})
478 ;;
479 *)
480 table="${1}"
481 ;;
482 esac
483 shift
484 done
485
486 # If the table does not exists, there is nothing to
487 # flush.
488 route_table_exists ${table} || return ${EXIT_OK}
489
490 local command
491 local proto
492 for proto in ${IP_SUPPORTED_PROTOCOLS}; do
493 # Skip unwanted protocols.
494 if isset protocol; then
495 [ "${protocol}" = "${proto}" ] || continue
496 fi
497
498 command=""
499 case "${proto}" in
500 ipv6)
501 command="ip -6 route flush"
502 ;;
503 ipv4)
504 command="ip route flush"
505 ;;
506 esac
507 assert isset command
508
509 list_append command "table ${table}"
510
511 # Execute command.
512 cmd "${command}"
513 done
514
515 return ${EXIT_OK}
516}
517
1c6a4e30 518route_table_exists() {
d2021e87
MT
519 local _id _table
520
521 while [ $# -gt 0 ]; do
522 case "${1}" in
523 --id=*)
524 _id=$(cli_get_val ${1})
525 ;;
526 *)
527 _table=${1}
528 break
529 ;;
530 esac
531 shift
532 done
533
534 local id table
535 while read -r id table; do
536 # Skip all comments.
537 [ "${id:0:1}" = "#" ] && continue
538
539 if [ "${_table}" = "${table}" ] || [ "${_id}" = "${id}" ]; then
540 # Found a match.
541 return ${EXIT_TRUE}
542 fi
543 done < /etc/iproute2/rt_tables
544
545 return ${EXIT_FALSE}
546}
547
1c6a4e30 548route_rule_add() {
d2021e87
MT
549 local priority
550 local protocols=${IP_SUPPORTED_PROTOCOLS}
551 local lookup
552
553 while [ $# -gt 0 ]; do
554 case "${1}" in
555 --lookup=*)
556 lookup=$(cli_get_val ${1})
557 ;;
558 --priority=*)
559 priority=$(cli_get_val ${1})
560 ;;
561 --protocol=*)
562 protocols=$(cli_get_val ${1})
563
564 assert isoneof protocols ${IP_SUPPORTED_PROTOCOLS}
565 ;;
566 *)
567 warning "Unhandled argument: ${1}"
568 ;;
569 esac
570 shift
571 done
572
573 local command options
574
575 if isset lookup; then
576 route_table_create ${lookup}
577
578 list_append options "lookup ${lookup}"
579 fi
580
581 if isset priority; then
582 assert isinteger priority
583
584 list_append options "prio ${priority}"
585 fi
586
587 local proto
588 for proto in ${protocols}; do
589 command=
590 case "${proto}" in
591 ipv6)
592 command="ip -6 rule add ${options}"
593 ;;
594 ipv4)
595 command="ip rule add ${options}"
596 ;;
597 esac
598 assert isset command
599
600 # Skip, if the rule does already exist.
601 route_rule_exists \
602 --protocol=${proto} \
603 --lookup=${lookup} \
604 --priority=${priority} \
605 && continue
606
607 cmd "${command}"
608 done
609}
610
1c6a4e30 611route_rule_exists() {
d2021e87
MT
612 local from
613 local lookup
614 local proto
615 local prio
616
617 while [ $# -gt 0 ]; do
618 case "${1}" in
619 --from=*)
620 from=$(cli_get_val ${1})
621 ;;
622 --lookup=*)
623 lookup=$(cli_get_val ${1})
624 ;;
625 --priority=*)
626 prio=$(cli_get_val ${1})
627 ;;
628 --protocol=*)
629 proto=$(cli_get_val ${1})
630 ;;
631 *)
632 warning "Unrecognized argument: ${1}"
633 ;;
634 esac
635 shift
636 done
637
638 local command
639 case "${proto}" in
640 ipv6)
641 command="ip -6 rule show"
642 ;;
643 ipv4)
644 command="ip rule show"
645 ;;
646 esac
647 assert isset command
648
649 local _lookup _from _prio
650 local line
651 while read -r line; do
652 _route_rule_exists_parse ${line}
653
654 if isset from; then
655 [ "${from}" = "${_from}" ] || continue
656 fi
657
658 if isset prio; then
659 [ "${prio}" = "${_prio}" ] || continue
660 fi
661
662 if isset lookup; then
663 [ "${lookup}" = "${_lookup}" ] || continue
664 fi
665
666 return ${EXIT_TRUE}
667 done <<< "$(${command})"
668
669 return ${EXIT_FALSE}
670}
671
1c6a4e30 672_route_rule_exists_parse() {
d2021e87
MT
673 # Reset all variables.
674 _lookup=
675 _from=
676 _prio=
677
678 while [ $# -gt 0 ]; do
679 case "${1}" in
680 lookup)
681 _lookup=${2}
682 shift 2
683 ;;
684 from)
685 _from=${2}
686 shift 2
687 ;;
688 *:)
689 _prio=${1//:/}
690 shift
691 ;;
692 *)
693 # Skip unknown arguments.
694 shift
695 ;;
696 esac
697 done
698}