6 IPT4
="iptables -t mangle -w"
7 IPT6
="ip6tables -t mangle -w"
8 LOG
="logger -t mwan3[$$] -p"
9 CONNTRACK_FILE
="/proc/net/nf_conntrack"
11 # mwan3's MARKing mask (at least 3 bits should be set)
14 # counts how many bits are set to 1
15 # n&(n-1) clears the lowest bit set to 1
16 mwan3_count_one_bits
()
21 while [ "$n" -gt "0" ]; do
28 # maps the 1st parameter so it only uses the bits allowed by the bitmask (2nd parameter)
29 # which means spreading the bits of the 1st parameter to only use the bits that are set to 1 in the 2nd parameter
30 # 0 0 0 0 0 1 0 1 (0x05) 1st parameter
31 # 1 0 1 0 1 0 1 0 (0xAA) 2nd parameter
35 local bit_msk bit_val result
38 for bit_msk
in $
(seq 0 31); do
39 if [ $
((($2>>bit_msk
)&1)) = "1" ]; then
40 if [ $
((($1>>bit_val
)&1)) = "1" ]; then
41 result
=$
((result|
(1<<bit_msk)))
43 bit_val=$((bit_val+1))
50 MM_BIT_CNT=$(mwan3_count_one_bits MMX_MASK)
51 MM_DEFAULT=$(((1<<MM_BIT_CNT)-1))
52 MM_BLACKHOLE=$(($MM_DEFAULT-2))
53 MM_UNREACHABLE=$(($MM_DEFAULT-1))
55 # MMX_DEFAULT should equal MMX_MASK
56 MMX_DEFAULT=$(mwan3_id2mask MM_DEFAULT MMX_MASK)
57 MMX_BLACKHOLE=$(mwan3_id2mask MM_BLACKHOLE MMX_MASK)
58 MMX_UNREACHABLE=$(mwan3_id2mask MM_UNREACHABLE MMX_MASK)
61 lock /var/run/mwan3.lock
65 lock -u /var/run/mwan3.lock
70 local _tmp _iface _iface_count
77 [ "$1" == "$_iface" ] && _tmp=$_iface_count
79 config_foreach mwan3_get_id interface
83 mwan3_set_connected_iptables()
85 local connected_network_v4 connected_network_v6
87 $IPS -! create mwan3_connected_v4 hash:net
88 $IPS create mwan3_connected_v4_temp hash:net
90 for connected_network_v4 in $($IP4 route | awk '{print $1}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
91 $IPS -! add mwan3_connected_v4_temp $connected_network_v4
94 for connected_network_v4 in $($IP4 route list table 0 | awk '{print $2}' | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
95 $IPS -! add mwan3_connected_v4_temp $connected_network_v4
98 $IPS add mwan3_connected_v4_temp 224.0.0.0/3
100 $IPS swap mwan3_connected_v4_temp mwan3_connected_v4
101 $IPS destroy mwan3_connected_v4_temp
103 $IPS -! create mwan3_connected_v6 hash:net family inet6
104 $IPS create mwan3_connected_v6_temp hash:net family inet6
106 for connected_network_v6 in $($IP6 route | awk '{print $1}' | egrep '([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(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])|([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])'); do
107 $IPS -! add mwan3_connected_v6_temp $connected_network_v6
110 $IPS swap mwan3_connected_v6_temp mwan3_connected_v6
111 $IPS destroy mwan3_connected_v6_temp
113 $IPS -! create mwan3_connected list:set
114 $IPS -! add mwan3_connected mwan3_connected_v4
115 $IPS -! add mwan3_connected mwan3_connected_v6
118 mwan3_set_general_rules()
122 for IP in "$IP4" "$IP6"; do
124 RULE_NO=$(($MM_BLACKHOLE+2000))
125 if [ -z "$($IP rule list | awk -v var="$RULE_NO:" '$1 == var')" ]; then
126 $IP rule add pref $RULE_NO fwmark $MMX_BLACKHOLE/$MMX_MASK blackhole
129 RULE_NO=$(($MM_UNREACHABLE+2000))
130 if [ -z "$($IP rule list | awk -v var="$RULE_NO:" '$1 == var')" ]; then
131 $IP rule add pref $RULE_NO fwmark $MMX_UNREACHABLE/$MMX_MASK unreachable
136 mwan3_set_general_iptables()
140 for IPT in "$IPT4" "$IPT6"; do
142 if ! $IPT -S mwan3_ifaces_in &> /dev/null; then
143 $IPT -N mwan3_ifaces_in
146 if ! $IPT -S mwan3_connected &> /dev/null; then
147 $IPT -N mwan3_connected
148 $IPS -! create mwan3_connected list:set
149 $IPT -A mwan3_connected -m set --match-set mwan3_connected dst -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
152 if ! $IPT -S mwan3_ifaces_out &> /dev/null; then
153 $IPT -N mwan3_ifaces_out
156 if ! $IPT -S mwan3_rules &> /dev/null; then
160 if ! $IPT -S mwan3_hook &> /dev/null; then
162 $IPT -A mwan3_hook -j CONNMARK --restore-mark --nfmask $MMX_MASK --ctmask $MMX_MASK
163 $IPT -A mwan3_hook -m mark --mark 0x0/$MMX_MASK -j mwan3_ifaces_in
164 $IPT -A mwan3_hook -m mark --mark 0x0/$MMX_MASK -j mwan3_connected
165 $IPT -A mwan3_hook -m mark --mark 0x0/$MMX_MASK -j mwan3_ifaces_out
166 $IPT -A mwan3_hook -m mark --mark 0x0/$MMX_MASK -j mwan3_rules
167 $IPT -A mwan3_hook -j CONNMARK --save-mark --nfmask $MMX_MASK --ctmask $MMX_MASK
168 $IPT -A mwan3_hook -m mark ! --mark $MMX_DEFAULT/$MMX_MASK -j mwan3_connected
171 if ! $IPT -S PREROUTING | grep mwan3_hook &> /dev/null; then
172 $IPT -A PREROUTING -j mwan3_hook
175 if ! $IPT -S OUTPUT | grep mwan3_hook &> /dev/null; then
176 $IPT -A OUTPUT -j mwan3_hook
181 mwan3_create_iface_iptables()
183 local id family src_ip src_ipv6
185 config_get family $1 family ipv4
186 mwan3_get_iface_id id $1
188 [ -n "$id" ] || return 0
190 if [ "$family" == "ipv4" ]; then
192 ubus call network.interface.${1}_4 status &>/dev/null
193 if [ "$?" -eq "0" ]; then
194 network_get_ipaddr src_ip ${1}_4
196 network_get_ipaddr src_ip $1
199 $IPS -! create mwan3_connected list:set
201 if ! $IPT4 -S mwan3_ifaces_in &> /dev/null; then
202 $IPT4 -N mwan3_ifaces_in
205 if ! $IPT4 -S mwan3_ifaces_out &> /dev/null; then
206 $IPT4 -N mwan3_ifaces_out
209 if ! $IPT4 -S mwan3_iface_in_$1 &> /dev/null; then
210 $IPT4 -N mwan3_iface_in_$1
213 if ! $IPT4 -S mwan3_iface_out_$1 &> /dev/null; then
214 $IPT4 -N mwan3_iface_out_$1
217 $IPT4 -F mwan3_iface_in_$1
218 $IPT4 -A mwan3_iface_in_$1 -i $2 -m set --match-set mwan3_connected src -m mark --mark 0x0/$MMX_MASK -m comment --comment "default" -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
219 $IPT4 -A mwan3_iface_in_$1 -i $2 -m mark --mark 0x0/$MMX_MASK -m comment --comment "$1" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
221 $IPT4 -D mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1 &> /dev/null
222 $IPT4 -A mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1
224 $IPT4 -F mwan3_iface_out_$1
225 $IPT4 -A mwan3_iface_out_$1 -s $src_ip -m mark --mark 0x0/$MMX_MASK -m comment --comment "$1" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
227 $IPT4 -D mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1 &> /dev/null
228 $IPT4 -A mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1
231 if [ "$family" == "ipv6" ]; then
233 ubus call network.interface.${1}_6 status &>/dev/null
234 if [ "$?" -eq "0" ]; then
235 network_get_ipaddr6 src_ipv6 ${1}_6
237 network_get_ipaddr6 src_ipv6 $1
240 $IPS -! create mwan3_connected_v6 hash:net family inet6
242 if ! $IPT6 -S mwan3_ifaces_in &> /dev/null; then
243 $IPT6 -N mwan3_ifaces_in
246 if ! $IPT6 -S mwan3_ifaces_out &> /dev/null; then
247 $IPT6 -N mwan3_ifaces_out
250 if ! $IPT6 -S mwan3_iface_in_$1 &> /dev/null; then
251 $IPT6 -N mwan3_iface_in_$1
254 if ! $IPT6 -S mwan3_iface_out_$1 &> /dev/null; then
255 $IPT6 -N mwan3_iface_out_$1
258 $IPT6 -F mwan3_iface_in_$1
259 $IPT6 -A mwan3_iface_in_$1 -i $2 -m set --match-set mwan3_connected_v6 src -m mark --mark 0x0/$MMX_MASK -m comment --comment "default" -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
260 $IPT6 -A mwan3_iface_in_$1 -i $2 -m mark --mark 0x0/$MMX_MASK -m comment --comment "$1" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
262 $IPT6 -D mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1 &> /dev/null
263 $IPT6 -A mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1
265 $IPT6 -F mwan3_iface_out_$1
266 $IPT6 -A mwan3_iface_out_$1 -s $src_ipv6 -m mark --mark 0x0/$MMX_MASK -m comment --comment "$1" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
268 $IPT6 -D mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1 &> /dev/null
269 $IPT6 -A mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1
273 mwan3_delete_iface_iptables()
275 config_get family $1 family ipv4
277 if [ "$family" == "ipv4" ]; then
279 $IPT4 -D mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1 &> /dev/null
280 $IPT4 -F mwan3_iface_in_$1 &> /dev/null
281 $IPT4 -X mwan3_iface_in_$1 &> /dev/null
283 $IPT4 -D mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1 &> /dev/null
284 $IPT4 -F mwan3_iface_out_$1 &> /dev/null
285 $IPT4 -X mwan3_iface_out_$1 &> /dev/null
288 if [ "$family" == "ipv6" ]; then
290 $IPT6 -D mwan3_ifaces_in -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_in_$1 &> /dev/null
291 $IPT6 -F mwan3_iface_in_$1 &> /dev/null
292 $IPT6 -X mwan3_iface_in_$1 &> /dev/null
294 $IPT6 -D mwan3_ifaces_out -m mark --mark 0x0/$MMX_MASK -j mwan3_iface_out_$1 &> /dev/null
295 $IPT6 -F mwan3_iface_out_$1 &> /dev/null
296 $IPT6 -X mwan3_iface_out_$1 &> /dev/null
300 mwan3_create_iface_route()
304 config_get family $1 family ipv4
305 mwan3_get_iface_id id $1
307 [ -n "$id" ] || return 0
309 if [ "$family" == "ipv4" ]; then
310 ubus call network.interface.${1}_4 status &>/dev/null
311 if [ "$?" -eq "0" ]; then
312 network_get_gateway route_args ${1}_4
314 network_get_gateway route_args $1
317 route_args="via $route_args dev $2"
319 $IP4 route flush table $id
320 $IP4 route add table $id default $route_args
323 if [ "$family" == "ipv6" ]; then
325 ubus call network.interface.${1}_6 status &>/dev/null
326 if [ "$?" -eq "0" ]; then
327 network_get_gateway6 route_args ${1}_6
329 network_get_gateway6 route_args $1
332 route_args="via $route_args dev $2"
334 $IP6 route flush table $id
335 $IP6 route add table $id default $route_args
339 mwan3_delete_iface_route()
343 config_get family $1 family ipv4
344 mwan3_get_iface_id id $1
346 [ -n "$id" ] || return 0
348 if [ "$family" == "ipv4" ]; then
349 $IP4 route flush table $id
352 if [ "$family" == "ipv6" ]; then
353 $IP6 route flush table $id
357 mwan3_create_iface_rules()
361 config_get family $1 family ipv4
362 mwan3_get_iface_id id $1
364 [ -n "$id" ] || return 0
366 if [ "$family" == "ipv4" ]; then
368 while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
369 $IP4 rule del pref $(($id+1000))
372 while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
373 $IP4 rule del pref $(($id+2000))
376 $IP4 rule add pref $(($id+1000)) iif $2 lookup main
377 $IP4 rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup $id
380 if [ "$family" == "ipv6" ]; then
382 while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
383 $IP6 rule del pref $(($id+1000))
386 while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
387 $IP6 rule del pref $(($id+2000))
390 $IP6 rule add pref $(($id+1000)) iif $2 lookup main
391 $IP6 rule add pref $(($id+2000)) fwmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK lookup $id
395 mwan3_delete_iface_rules()
399 config_get family $1 family ipv4
400 mwan3_get_iface_id id $1
402 [ -n "$id" ] || return 0
404 if [ "$family" == "ipv4" ]; then
406 while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
407 $IP4 rule del pref $(($id+1000))
410 while [ -n "$($IP4 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
411 $IP4 rule del pref $(($id+2000))
415 if [ "$family" == "ipv6" ]; then
417 while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+1000)):'"')" ]; do
418 $IP6 rule del pref $(($id+1000))
421 while [ -n "$($IP6 rule list | awk '$1 == "'$(($id+2000)):'"')" ]; do
422 $IP6 rule del pref $(($id+2000))
427 mwan3_delete_iface_ipset_entries()
429 local id setname entry
431 mwan3_get_iface_id id $1
433 [ -n "$id" ] || return 0
435 for setname in $(ipset -n list | grep ^mwan3_sticky_); do
436 for entry in $(ipset list $setname | grep "$(echo $(mwan3_id2mask id MMX_MASK) | awk '{ printf "0x%08x", $1; }')" | cut -d ' ' -f 1); do
437 $IPS del $setname $entry
444 local track_ip track_ips
446 mwan3_list_track_ips()
448 track_ips="$1 $track_ips"
450 config_list_foreach $1 track_ip mwan3_list_track_ips
452 kill $(pgrep -f "mwan3track $1 $2") &> /dev/null
453 if [ -n "$track_ips" ]; then
454 [ -x /usr/sbin/mwan3track ] && /usr/sbin/mwan3track "$1" "$2" "$3" $track_ips &
462 pid="$(pgrep -f "mwan3track $1 $2")"
463 if [ "${pid}" != "" ]; then
466 $LOG warn "Unable to send signal USR1 to mwan3track on interface $1 with pid ${pid}"
472 local iface_count id iface family metric probability weight
474 config_get iface $1 interface
475 config_get metric $1 metric 1
476 config_get weight $1 weight 1
478 [ -n "$iface" ] || return 0
480 mwan3_get_iface_id id $iface
482 [ -n "$id" ] || return 0
484 config_get family $iface family ipv4
486 if [ "$family" == "ipv4" ]; then
488 if [ -n "$($IP4 route list table $id)" ]; then
489 if [ "$metric" -lt "$lowest_metric_v4" ]; then
491 total_weight_v4=$weight
492 $IPT4 -F mwan3_policy_$policy
493 $IPT4 -A mwan3_policy_$policy -m mark --mark 0x0/$MMX_MASK -m comment --comment "$iface $weight $weight" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
495 lowest_metric_v4=$metric
497 elif [ "$metric" -eq "$lowest_metric_v4" ]; then
499 total_weight_v4=$(($total_weight_v4+$weight))
500 probability=$(($weight*1000/$total_weight_v4))
502 if [ "$probability" -lt 10 ]; then
503 probability="0.00$probability"
504 elif [ $probability -lt 100 ]; then
505 probability="0.0$probability"
506 elif [ $probability -lt 1000 ]; then
507 probability="0.$probability"
512 probability="-m statistic --mode random --probability $probability"
514 $IPT4 -I mwan3_policy_$policy -m mark --mark 0x0/$MMX_MASK $probability -m comment --comment "$iface $weight $total_weight_v4" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
519 if [ "$family" == "ipv6" ]; then
521 if [ -n "$($IP6 route list table $id)" ]; then
522 if [ "$metric" -lt "$lowest_metric_v6" ]; then
524 total_weight_v6=$weight
525 $IPT6 -F mwan3_policy_$policy
526 $IPT6 -A mwan3_policy_$policy -m mark --mark 0x0/$MMX_MASK -m comment --comment "$iface $weight $weight" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
528 lowest_metric_v6=$metric
530 elif [ "$metric" -eq "$lowest_metric_v6" ]; then
532 total_weight_v6=$(($total_weight_v6+$weight))
533 probability=$(($weight*1000/$total_weight_v6))
535 if [ "$probability" -lt 10 ]; then
536 probability="0.00$probability"
537 elif [ $probability -lt 100 ]; then
538 probability="0.0$probability"
539 elif [ $probability -lt 1000 ]; then
540 probability="0.$probability"
545 probability="-m statistic --mode random --probability $probability"
547 $IPT6 -I mwan3_policy_$policy -m mark --mark 0x0/$MMX_MASK $probability -m comment --comment "$iface $weight $total_weight_v6" -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
553 mwan3_create_policies_iptables()
555 local last_resort lowest_metric_v4 lowest_metric_v6 total_weight_v4 total_weight_v6 policy IPT
559 config_get last_resort $1 last_resort unreachable
561 if [ "$1" != $(echo "$1" | cut -c1-15) ]; then
562 $LOG warn "Policy $1 exceeds max of 15 chars. Not setting policy" && return 0
565 for IPT in "$IPT4" "$IPT6"; do
567 if ! $IPT -S mwan3_policy_$1 &> /dev/null; then
568 $IPT -N mwan3_policy_$1
571 $IPT -F mwan3_policy_$1
573 case "$last_resort" in
575 $IPT -A mwan3_policy_$1 -m mark --mark 0x0/$MMX_MASK -m comment --comment "blackhole" -j MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK
578 $IPT -A mwan3_policy_$1 -m mark --mark 0x0/$MMX_MASK -m comment --comment "default" -j MARK --set-xmark $MMX_DEFAULT/$MMX_MASK
581 $IPT -A mwan3_policy_$1 -m mark --mark 0x0/$MMX_MASK -m comment --comment "unreachable" -j MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK
592 config_list_foreach $1 use_member mwan3_set_policy
595 mwan3_set_policies_iptables()
597 config_foreach mwan3_create_policies_iptables policy
600 mwan3_set_sticky_iptables()
604 for iface in $($IPT4 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do
606 if [ "$iface" == "$1" ]; then
608 mwan3_get_iface_id id $1
610 [ -n "$id" ] || return 0
612 for IPT in "$IPT4" "$IPT6"; do
613 if [ -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -a -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" ]; then
614 $IPT -I mwan3_rule_$rule -m mark --mark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK -m set ! --match-set mwan3_sticky_$rule src,src -j MARK --set-xmark 0x0/$MMX_MASK
615 $IPT -I mwan3_rule_$rule -m mark --mark 0/$MMX_MASK -j MARK --set-xmark $(mwan3_id2mask id MMX_MASK)/$MMX_MASK
622 mwan3_set_user_iptables_rule()
624 local ipset family proto policy src_ip src_port sticky dest_ip dest_port use_policy timeout rule policy IPT
628 config_get sticky $1 sticky 0
629 config_get timeout $1 timeout 600
630 config_get ipset $1 ipset
631 config_get proto $1 proto all
632 config_get src_ip $1 src_ip 0.0.0.0/0
633 config_get src_port $1 src_port 0:65535
634 config_get dest_ip $1 dest_ip 0.0.0.0/0
635 config_get dest_port $1 dest_port 0:65535
636 config_get use_policy $1 use_policy
637 config_get family $1 family any
639 if [ "$1" != $(echo "$1" | cut -c1-15) ]; then
640 $LOG warn "Rule $1 exceeds max of 15 chars. Not setting rule" && return 0
643 if [ -n "$ipset" ]; then
644 ipset="-m set --match-set $ipset dst"
647 if [ -n "$use_policy" ]; then
648 if [ "$use_policy" == "default" ]; then
649 policy="MARK --set-xmark $MMX_DEFAULT/$MMX_MASK"
650 elif [ "$use_policy" == "unreachable" ]; then
651 policy="MARK --set-xmark $MMX_UNREACHABLE/$MMX_MASK"
652 elif [ "$use_policy" == "blackhole" ]; then
653 policy="MARK --set-xmark $MMX_BLACKHOLE/$MMX_MASK"
655 if [ "$sticky" -eq 1 ]; then
657 policy="mwan3_policy_$use_policy"
659 for IPT in "$IPT4" "$IPT6"; do
660 if ! $IPT -S $policy &> /dev/null; then
664 if ! $IPT -S mwan3_rule_$1 &> /dev/null; then
665 $IPT -N mwan3_rule_$1
668 $IPT -F mwan3_rule_$1
671 $IPS -! create mwan3_sticky_v4_$rule hash:ip,mark markmask $MMX_MASK timeout $timeout
672 $IPS -! create mwan3_sticky_v6_$rule hash:ip,mark markmask $MMX_MASK timeout $timeout family inet6
673 $IPS -! create mwan3_sticky_$rule list:set
674 $IPS -! add mwan3_sticky_$rule mwan3_sticky_v4_$rule
675 $IPS -! add mwan3_sticky_$rule mwan3_sticky_v6_$rule
677 config_foreach mwan3_set_sticky_iptables interface
679 for IPT in "$IPT4" "$IPT6"; do
680 $IPT -A mwan3_rule_$1 -m mark --mark 0/$MMX_MASK -j $policy
681 $IPT -A mwan3_rule_$1 -m mark ! --mark 0xfc00/0xfc00 -j SET --del-set mwan3_sticky_$rule src,src
682 $IPT -A mwan3_rule_$1 -m mark ! --mark 0xfc00/0xfc00 -j SET --add-set mwan3_sticky_$rule src,src
685 policy="mwan3_rule_$1"
687 policy="mwan3_policy_$use_policy"
689 for IPT in "$IPT4" "$IPT6"; do
690 if ! $IPT -S $policy &> /dev/null; then
698 if [ "$family" == "any" ]; then
700 for IPT in "$IPT4" "$IPT6"; do
703 $IPT -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m multiport --sports $src_port -m multiport --dports $dest_port -m mark --mark 0/$MMX_MASK -m comment --comment "$1" -j $policy &> /dev/null
706 $IPT -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m mark --mark 0/$MMX_MASK -m comment --comment "$1" -j $policy &> /dev/null
711 elif [ "$family" == "ipv4" ]; then
715 $IPT4 -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m multiport --sports $src_port -m multiport --dports $dest_port -m mark --mark 0/$MMX_MASK -m comment --comment "$1" -j $policy &> /dev/null
718 $IPT4 -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m mark --mark 0/$MMX_MASK -m comment --comment "$1" -j $policy &> /dev/null
722 elif [ "$family" == "ipv6" ]; then
726 $IPT6 -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m multiport --sports $src_port -m multiport --dports $dest_port -m mark --mark 0/$MMX_MASK -m comment --comment "$1" -j $policy &> /dev/null
729 $IPT6 -A mwan3_rules -p $proto -s $src_ip -d $dest_ip $ipset -m mark --mark 0/$MMX_MASK -m comment --comment "$1" -j $policy &> /dev/null
736 mwan3_set_user_rules()
740 for IPT in "$IPT4" "$IPT6"; do
742 if ! $IPT -S mwan3_rules &> /dev/null; then
749 config_foreach mwan3_set_user_iptables_rule rule
752 mwan3_report_iface_status()
754 local device result track_ips tracking IP IPT
756 mwan3_get_iface_id id $1
757 network_get_device device $1
758 config_get enabled "$1" enabled 0
759 config_get family "$1" family ipv4
761 if [ "$family" == "ipv4" ]; then
766 if [ "$family" == "ipv6" ]; then
771 if [ -z "$id" -o -z "$device" ]; then
773 elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')"i -a -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" -a -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -a -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" -a -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
775 elif [ -n "$($IP rule | awk '$1 == "'$(($id+1000)):'"')" -o -n "$($IP rule | awk '$1 == "'$(($id+2000)):'"')" -o -n "$($IPT -S mwan3_iface_in_$1 2> /dev/null)" -o -n "$($IPT -S mwan3_iface_out_$1 2> /dev/null)" -o -n "$($IP route list table $id default dev $device 2> /dev/null)" ]; then
778 if [ "$enabled" == "1" ]; then
785 mwan3_list_track_ips()
787 track_ips="$1 $track_ips"
789 config_list_foreach $1 track_ip mwan3_list_track_ips
791 if [ -n "$track_ips" ]; then
792 if [ -n "$(pgrep -f "mwan3track $1 $device")" ]; then
798 tracking="not enabled"
801 echo " interface $1 is $result and tracking is $tracking"
804 mwan3_report_policies_v4()
806 local percent policy share total_weight weight iface
808 for policy in $($IPT4 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
809 echo "$policy:" | sed 's/mwan3_policy_//'
811 [ -n "$total_weight" ] || total_weight=$($IPT4 -S $policy | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
813 if [ ! -z "${total_weight##*[!0-9]*}" ]; then
814 for iface in $($IPT4 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do
815 weight=$($IPT4 -S $policy | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
816 percent=$(($weight*100/$total_weight))
817 echo " $iface ($percent%)"
820 echo " $($IPT4 -S $policy | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
829 mwan3_report_policies_v6()
831 local percent policy share total_weight weight iface
833 for policy in $($IPT6 -S | awk '{print $2}' | grep mwan3_policy_ | sort -u); do
834 echo "$policy:" | sed 's/mwan3_policy_//'
836 [ -n "$total_weight" ] || total_weight=$($IPT6 -S $policy | cut -s -d'"' -f2 | head -1 | awk '{print $3}')
838 if [ ! -z "${total_weight##*[!0-9]*}" ]; then
839 for iface in $($IPT6 -S $policy | cut -s -d'"' -f2 | awk '{print $1}'); do
840 weight=$($IPT6 -S $policy | cut -s -d'"' -f2 | awk '$1 == "'$iface'"' | awk '{print $2}')
841 percent=$(($weight*100/$total_weight))
842 echo " $iface ($percent%)"
845 echo " $($IPT6 -S $policy | sed '/.*--comment \([^ ]*\) .*$/!d;s//\1/;q')"
854 mwan3_report_connected_v4()
858 if [ -n "$($IPT4 -S mwan3_connected 2> /dev/null)" ]; then
859 for address in $($IPS list mwan3_connected_v4 | egrep '[0-9]{1,3}(\.[0-9]{1,3}){3}'); do
865 mwan3_report_connected_v6()
869 if [ -n "$($IPT6 -S mwan3_connected 2> /dev/null)" ]; then
870 for address in $($IPS list mwan3_connected_v6 | egrep '([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(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])|([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])'); do
876 mwan3_report_rules_v4()
878 if [ -n "$($IPT4 -S mwan3_rules 2> /dev/null)" ]; then
879 $IPT4 -L mwan3_rules -n -v 2> /dev/null | tail -n+3 | sed 's/mark.*//' | sed 's/mwan3_policy_/- /' | sed 's/mwan3_rule_/S /'
883 mwan3_report_rules_v6()
885 if [ -n "$($IPT6 -S mwan3_rules 2> /dev/null)" ]; then
886 $IPT6 -L mwan3_rules -n -v 2> /dev/null | tail -n+3 | sed 's/mark.*//' | sed 's/mwan3_policy_/- /' | sed 's/mwan3_rule_/S /'
890 mwan3_flush_conntrack()
892 local flush_conntrack
894 config_get flush_conntrack $1 flush_conntrack never
896 if [ -e "$CONNTRACK_FILE" ]; then
897 case $flush_conntrack in
899 [ "$3" = "ifup" ] && {
900 echo f > ${CONNTRACK_FILE}
901 $LOG info "connection tracking flushed on interface $1 ($2) $3"
905 [ "$3" = "ifdown" ] && {
906 echo f > ${CONNTRACK_FILE}
907 $LOG info "connection tracking flushed on interface $1 ($2) $3"
911 echo f > ${CONNTRACK_FILE}
912 $LOG info "connection tracking flushed on interface $1 ($2) $3"
915 $LOG info "connection tracking not flushed on interface $1 ($2) $3"
919 $LOG warning "connection tracking not enabled"