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