aboutsummaryrefslogtreecommitdiff
path: root/net/mwan3/files/usr/sbin/mwan3rtmon
blob: b7f03cc8746c6c1a615e526bdeab40cd30d063f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
#!/bin/sh

. /lib/functions.sh
. /lib/functions/network.sh
. /lib/mwan3/mwan3.sh

trap_with_arg()
{
	func="$1" ; shift
	pid="$1" ; shift
	for sig ; do
		# shellcheck disable=SC2064
		trap "$func $sig $pid" "$sig"
	done
}

func_trap()
{
	kill -${1} ${2} 2>/dev/null
}

mwan3_add_all_routes()
{
	local tid IP IPT route_line family active_tbls tid initial_state error
	local ipv=$1

	add_active_tbls()
	{
		let tid++
		config_get family "$1" family ipv4
		config_get initial_state "$1" initial_state "online"
		[ "$family" != "$ipv" ] && return
		if $IPT -S "mwan3_iface_in_$1" &> /dev/null; then
			active_tbls="$active_tbls${tid} "
		fi
	}

	add_route()
	{
		let tid++
		[ -n "${active_tbls##* $tid *}" ] && return
		error=$($IP route add table $tid $route_line 2>&1) ||
			LOG warn "failed to add $route_line to table $tid - error: $error"
	}

	mwan3_update_dev_to_table
	[ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
	if [ "$ipv" = "ipv4" ]; then
		IP="$IP4"
		IPT="$IPT4"
	elif [ "$ipv" = "ipv6" ]; then
		IP="$IP6"
		IPT="$IPT6"
	fi
	tid=0
	active_tbls=" "
	config_foreach add_active_tbls interface
	[ "$active_tbls" = " " ] && return
	mwan3_get_routes | while read -r route_line; do
		mwan3_route_line_dev "tid" "$route_line" "$ipv"
		if [ -n "$tid" ] && [ -z "${active_tbls##* $tid *}" ]; then
			$IP route add table $tid $route_line
		elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then
			config_foreach add_route interface
		fi
	done
}

mwan3_rtmon_route_handle()
{
	local action route_line family tbl device line tid

	route_line=${1##"Deleted "}
	route_family=$2

	if [ "$route_line" = "$1" ]; then
		action="replace"
		$IPS -! add mwan3_connected_${route_family##ip} ${route_line%% *}
	else
		action="del"
		mwan3_set_connected_${route_family}
	fi

	if [ -z "${route_line##*linkdown*}" ]; then
		LOG debug "attempting to add link on down interface - $route_line"
	fi

	if [ "$route_family" = "ipv4" ]; then
		IP="$IP4"
	elif [ "$route_family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
		IP="$IP6"
	else
		LOG warn "route update called with invalid family - $route_family"
		return
	fi
	route_line=$(echo "$route_line" | sed -ne "$MWAN3_ROUTE_LINE_EXP")

	handle_route() {
		local error
		local iface=$1
		tbl=$($IP route list table $tid 2>/dev/null)$'\n'

		if [ -n "$iface" ] && [ "$(mwan3_get_mwan3track_status $iface)" != "active" ]; then
			LOG debug "interface $iface is disabled - skipping '$route_line'";
			return
		fi

		# check that action needs to be performed. May not need to take action if we
		# got a delete event, but table was already flushed
		if [ $action = "del" ] && [ -n "${tbl##*$route_line$'\n'*}" ]; then
			LOG debug "skipping already deleted route table $tid - skipping '$route_line'"
			return
		fi

		network_get_device device "$iface"
		LOG debug "adjusting route $device: '$IP route $action table $tid $route_line'"
		error=$($IP route "$action" table $tid $route_line 2>&1)||
			LOG warn "failed: '$IP route $action table $tid $route_line' - error: $error"
	}
	handle_route_cb(){
		local iface=$1
		let tid++
		config_get family "$iface" family ipv4
		[ "$family" != "$route_family" ] && return
		handle_route "$iface"
	}

	mwan3_update_dev_to_table
	mwan3_route_line_dev "tid" "$route_line" "$route_family"

	if [ -n "$tid" ]; then
		handle_route
	elif [ -n "${route_line##default*}" ] && [ -n "${route_line##fe80::/64*}" ]; then
		config_foreach handle_route_cb interface
	fi
}

main()
{
	local IP family

	mwan3_init

	family=$1
	[ -z $family ] && family=ipv4
	if [ "$family" = "ipv6" ]; then
		if [ $NO_IPV6 -ne 0 ]; then
			LOG warn "mwan3rtmon started for ipv6, but ipv6 not enabled on system"
			exit 1
		fi
		IP="$IP6"
	else
		IP="$IP4"
	fi
	sh -c "echo \$\$; exec $IP monitor route" | {
		read -r monitor_pid
		trap_with_arg func_trap "$monitor_pid" SIGINT SIGTERM SIGKILL
		KILL -SIGSTOP $$
		while IFS='' read -r line; do
			[ -z "${line##*table*}" ] && continue
			LOG debug "handling route update $family '$line'"
			mwan3_rtmon_route_handle "$line" "$family"
		done
	} &
	child=$!
	trap_with_arg func_trap "$child" SIGINT SIGTERM SIGKILL
	mwan3_set_connected_${family}
	mwan3_add_all_routes ${family}
	kill -SIGCONT $child
	wait $child
}
main "$@"