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