Merge pull request #11353 from kvuorine/fwknop-fixes
[feed/packages.git] / net / mwan3 / files / lib / mwan3 / mwan3.sh
1 #!/bin/sh
2
3 . /usr/share/libubox/jshn.sh
4
5 IP4="ip -4"
6 IP6="ip -6"
7 IPS="ipset"
8 IPT4="iptables -t mangle -w"
9 IPT6="ip6tables -t mangle -w"
10 IPT4R="iptables-restore -T mangle -w -n"
11 IPT6R="ip6tables-restore -T mangle -w -n"
12 CONNTRACK_FILE="/proc/net/nf_conntrack"
13 IPv6_REGEX="([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|"
14 IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,7}:|"
15 IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|"
16 IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|"
17 IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|"
18 IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|"
19 IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|"
20 IPv6_REGEX="${IPv6_REGEX}[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|"
21 IPv6_REGEX="${IPv6_REGEX}:((:[0-9a-fA-F]{1,4}){1,7}|:)|"
22 IPv6_REGEX="${IPv6_REGEX}fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|"
23 IPv6_REGEX="${IPv6_REGEX}::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|"
24 IPv6_REGEX="${IPv6_REGEX}([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])"
25
26 MWAN3_STATUS_DIR="/var/run/mwan3"
27 MWAN3TRACK_STATUS_DIR="/var/run/mwan3track"
28 MWAN3_INTERFACE_MAX=""
29 DEFAULT_LOWEST_METRIC=256
30 MMX_MASK=""
31 MMX_DEFAULT=""
32 MMX_BLACKHOLE=""
33 MM_BLACKHOLE=""
34
35 MMX_UNREACHABLE=""
36 MM_UNREACHABLE=""
37
38 command -v ip6tables > /dev/null
39 NO_IPV6=$?
40
41 mwan3_push_update()
42 {
43 # helper function to build an update string to pass on to
44 # IPTR or IPS RESTORE. Modifies the 'update' variable in
45 # the local scope.
46 update="$update
47 $*";
48 }
49
50 mwan3_update_dev_to_table()
51 {
52 local _tid
53 mwan3_dev_tbl_ipv4=" "
54 mwan3_dev_tbl_ipv6=" "
55
56 update_table()
57 {
58 local family curr_table device enabled
59 let _tid++
60 config_get family "$1" family ipv4
61 network_get_device device "$1"
62 [ -z "$device" ] && return
63 config_get enabled "$1" enabled
64 [ "$enabled" -eq 0 ] && return
65 curr_table=$(eval "echo \"\$mwan3_dev_tbl_${family}\"")
66 export "mwan3_dev_tbl_$family=${curr_table}${device}=$_tid "
67 }
68 network_flush_cache
69 config_foreach update_table interface
70 }
71
72 mwan3_update_iface_to_table()
73 {
74 local _tid
75 mwan3_iface_tbl=" "
76 update_table()
77 {
78 let _tid++
79 export mwan3_iface_tbl="${mwan3_iface_tbl}${1}=$_tid "
80 }
81 config_foreach update_table interface
82 }
83
84 mwan3_get_true_iface()
85 {
86 local family V
87 _true_iface=$2
88 config_get family "$iface" family ipv4
89 if [ "$family" = "ipv4" ]; then
90 V=4
91 elif [ "$family" = "ipv6" ]; then
92 V=6
93 fi
94 ubus call "network.interface.${iface}_${V}" status &>/dev/null && _true_iface="${iface}_${V}"
95 export "$1=$_true_iface"
96 }
97
98 mwan3_route_line_dev()
99 {
100 # must have mwan3 config already loaded
101 # arg 1 is route device
102 local _tid route_line route_device route_family entry curr_table
103 route_line=$2
104 route_family=$3
105 route_device=$(echo "$route_line" | sed -ne "s/.*dev \([^ ]*\).*/\1/p")
106 unset "$1"
107 [ -z "$route_device" ] && return
108
109 curr_table=$(eval "echo \"\$mwan3_dev_tbl_${route_family}\"")
110 for entry in $curr_table; do
111 if [ "${entry%%=*}" = "$route_device" ]; then
112 _tid=${entry##*=}
113 export "$1=$_tid"
114 return
115 fi
116 done
117 }
118
119 # counts how many bits are set to 1
120 # n&(n-1) clears the lowest bit set to 1
121 mwan3_count_one_bits()
122 {
123 local count n
124 count=0
125 n=$(($1))
126 while [ "$n" -gt "0" ]; do
127 n=$((n&(n-1)))
128 count=$((count+1))
129 done
130 echo $count
131 }
132
133 # maps the 1st parameter so it only uses the bits allowed by the bitmask (2nd parameter)
134 # which means spreading the bits of the 1st parameter to only use the bits that are set to 1 in the 2nd parameter
135 # 0 0 0 0 0 1 0 1 (0x05) 1st parameter
136 # 1 0 1 0 1 0 1 0 (0xAA) 2nd parameter
137 # 1 0 1 result
138 mwan3_id2mask()
139 {
140 local bit_msk bit_val result
141 bit_val=0
142 result=0
143 for bit_msk in $(seq 0 31); do
144 if [ $((($2>>bit_msk)&1)) = "1" ]; then
145 if [ $((($1>>bit_val)&1)) = "1" ]; then
146 result=$((result|(1<<bit_msk)))
147 fi
148 bit_val=$((bit_val+1))
149 fi
150 done
151 printf "0x%x" $result
152 }
153
154 mwan3_init()
155 {
156 local bitcnt
157 local mmdefault
158
159 [ -d $MWAN3_STATUS_DIR ] || mkdir -p $MWAN3_STATUS_DIR/iface_state
160
161 # mwan3's MARKing mask (at least 3 bits should be set)
162 if [ -e "${MWAN3_STATUS_DIR}/mmx_mask" ]; then
163 MMX_MASK=$(cat "${MWAN3_STATUS_DIR}/mmx_mask")
164 MWAN3_INTERFACE_MAX=$(uci_get_state mwan3 globals iface_max)
165 else
166 config_load mwan3
167 config_get MMX_MASK globals mmx_mask '0x3F00'
168 echo "$MMX_MASK"| tr 'A-F' 'a-f' > "${MWAN3_STATUS_DIR}/mmx_mask"
169 LOG debug "Using firewall mask ${MMX_MASK}"
170
171 bitcnt=$(mwan3_count_one_bits MMX_MASK)
172 mmdefault=$(((1<<bitcnt)-1))
173 MWAN3_INTERFACE_MAX=$(($mmdefault-3))
174 uci_toggle_state mwan3 globals iface_max "$MWAN3_INTERFACE_MAX"
175 LOG debug "Max interface count is ${MWAN3_INTERFACE_MAX}"
176 fi
177
178 # mark mask constants
179 bitcnt=$(mwan3_count_one_bits MMX_MASK)
180 mmdefault=$(((1<<bitcnt)-1))
181 MM_BLACKHOLE=$(($mmdefault-2))
182 MM_UNREACHABLE=$(($mmdefault-1))
183
184 # MMX_DEFAULT should equal MMX_MASK
185 MMX_DEFAULT=$(mwan3_id2mask mmdefault MMX_MASK)
186 MMX_BLACKHOLE=$(mwan3_id2mask MM_BLACKHOLE MMX_MASK)
187 MMX_UNREACHABLE=$(mwan3_id2mask MM_UNREACHABLE MMX_MASK)
188 }
189
190 mwan3_lock() {
191 lock /var/run/mwan3.lock
192 #LOG debug "$1 $2 (lock)"
193 }
194
195 mwan3_unlock() {
196 #LOG debug "$1 $2 (unlock)"
197 lock -u /var/run/mwan3.lock
198 }
199
200 mwan3_get_src_ip()
201 {
202 local family _src_ip true_iface
203 true_iface=$2
204 unset "$1"
205 config_get family "$true_iface" family ipv4
206 if [ "$family" = "ipv4" ]; then
207 network_get_ipaddr _src_ip "$true_iface"
208 [ -n "$_src_ip" ] || _src_ip="0.0.0.0"
209 elif [ "$family" = "ipv6" ]; then
210 network_get_ipaddr6 _src_ip "$true_iface"
211 [ -n "$_src_ip" ] || _src_ip="::"
212 fi
213 export "$1=$_src_ip"
214 }
215
216 mwan3_get_iface_id()
217 {
218 local _tmp
219 [ -z "$mwan3_iface_tbl" ] && mwan3_update_iface_to_table
220 _tmp="${mwan3_iface_tbl##* ${2}=}"
221 _tmp=${_tmp%% *}
222 export "$1=$_tmp"
223 new_val=$_tmp
224 }
225
226 mwan3_set_custom_ipset_v4()
227 {
228 local custom_network_v4
229
230 for custom_network_v4 in $($IP4 route list table "$1" | awk '{print $1}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
231 LOG notice "Adding network $custom_network_v4 from table $1 to mwan3_custom_v4 ipset"
232 mwan3_push_update -! add mwan3_custom_v4 "$custom_network_v4"
233 done
234 }
235
236 mwan3_set_custom_ipset_v6()
237 {
238 local custom_network_v6
239
240 for custom_network_v6 in $($IP6 route list table "$1" | awk '{print $1}' | egrep "$IPv6_REGEX"); do
241 LOG notice "Adding network $custom_network_v6 from table $1 to mwan3_custom_v6 ipset"
242 mwan3_push_update -! add mwan3_custom_v6 "$custom_network_v6"
243 done
244 }
245
246 mwan3_set_custom_ipset()
247 {
248 local update=""
249
250 mwan3_push_update -! create mwan3_custom_v4 hash:net
251 config_list_foreach "globals" "rt_table_lookup" mwan3_set_custom_ipset_v4
252
253 mwan3_push_update -! create mwan3_custom_v6 hash:net family inet6
254 config_list_foreach "globals" "rt_table_lookup" mwan3_set_custom_ipset_v6
255
256 mwan3_push_update -! create mwan3_connected list:set
257 mwan3_push_update -! add mwan3_connected mwan3_custom_v4
258 mwan3_push_update -! add mwan3_connected mwan3_custom_v6
259 error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_custom_ipset: $error"
260 }
261
262
263 mwan3_set_connected_ipv4()
264 {
265 local connected_network_v4 candidate_list cidr_list
266 local ipv4regex='[0-9]{1,3}(\.[0-9]{1,3}){3}'
267 $IPS -! create mwan3_connected_v4 hash:net
268 $IPS create mwan3_connected_v4_temp hash:net
269
270 candidate_list=""
271 cidr_list=""
272 route_lists()
273 {
274 $IP4 route | awk '{print $1}'
275 $IP4 route list table 0 | awk '{print $2}'
276 }
277 for connected_network_v4 in $(route_lists | egrep "$ipv4regex"); do
278 if [ -z "${connected_network_v4##*/*}" ]; then
279 cidr_list="$cidr_list $connected_network_v4"
280 else
281 candidate_list="$candidate_list $connected_network_v4"
282 fi
283 done
284
285 for connected_network_v4 in $cidr_list; do
286 $IPS -! add mwan3_connected_v4_temp "$connected_network_v4"
287 done
288 for connected_network_v4 in $candidate_list; do
289 ipset -q test mwan3_connected_v4_temp "$connected_network_v4" ||
290 $IPS -! add mwan3_connected_v4_temp "$connected_network_v4"
291 done
292
293 $IPS add mwan3_connected_v4_temp 224.0.0.0/3
294
295 $IPS swap mwan3_connected_v4_temp mwan3_connected_v4
296 $IPS destroy mwan3_connected_v4_temp
297
298 }
299
300 mwan3_set_connected_iptables()
301 {
302 local connected_network_v6 source_network_v6 error
303 local update=""
304 mwan3_set_connected_ipv4
305
306 [ $NO_IPV6 -eq 0 ] && {
307 mwan3_push_update -! create mwan3_connected_v6 hash:net family inet6
308 mwan3_push_update flush mwan3_connected_v6
309
310 for connected_network_v6 in $($IP6 route | awk '{print $1}' | egrep "$IPv6_REGEX"); do
311 mwan3_push_update -! add mwan3_connected_v6 "$connected_network_v6"
312 done
313
314 mwan3_push_update -! create mwan3_source_v6 hash:net family inet6
315 for source_network_v6 in $($IP6 addr ls | sed -ne 's/ *inet6 \([^ \/]*\).* scope global.*/\1/p'); do
316 mwan3_push_update -! add mwan3_source_v6 "$source_network_v6"
317 done
318 }
319
320 mwan3_push_update -! create mwan3_connected list:set
321 mwan3_push_update flush mwan3_connected
322 mwan3_push_update -! add mwan3_connected mwan3_connected_v4
323 [ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_connected_v6
324
325 mwan3_push_update -! create mwan3_dynamic_v4 hash:net
326 mwan3_push_update -! add mwan3_connected mwan3_dynamic_v4
327
328 [ $NO_IPV6 -eq 0 ] && mwan3_push_update -! create mwan3_dynamic_v6 hash:net family inet6
329 [ $NO_IPV6 -eq 0 ] && mwan3_push_update -! add mwan3_connected mwan3_dynamic_v6
330 error=$(echo "$update" | $IPS restore 2>&1) || LOG error "set_connected_iptables: $error"
331 }
332
333 mwan3_set_general_rules()
334 {
335 local IP
336
337 for IP in "$IP4" "$IP6"; do
338 [ "$IP" = "$IP6" ] && [ $NO_IPV6 -ne 0 ] && continue
339 RULE_NO=$(($MM_BLACKHOLE+2000))
340 if [ -z "$($IP rule list | awk -v var="$RULE_NO:" '$1 == var')" ]; then
341 $IP rule add pref $RULE_NO fwmark $MMX_BLACKHOLE/$MMX_MASK blackhole
342 fi
343
344 RULE_NO=$(($MM_UNREACHABLE+2000))
345 if [ -z "$($IP rule list | awk -v var="$RULE_NO:" '$1 == var')" ]; then
346 $IP rule add pref $RULE_NO fwmark $MMX_UNREACHABLE/$MMX_MASK unreachable
347 fi
348 done
349 }
350
351 mwan3_set_general_iptables()
352 {
353 local IPT current update error
354 for IPT in "$IPT4" "$IPT6"; do
355 [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
356 current="$($IPT -S)"
357 update="*mangle"
358 if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
359 mwan3_push_update -N mwan3_ifaces_in
360 fi
361
362 if [ -n "${current##*-N mwan3_connected*}" ]; then
363 mwan3_push_update -N mwan3_connected
364 $IPS -! create mwan3_connected list:set
365 mwan3_push_update -A mwan3_connected \
366 -m set --match-set mwan3_connected dst \
367 -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
368 fi
369
370 if [ -n "${current##*-N mwan3_rules*}" ]; then
371 mwan3_push_update -N mwan3_rules
372 fi
373
374 if [ -n "${current##*-N mwan3_hook*}" ]; then
375 mwan3_push_update -N mwan3_hook
376 # do not mangle ipv6 ra service
377 if [ "$IPT" = "$IPT6" ]; then
378 mwan3_push_update -A mwan3_hook \
379 -p ipv6-icmp \
380 -m icmp6 --icmpv6-type 133 \
381 -j RETURN
382 mwan3_push_update -A mwan3_hook \
383 -p ipv6-icmp \
384 -m icmp6 --icmpv6-type 134 \
385 -j RETURN
386 mwan3_push_update -A mwan3_hook \
387 -p ipv6-icmp \
388 -m icmp6 --icmpv6-type 135 \
389 -j RETURN
390 mwan3_push_update -A mwan3_hook \
391 -p ipv6-icmp \
392 -m icmp6 --icmpv6-type 136 \
393 -j RETURN
394 mwan3_push_update -A mwan3_hook \
395 -p ipv6-icmp \
396 -m icmp6 --icmpv6-type 137 \
397 -j RETURN
398 # do not mangle outgoing echo request
399 mwan3_push_update -A mwan3_hook \
400 -m set --match-set mwan3_source_v6 src \
401 -p ipv6-icmp \
402 -m icmp6 --icmpv6-type 128 \
403 -j RETURN
404
405 fi
406 mwan3_push_update -A mwan3_hook \
407 -j CONNMARK --restore-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
408 mwan3_push_update -A mwan3_hook \
409 -m mark --mark 0x0/$MMX_MASK \
410 -j mwan3_ifaces_in
411 mwan3_push_update -A mwan3_hook \
412 -m mark --mark 0x0/$MMX_MASK \
413 -j mwan3_connected
414 mwan3_push_update -A mwan3_hook \
415 -m mark --mark 0x0/$MMX_MASK \
416 -j mwan3_rules
417 mwan3_push_update -A mwan3_hook \
418 -j CONNMARK --save-mark --nfmask "$MMX_MASK" --ctmask "$MMX_MASK"
419 mwan3_push_update -A mwan3_hook \
420 -m mark ! --mark $MMX_DEFAULT/$MMX_MASK \
421 -j mwan3_connected
422 fi
423
424 if [ -n "${current##*-A PREROUTING -j mwan3_hook*}" ]; then
425 mwan3_push_update -A PREROUTING -j mwan3_hook
426 fi
427 if [ -n "${current##*-A OUTPUT -j mwan3_hook*}" ]; then
428 mwan3_push_update -A OUTPUT -j mwan3_hook
429 fi
430 mwan3_push_update COMMIT
431 mwan3_push_update ""
432 if [ "$IPT" = "$IPT4" ]; then
433 error=$(echo "$update" | $IPT4R 2>&1) || LOG error "set_general_iptables: $error"
434 else
435 error=$(echo "$update" | $IPT6R 2>&1) || LOG error "set_general_iptables: $error"
436 fi
437 done
438 }
439
440 mwan3_create_iface_iptables()
441 {
442 local id family connected_name IPT IPTR current update error
443
444 config_get family "$1" family ipv4
445 mwan3_get_iface_id id "$1"
446
447 [ -n "$id" ] || return 0
448
449 if [ "$family" = "ipv4" ]; then
450 connected_name=mwan3_connected
451 IPT="$IPT4"
452 IPTR="$IPT4R"
453 $IPS -! create $connected_name list:set
454
455 elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
456 connected_name=mwan3_connected_v6
457 IPT="$IPT6"
458 IPTR="$IPT6R"
459 $IPS -! create $connected_name hash:net family inet6
460 else
461 return
462 fi
463 current="$($IPT -S)"
464 update="*mangle"
465 if [ -n "${current##*-N mwan3_ifaces_in*}" ]; then
466 mwan3_push_update -N mwan3_ifaces_in
467 fi
468
469 if [ -n "${current##*-N mwan3_iface_in_$1*}" ]; then
470 mwan3_push_update -N "mwan3_iface_in_$1"
471 else
472 mwan3_push_update -F "mwan3_iface_in_$1"
473 fi
474
475 mwan3_push_update -A "mwan3_iface_in_$1" \
476 -i "$2" \
477 -m set --match-set $connected_name src \
478 -m mark --mark 0x0/$MMX_MASK \
479 -m comment --comment "default" \
480 -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
481 mwan3_push_update -A "mwan3_iface_in_$1" \
482 -i "$2" \
483 -m mark --mark 0x0/$MMX_MASK \
484 -m comment --comment "$1" \
485 -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
486
487 if [ -n "${current##*-A mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_${1}*}" ]; then
488 mwan3_push_update -A mwan3_ifaces_in \
489 -m mark --mark 0x0/$MMX_MASK \
490 -j "mwan3_iface_in_$1"
491 LOG debug "create_iface_iptables: mwan3_iface_in_$1 not in iptables, adding"
492 else
493 LOG debug "create_iface_iptables: mwan3_iface_in_$1 already in iptables, skip"
494 fi
495
496 mwan3_push_update COMMIT
497 mwan3_push_update ""
498 error=$(echo "$update" | $IPTR 2>&1) || LOG error "create_iface_iptables: $error"
499
500 }
501
502 mwan3_delete_iface_iptables()
503 {
504 local IPT
505 config_get family "$1" family ipv4
506
507 if [ "$family" = "ipv4" ]; then
508 IPT="$IPT4"
509 fi
510
511 if [ "$family" = "ipv6" ]; then
512 [ $NO_IPV6 -ne 0 ] && return
513 IPT="$IPT6"
514 fi
515
516 $IPT -D mwan3_ifaces_in \
517 -m mark --mark 0x0/$MMX_MASK \
518 -j "mwan3_iface_in_$1" &> /dev/null
519 $IPT -F "mwan3_iface_in_$1" &> /dev/null
520 $IPT -X "mwan3_iface_in_$1" &> /dev/null
521
522 }
523
524 mwan3_create_iface_route()
525 {
526 local id via metric V V_ IP family
527 local iface device cmd true_iface
528
529 iface=$1
530 device=$2
531 config_get family "$iface" family ipv4
532 mwan3_get_iface_id id "$iface"
533
534 [ -n "$id" ] || return 0
535
536 mwan3_get_true_iface true_iface $iface
537 if [ "$family" = "ipv4" ]; then
538 V_=""
539 IP="$IP4"
540 elif [ "$family" = "ipv6" ]; then
541 V_=6
542 IP="$IP6"
543 fi
544
545 network_get_gateway${V_} via "$true_iface"
546
547 { [ -z "$via" ] || [ "$via" = "0.0.0.0" ] || [ "$via" = "::" ] ; } && unset via
548
549 network_get_metric metric "$true_iface"
550
551 $IP route flush table "$id"
552 cmd="$IP route add table $id default \
553 ${via:+via} $via \
554 ${metric:+metric} $metric \
555 dev $2"
556 $cmd || LOG warn "ip cmd failed $cmd"
557
558 }
559
560 mwan3_add_non_default_iface_route()
561 {
562 local tid route_line family IP id
563 config_get family "$1" family ipv4
564 mwan3_get_iface_id id "$1"
565
566 [ -n "$id" ] || return 0
567
568 if [ "$family" = "ipv4" ]; then
569 IP="$IP4"
570 elif [ "$family" = "ipv6" ]; then
571 IP="$IP6"
572 fi
573
574 mwan3_update_dev_to_table
575 $IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read route_line; do
576 mwan3_route_line_dev "tid" "$route_line" "$family"
577 if [ -z "$tid" ] || [ "$tid" = "$id" ]; then
578 $IP route add table $id $route_line ||
579 LOG warn "failed to add $route_line to table $id"
580 fi
581
582 done
583 }
584
585 mwan3_add_all_nondefault_routes()
586 {
587 local tid IP route_line ipv family active_tbls tid
588
589 add_active_tbls()
590 {
591 let tid++
592 config_get family "$1" family ipv4
593 [ "$family" != "$ipv" ] && return
594 $IP route list table $tid 2>/dev/null | grep -q "^default\|^::/0" && {
595 active_tbls="$active_tbls${tid} "
596 }
597 }
598
599 add_route()
600 {
601 let tid++
602 [ -n "${active_tbls##* $tid *}" ] && return
603 $IP route add table $tid $route_line ||
604 LOG warn "failed to add $route_line to table $tid"
605 }
606
607 mwan3_update_dev_to_table
608 for ipv in ipv4 ipv6; do
609 [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
610 if [ "$ipv" = "ipv4" ]; then
611 IP="$IP4"
612 elif [ "$ipv" = "ipv6" ]; then
613 IP="$IP6"
614 fi
615 tid=0
616 active_tbls=" "
617 config_foreach add_active_tbls interface
618 $IP route list table main | grep -v "^default\|linkdown\|^::/0\|^fe80::/64\|^unreachable" | while read route_line; do
619 mwan3_route_line_dev "tid" "$route_line" "$ipv"
620 if [ -n "$tid" ]; then
621 $IP route add table $tid $route_line
622 else
623 config_foreach add_route interface
624 fi
625 done
626 done
627 }
628 mwan3_delete_iface_route()
629 {
630 local id
631
632 config_get family "$1" family ipv4
633 mwan3_get_iface_id id "$1"
634
635 [ -n "$id" ] || return 0
636
637 if [ "$family" = "ipv4" ]; then
638 $IP4 route flush table "$id"
639 fi
640
641 if [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
642 $IP6 route flush table "$id"
643 fi
644 }
645
646 mwan3_create_iface_rules()
647 {
648 local id family IP
649
650 config_get family "$1" family ipv4
651 mwan3_get_iface_id id "$1"
652
653 [ -n "$id" ] || return 0
654
655 if [ "$family" = "ipv4" ]; then
656 IP="$IP4"
657 elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
658 IP="$IP6"
659 else
660 return
661 fi
662
663 while [ -n "$($IP rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
664 $IP rule del pref $(($id+1000))
665 done
666
667 while [ -n "$($IP rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
668 $IP rule del pref $(($id+2000))
669 done
670
671 $IP rule add pref $(($id+1000)) iif "$2" lookup "$id"
672 $IP rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup "$id"
673 }
674
675 mwan3_delete_iface_rules()
676 {
677 local id family
678
679 config_get family "$1" family ipv4
680 mwan3_get_iface_id id "$1"
681
682 [ -n "$id" ] || return 0
683
684 if [ "$family" = "ipv4" ]; then
685 IP="$IP4"
686 elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ]; then
687 IP="$IP6"
688 else
689 return
690 fi
691
692 while [ -n "$($IP rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
693 $IP rule del pref $(($id+1000))
694 done
695
696 while [ -n "$($IP rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
697 $IP rule del pref $(($id+2000))
698 done
699 }
700
701 mwan3_delete_iface_ipset_entries()
702 {
703 local id setname entry
704
705 mwan3_get_iface_id id "$1"
706
707 [ -n "$id" ] || return 0
708
709 for setname in $(ipset -n list | grep ^mwan3_sticky_); do
710 for entry in $(ipset list "$setname" | grep "$(mwan3_id2mask id MMX_MASK | awk '{ printf "0x%08x", $1; }')" | cut -d ' ' -f 1); do
711 $IPS del "$setname" $entry
712 done
713 done
714 }
715
716 mwan3_rtmon()
717 {
718 local protocol
719 for protocol in "ipv4" "ipv6"; do
720 pid="$(pgrep -f "mwan3rtmon $protocol")"
721 [ "$protocol" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
722 if [ "${pid}" = "" ]; then
723 [ -x /usr/sbin/mwan3rtmon ] && /usr/sbin/mwan3rtmon $protocol &
724 fi
725 done
726 }
727
728 mwan3_track()
729 {
730 local track_ips pids
731
732 mwan3_list_track_ips()
733 {
734 track_ips="$track_ips $1"
735 }
736 config_list_foreach "$1" track_ip mwan3_list_track_ips
737
738 # don't match device in case it changed from last launch
739 if pids=$(pgrep -f "mwan3track $1 "); then
740 kill -TERM $pids > /dev/null 2>&1
741 sleep 1
742 kill -KILL $(pgrep -f "mwan3track $1 ") > /dev/null 2>&1
743 fi
744
745 if [ -n "$track_ips" ]; then
746 [ -x /usr/sbin/mwan3track ] && MWAN3_STARTUP=0 /usr/sbin/mwan3track "$1" "$2" "$3" "$4" $track_ips &
747 fi
748 }
749
750 mwan3_set_policy()
751 {
752 local id iface family metric probability weight device is_lowest is_offline IPT IPTR total_weight current update error
753
754 is_lowest=0
755 config_get iface "$1" interface
756 config_get metric "$1" metric 1
757 config_get weight "$1" weight 1
758
759 [ -n "$iface" ] || return 0
760 network_get_device device "$iface"
761 [ "$metric" -gt $DEFAULT_LOWEST_METRIC ] && LOG warn "Member interface $iface has >$DEFAULT_LOWEST_METRIC metric. Not appending to policy" && return 0
762
763 mwan3_get_iface_id id "$iface"
764
765 [ -n "$id" ] || return 0
766
767 [ "$(mwan3_get_iface_hotplug_state "$iface")" = "online" ]
768 is_offline=$?
769
770 config_get family "$iface" family ipv4
771
772 if [ "$family" = "ipv4" ]; then
773 IPT="$IPT4"
774 IPTR="$IPT4R"
775 elif [ "$family" = "ipv6" ]; then
776 IPT="$IPT6"
777 IPTR="$IPT6R"
778 fi
779 current="$($IPT -S)"
780 update="*mangle"
781
782 if [ "$family" = "ipv4" ] && [ $is_offline -eq 0 ]; then
783 if [ "$metric" -lt "$lowest_metric_v4" ]; then
784 is_lowest=1
785 total_weight_v4=$weight
786 lowest_metric_v4=$metric
787 elif [ "$metric" -eq "$lowest_metric_v4" ]; then
788 total_weight_v4=$(($total_weight_v4+$weight))
789 total_weight=$total_weight_v4
790 else
791 return
792 fi
793 elif [ "$family" = "ipv6" ] && [ $NO_IPV6 -eq 0 ] && [ $is_offline -eq 0 ]; then
794 if [ "$metric" -lt "$lowest_metric_v6" ]; then
795 is_lowest=1
796 total_weight_v6=$weight
797 lowest_metric_v6=$metric
798 elif [ "$metric" -eq "$lowest_metric_v6" ]; then
799 total_weight_v6=$(($total_weight_v6+$weight))
800 total_weight=$total_weight_v6
801 else
802 return
803 fi
804 fi
805 if [ $is_lowest -eq 1 ]; then
806 mwan3_push_update -F "mwan3_policy_$policy"
807 mwan3_push_update -A "mwan3_policy_$policy" \
808 -m mark --mark 0x0/$MMX_MASK \
809 -m comment --comment \"$iface $weight $weight\" \
810 -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
811 elif [ $is_offline -eq 0 ]; then
812 probability=$(($weight*1000/$total_weight))
813 if [ "$probability" -lt 10 ]; then
814 probability="0.00$probability"
815 elif [ $probability -lt 100 ]; then
816 probability="0.0$probability"
817 elif [ $probability -lt 1000 ]; then
818 probability="0.$probability"
819 else
820 probability="1"
821 fi
822
823 mwan3_push_update -I "mwan3_policy_$policy" \
824 -m mark --mark 0x0/$MMX_MASK \
825 -m statistic \
826 --mode random \
827 --probability "$probability" \
828 -m comment --comment \"$iface $weight $total_weight\" \
829 -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
830 elif [ -n "$device" ]; then
831 echo "$current" | grep -q "^-A mwan3_policy_$policy.*--comment .* [0-9]* [0-9]*" ||
832 mwan3_push_update -I "mwan3_policy_$policy" \
833 -o "$device" \
834 -m mark --mark 0x0/$MMX_MASK \
835 -m comment --comment \"out $iface $device\" \
836 -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
837 fi
838 mwan3_push_update COMMIT
839 mwan3_push_update ""
840 error=$(echo "$update" | $IPTR 2>&1) || LOG error "set_policy ($1): $error"
841
842 }
843
844 mwan3_create_policies_iptables()
845 {
846 local last_resort lowest_metric_v4 lowest_metric_v6 total_weight_v4 total_weight_v6 policy IPT current update error
847
848 policy="$1"
849
850 config_get last_resort "$1" last_resort unreachable
851
852 if [ "$1" != "$(echo "$1" | cut -c1-15)" ]; then
853 LOG warn "Policy $1 exceeds max of 15 chars. Not setting policy" && return 0
854 fi
855
856 for IPT in "$IPT4" "$IPT6"; do
857 [ "$IPT" = "$IPT6" ] && [ $NO_IPV6 -ne 0 ] && continue
858 current="$($IPT -S)"
859 update="*mangle"
860 if [ -n "${current##*-N mwan3_policy_$1*}" ]; then
861 mwan3_push_update -N "mwan3_policy_$1"
862 fi
863
864 mwan3_push_update -F "mwan3_policy_$1"
865
866 case "$last_resort" in
867 blackhole)
868 mwan3_push_update -A "mwan3_policy_$1" \
869 -m mark --mark 0x0/$MMX_MASK \
870 -m comment --comment "blackhole" \
871 -j MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK
872 ;;
873 default)
874 mwan3_push_update -A "mwan3_policy_$1" \
875 -m mark --mark 0x0/$MMX_MASK \
876 -m comment --comment "default" \
877 -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
878 ;;
879 *)
880 mwan3_push_update -A "mwan3_policy_$1" \
881 -m mark --mark 0x0/$MMX_MASK \
882 -m comment --comment "unreachable" \
883 -j MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK
884 ;;
885 esac
886 mwan3_push_update COMMIT
887 mwan3_push_update ""
888 if [ "$IPT" = "$IPT4" ]; then
889 error=$(echo "$update" | $IPT4R 2>&1) || LOG error "create_policies_iptables ($1): $error"
890 else
891 error=$(echo "$update" | $IPT6R 2>&1) || LOG error "create_policies_iptables ($1): $error"
892 fi
893 done
894
895 lowest_metric_v4=$DEFAULT_LOWEST_METRIC
896 total_weight_v4=0
897
898 lowest_metric_v6=$DEFAULT_LOWEST_METRIC
899 total_weight_v6=0
900
901 config_list_foreach "$1" use_member mwan3_set_policy
902 }
903
904 mwan3_set_policies_iptables()
905 {
906 config_foreach mwan3_create_policies_iptables policy
907 }
908
909 mwan3_set_sticky_iptables()
910 {
911 local id iface
912 for iface in $(echo "$current" | grep "^-A $policy" | cut -s -d'"' -f2 | awk '{print $1}'); do
913 if [ "$iface" = "$1" ]; then
914
915 mwan3_get_iface_id id "$1"
916
917 [ -n "$id" ] || return 0
918 if [ -z "${current##*-N mwan3_iface_in_$1*}" ]; then
919 mwan3_push_update -I "mwan3_rule_$rule" \
920 -m mark --mark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK \
921 -m set ! --match-set "mwan3_sticky_$rule" src,src \
922 -j MARK --set-xmark 0x0/$MMX_MASK
923 mwan3_push_update -I "mwan3_rule_$rule" \
924 -m mark --mark 0/$MMX_MASK \
925 -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
926 fi
927 fi
928 done
929 }
930
931 mwan3_set_user_iptables_rule()
932 {
933 local ipset family proto policy src_ip src_port src_iface src_dev
934 local sticky dest_ip dest_port use_policy timeout policy
935 local global_logging rule_logging loglevel rule_policy rule ipv
936
937 rule="$1"
938 ipv="$2"
939 rule_policy=0
940 config_get sticky "$1" sticky 0
941 config_get timeout "$1" timeout 600
942 config_get ipset "$1" ipset
943 config_get proto "$1" proto all
944 config_get src_ip "$1" src_ip
945 config_get src_iface "$1" src_iface
946 config_get src_port "$1" src_port
947 config_get dest_ip "$1" dest_ip
948 config_get dest_port "$1" dest_port
949 config_get use_policy "$1" use_policy
950 config_get family "$1" family any
951 config_get rule_logging "$1" logging 0
952 config_get global_logging globals logging 0
953 config_get loglevel globals loglevel notice
954
955 if [ -n "$src_iface" ]; then
956 network_get_device src_dev "$src_iface"
957 if [ -z "$src_dev" ]; then
958 LOG notice "could not find device corresponding to src_iface $src_iface for rule $1"
959 return
960 fi
961 fi
962
963 [ -z "$dest_ip" ] && unset dest_ip
964 [ -z "$src_ip" ] && unset src_ip
965 [ -z "$ipset" ] && unset ipset
966 [ -z "$src_port" ] && unset src_port
967 [ -z "$dest_port" ] && unset dest_port
968 if [ "$proto" != 'tcp' ] && [ "$proto" != 'udp' ]; then
969 [ -n "$src_port" ] && {
970 LOG warn "src_port set to '$src_port' but proto set to '$proto' not tcp or udp. src_port will be ignored"
971 }
972
973 [ -n "$dest_port" ] && {
974 LOG warn "dest_port set to '$dest_port' but proto set to '$proto' not tcp or udp. dest_port will be ignored"
975 }
976 unset src_port
977 unset dest_port
978 fi
979
980 if [ "$1" != "$(echo "$1" | cut -c1-15)" ]; then
981 LOG warn "Rule $1 exceeds max of 15 chars. Not setting rule" && return 0
982 fi
983
984 if [ -n "$ipset" ]; then
985 ipset="-m set --match-set $ipset dst"
986 fi
987
988 if [ -z "$use_policy" ]; then
989 return
990 fi
991
992 if [ "$use_policy" = "default" ]; then
993 policy="MARK --set-xmark $MMX_DEFAULT/$MMX_MASK"
994 elif [ "$use_policy" = "unreachable" ]; then
995 policy="MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK"
996 elif [ "$use_policy" = "blackhole" ]; then
997 policy="MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK"
998 else
999 rule_policy=1
1000 policy="mwan3_policy_$use_policy"
1001 if [ "$sticky" -eq 1 ]; then
1002 $IPS -! create "mwan3_sticky_v4_$rule" \
1003 hash:ip,mark markmask "$MMX_MASK" \
1004 timeout "$timeout"
1005 [ $NO_IPV6 -eq 0 ] &&
1006 $IPS -! create "mwan3_sticky_v6_$rule" \
1007 hash:ip,mark markmask "$MMX_MASK" \
1008 timeout "$timeout" family inet6
1009 $IPS -! create "mwan3_sticky_$rule" list:set
1010 $IPS -! add "mwan3_sticky_$rule" "mwan3_sticky_v4_$rule"
1011 [ $NO_IPV6 -eq 0 ] &&
1012 $IPS -! add "mwan3_sticky_$rule" "mwan3_sticky_v6_$rule"
1013 fi
1014 fi
1015
1016 [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && return
1017 [ "$family" = "ipv4" ] && [ "$ipv" = "ipv6" ] && return
1018 [ "$family" = "ipv6" ] && [ "$ipv" = "ipv4" ] && return
1019
1020 if [ $rule_policy -eq 1 ] && [ -n "${current##*-N $policy*}" ]; then
1021 mwan3_push_update -N "$policy"
1022 fi
1023
1024 if [ $rule_policy -eq 1 ] && [ "$sticky" -eq 1 ]; then
1025 if [ -n "${current##*-N mwan3_rule_$1*}" ]; then
1026 mwan3_push_update -N "mwan3_rule_$1"
1027 fi
1028
1029 mwan3_push_update -F "mwan3_rule_$1"
1030 config_foreach mwan3_set_sticky_iptables interface $ipv
1031
1032
1033 mwan3_push_update -A "mwan3_rule_$1" \
1034 -m mark --mark 0/$MMX_MASK \
1035 -j "$policy"
1036 mwan3_push_update -A "mwan3_rule_$1" \
1037 -m mark ! --mark 0xfc00/0xfc00 \
1038 -j SET --del-set "mwan3_sticky_$rule" src,src
1039 mwan3_push_update -A "mwan3_rule_$1" \
1040 -m mark ! --mark 0xfc00/0xfc00 \
1041 -j SET --add-set "mwan3_sticky_$rule" src,src
1042 policy="mwan3_rule_$1"
1043 fi
1044 if [ "$global_logging" = "1" ] && [ "$rule_logging" = "1" ]; then
1045 mwan3_push_update -A mwan3_rules \
1046 -p "$proto" \
1047 ${src_ip:+-s} $src_ip \
1048 ${src_dev:+-i} $src_dev \
1049 ${dest_ip:+-d} $dest_ip \
1050 $ipset \
1051 ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \
1052 ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \
1053 -m mark --mark 0/$MMX_MASK \
1054 -m comment --comment "$1" \
1055 -j LOG --log-level "$loglevel" --log-prefix "MWAN3($1)"
1056 fi
1057
1058 mwan3_push_update -A mwan3_rules \
1059 -p "$proto" \
1060 ${src_ip:+-s} $src_ip \
1061 ${src_dev:+-i} $src_dev \
1062 ${dest_ip:+-d} $dest_ip \
1063 $ipset \
1064 ${src_port:+-m} ${src_port:+multiport} ${src_port:+--sports} $src_port \
1065 ${dest_port:+-m} ${dest_port:+multiport} ${dest_port:+--dports} $dest_port \
1066 -m mark --mark 0/$MMX_MASK \
1067 -j $policy
1068
1069 }
1070
1071 mwan3_set_user_iface_rules()
1072 {
1073 local current iface update family error device is_src_iface
1074 iface=$1
1075 device=$2
1076
1077 if [ -z "$device" ]; then
1078 LOG notice "set_user_iface_rules: could not find device corresponding to iface $iface"
1079 return
1080 fi
1081
1082 config_get family "$iface" family ipv4
1083
1084 if [ "$family" = "ipv4" ]; then
1085 IPT="$IPT4"
1086 IPTR="$IPT4R"
1087 elif [ "$family" = "ipv6" ]; then
1088 IPT="$IPT6"
1089 IPTR="$IPT6R"
1090 fi
1091 $IPT -S | grep -q "^-A mwan3_rules.*-i $device" && return
1092
1093 is_src_iface=0
1094
1095 iface_rule()
1096 {
1097 local src_iface
1098 config_get src_iface "$1" src_iface
1099 [ "$src_iface" = "$iface" ] && is_src_iface=1
1100 }
1101 config_foreach iface_rule rule
1102 [ $is_src_iface -eq 1 ] && mwan3_set_user_rules
1103 }
1104
1105 mwan3_set_user_rules()
1106 {
1107 local IPT IPTR ipv
1108 local current update error
1109
1110 for ipv in ipv4 ipv6; do
1111 if [ "$ipv" = "ipv4" ]; then
1112 IPT="$IPT4"
1113 IPTR="$IPT4R"
1114 elif [ "$ipv" = "ipv6" ]; then
1115 IPT="$IPT6"
1116 IPTR="$IPT6R"
1117 fi
1118 [ "$ipv" = "ipv6" ] && [ $NO_IPV6 -ne 0 ] && continue
1119 update="*mangle"
1120 current="$($IPT -S)"
1121
1122
1123 if [ -n "${current##*-N mwan3_rules*}" ]; then
1124 mwan3_push_update -N "mwan3_rules"
1125 fi
1126
1127 mwan3_push_update -F mwan3_rules
1128
1129 config_foreach mwan3_set_user_iptables_rule rule "$ipv"
1130
1131 mwan3_push_update COMMIT
1132 mwan3_push_update ""
1133 error=$(echo "$update" | $IPTR 2>&1) || LOG error "set_user_rules: $error"
1134 done
1135
1136
1137 }
1138
1139 mwan3_set_iface_hotplug_state() {
1140 local iface=$1
1141 local state=$2
1142
1143 echo "$state" > "$MWAN3_STATUS_DIR/iface_state/$iface"
1144 }
1145
1146 mwan3_get_iface_hotplug_state() {
1147 local iface=$1
1148
1149 cat "$MWAN3_STATUS_DIR/iface_state/$iface" 2>/dev/null || echo "offline"
1150 }
1151
1152 mwan3_report_iface_status()
1153 {
1154 local device result track_ips tracking IP IPT
1155
1156 mwan3_get_iface_id id "$1"
1157 network_get_device device "$1"
1158 config_get enabled "$1" enabled 0
1159 config_get family "$1" family ipv4
1160
1161 if [ "$family" = "ipv4" ]; then
1162 IP="$IP4"
1163 IPT="$IPT4"
1164 fi
1165
1166 if [ "$family" = "ipv6" ]; then
1167 IP="$IP6"
1168 IPT="$IPT6"
1169 fi
1170
1171 if [ -z "$id" ] || [ -z "$device" ]; then
1172 result="offline"
1173 elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] && \
1174 [ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] && \
1175 [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] && \
1176 [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
1177 json_init
1178 json_add_string section interfaces
1179 json_add_string interface "$1"
1180 json_load "$(ubus call mwan3 status "$(json_dump)")"
1181 json_select "interfaces"
1182 json_select "$1"
1183 json_get_vars online uptime
1184 json_select ..
1185 json_select ..
1186 online="$(printf '%02dh:%02dm:%02ds\n' $(($online/3600)) $(($online%3600/60)) $(($online%60)))"
1187 uptime="$(printf '%02dh:%02dm:%02ds\n' $(($uptime/3600)) $(($uptime%3600/60)) $(($uptime%60)))"
1188 result="$(mwan3_get_iface_hotplug_state $1) $online, uptime $uptime"
1189 elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" ] || \
1190 [ -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" ] || \
1191 [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" ] || \
1192 [ -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
1193 result="error"
1194 elif [ "$enabled" = "1" ]; then
1195 result="offline"
1196 else
1197 result="disabled"
1198 fi
1199
1200 mwan3_list_track_ips()
1201 {
1202 track_ips="$1 $track_ips"
1203 }
1204 config_list_foreach "$1" track_ip mwan3_list_track_ips
1205
1206 if [ -n "$track_ips" ]; then
1207 if [ -n "$(pgrep -f "mwan3track $1 $device")" ]; then
1208 tracking="active"
1209 else
1210 tracking="down"
1211 fi
1212 else
1213 tracking="not enabled"
1214 fi
1215
1216 echo " interface $1 is $result and tracking is $tracking"
1217 }
1218
1219 mwan3_report_policies()
1220 {
1221 local ipt="$1"
1222 local policy="$2"
1223
1224 local percent total_weight weight iface
1225
1226 total_weight=$($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
1227
1228 if [ ! -z "${total_weight##*[!0-9]*}" ]; then
1229 for iface in $($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '{print $1}'); do
1230 weight=$($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
1231 percent=$(($weight*100/$total_weight))
1232 echo " $iface ($percent%)"
1233 done
1234 else
1235 echo " $($ipt -S "$policy" | grep -v '.*--comment "out .*" .*$' | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
1236 fi
1237 }
1238
1239 mwan3_report_policies_v4()
1240 {
1241 local policy
1242
1243 for policy in $($IPT4 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
1244 echo "$policy:" | sed 's/mwan3_policy_//'
1245 mwan3_report_policies "$IPT4" "$policy"
1246 done
1247 }
1248
1249 mwan3_report_policies_v6()
1250 {
1251 local policy
1252
1253 for policy in $($IPT6 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
1254 echo "$policy:" | sed 's/mwan3_policy_//'
1255 mwan3_report_policies "$IPT6" "$policy"
1256 done
1257 }
1258
1259 mwan3_report_connected_v4()
1260 {
1261 if [ -n "$($IPT4 -S mwan3_connected 2> /dev/null)" ]; then
1262 $IPS -o save list mwan3_connected_v4 | grep add | cut -d " " -f 3
1263 fi
1264 }
1265
1266 mwan3_report_connected_v6()
1267 {
1268 if [ -n "$($IPT6 -S mwan3_connected 2> /dev/null)" ]; then
1269 $IPS -o save list mwan3_connected_v6 | grep add | cut -d " " -f 3
1270 fi
1271 }
1272
1273 mwan3_report_rules_v4()
1274 {
1275 if [ -n "$($IPT4 -S mwan3_rules 2> /dev/null)" ]; then
1276 $IPT4 -L mwan3_rules -n -v 2> /dev/null | tail -n+3 | sed 's/mark.*//' | sed 's/mwan3_policy_/- /' | sed 's/mwan3_rule_/S /'
1277 fi
1278 }
1279
1280 mwan3_report_rules_v6()
1281 {
1282 if [ -n "$($IPT6 -S mwan3_rules 2> /dev/null)" ]; then
1283 $IPT6 -L mwan3_rules -n -v 2> /dev/null | tail -n+3 | sed 's/mark.*//' | sed 's/mwan3_policy_/- /' | sed 's/mwan3_rule_/S /'
1284 fi
1285 }
1286
1287 mwan3_flush_conntrack()
1288 {
1289 local interface="$1"
1290 local action="$2"
1291
1292 handle_flush() {
1293 local flush_conntrack="$1"
1294 local action="$2"
1295
1296 if [ "$action" = "$flush_conntrack" ]; then
1297 echo f > ${CONNTRACK_FILE}
1298 LOG info "Connection tracking flushed for interface '$interface' on action '$action'"
1299 fi
1300 }
1301
1302 if [ -e "$CONNTRACK_FILE" ]; then
1303 config_list_foreach "$interface" flush_conntrack handle_flush "$action"
1304 fi
1305 }
1306
1307 mwan3_track_clean()
1308 {
1309 rm -rf "$MWAN3_STATUS_DIR/${1}" &> /dev/null
1310 rmdir --ignore-fail-on-non-empty "$MWAN3_STATUS_DIR"
1311 }