multiwan: remove unnecessary call to config_clear()
[openwrt/svn-archive/packages.git] / net / multiwan / files / usr / bin / multiwan
1 #!/bin/sh
2
3 . /lib/functions.sh
4 . /lib/functions/network.sh
5
6 silencer() {
7 if [ -z "$debug" -o "$debug" == "0" ]; then
8 $* > /dev/null 2>&1
9 else
10 $*
11 fi
12 }
13
14 mwnote() {
15 logger ${debug:+-s} -p 5 -t multiwan "$1"
16 }
17
18 failover() {
19 local failchk=$(query_config failchk $2)
20 local recvrychk=$(query_config recvrychk $2)
21
22 local wanid=$(query_config wanid $2)
23 local failover_to=$(uci_get_state multiwan ${2} failover_to)
24 local failover_to_wanid=$(query_config wanid $failover_to)
25
26 local existing_failover=$(iptables -n -L FW${wanid}MARK -t mangle | echo $(($(wc -l) - 2)))
27
28 add() {
29
30 wan_fail_map=$(echo $wan_fail_map | sed -e "s/${1}\[${failchk}\]//g")
31 wan_fail_map="$wan_fail_map${1}[x]"
32 wan_recovery_map=$(echo $wan_recovery_map | sed -e "s/${1}\[${recvrychk}\]//g")
33 update_cache
34
35 if [ "$existing_failover" == "2" ]; then
36 if [ "$failover_to" != "balancer" -a "$failover_to" != "fastbalancer" -a "$failover_to" != "disable" -a "$failover_to_wanid" != "$wanid" ]; then
37 iptables -I FW${wanid}MARK 2 -t mangle -j FW${failover_to_wanid}MARK
38 elif [ "$failover_to" == "balancer" ]; then
39 iptables -I FW${wanid}MARK 2 -t mangle -j LoadBalancer
40 elif [ "$failover_to" == "fastbalancer" ]; then
41 iptables -I FW${wanid}MARK 2 -t mangle -j FastBalancer
42 fi
43 fi
44 mwnote "$1 has failed and is currently offline."
45 }
46
47 del() {
48
49 wan_recovery_map=$(echo $wan_recovery_map | sed -e "s/${1}\[${recvrychk}\]//g")
50 wan_fail_map=$(echo $wan_fail_map | sed -e "s/${1}\[${failchk}\]//g")
51 update_cache
52
53 if [ "$existing_failover" == "3" ]; then
54 iptables -D FW${wanid}MARK 2 -t mangle
55 fi
56 mwnote "$1 has recovered and is back online!"
57 }
58
59 case $1 in
60 add) add $2;;
61 del) del $2;;
62 esac
63 }
64
65 fail_wan() {
66 local new_fail_count
67
68 local health_fail_retries=$(uci_get_state multiwan ${1} health_fail_retries)
69 local weight=$(uci_get_state multiwan ${1} weight)
70
71 local failchk=$(query_config failchk $1)
72 local recvrychk=$(query_config recvrychk $1)
73 wan_recovery_map=$(echo $wan_recovery_map | sed -e "s/${1}\[${recvrychk}\]//g")
74
75 if [ -z "$failchk" ]; then
76 failchk=1
77 wan_fail_map="$wan_fail_map${1}[1]"
78 fi
79
80 if [ "$failchk" != "x" ]; then
81 new_fail_count=$(($failchk + 1))
82 if [ "$new_fail_count" -lt "$health_fail_retries" ]; then
83 wan_fail_map=$(echo $wan_fail_map | sed -e "s/${1}\[${failchk}\]/$1\[${new_fail_count}\]/g")
84 else
85 failover add $1
86 refresh_dns
87 if [ "$weight" != "disable" ]; then
88 refresh_loadbalancer
89 fi
90 fi
91 fi
92 update_cache
93 }
94
95 recover_wan() {
96 local new_fail_count
97
98 local health_recovery_retries=$(uci_get_state multiwan ${1} health_recovery_retries)
99 local weight=$(uci_get_state multiwan ${1} weight)
100
101 local failchk=$(query_config failchk $1)
102 local recvrychk=$(query_config recvrychk $1)
103 local wanid=$(query_config wanid $1)
104
105 if [ ! -z "$failchk" -a "$failchk" != "x" ]; then
106 wan_fail_map=$(echo $wan_fail_map | sed -e "s/${1}\[${failchk}\]//g")
107 update_cache
108 fi
109
110 if [ "$failchk" == "x" ]; then
111 if [ -z "$recvrychk" ]; then
112 wan_recovery_map="$wan_recovery_map${1}[1]"
113 update_cache
114 if [ "$health_recovery_retries" == "1" ]; then
115 recover_wan $1
116 fi
117 else
118 new_recovery_count=$(($recvrychk + 1))
119 if [ "$new_recovery_count" -lt "$health_recovery_retries" ]; then
120 wan_recovery_map=$(echo $wan_recovery_map | sed -e "s/${1}\[${recvrychk}\]/$1\[${new_recovery_count}\]/g")
121 update_cache
122 else
123 failover del $1
124 refresh_dns
125 if [ "$weight" != "disable" ]; then
126 refresh_loadbalancer
127 fi
128 fi
129 fi
130 fi
131 }
132
133 acquire_wan_data() {
134 local check_old_map
135 local get_wanid
136 local old_ifname
137 local old_ipaddr
138 local old_gateway
139
140 local ifname ipaddr gateway
141 network_get_device ifname ${1} || ifname=x
142 network_get_ipaddr ipaddr ${1} || ipaddr=x
143 network_get_gateway gateway ${1} || gateway=x
144
145 check_old_map=$(echo $wan_id_map 2>&1 | grep -o "$1\[")
146
147 if [ -z $check_old_map ]; then
148 wancount=$(($wancount + 1))
149 if [ $wancount -gt 20 ]; then
150 wancount=20
151 return
152 fi
153 wan_if_map="$wan_if_map${1}[${ifname}]"
154 wan_id_map="$wan_id_map${1}[${wancount}]"
155 wan_gw_map="$wan_gw_map${1}[${gateway}]"
156 wan_ip_map="$wan_ip_map${1}[${ipaddr}]"
157 else
158 old_ipaddr=$(query_config ipaddr $1)
159 old_gateway=$(query_config gateway $1)
160 old_ifname=$(query_config ifname $1)
161 get_wanid=$(query_config wanid $1)
162
163 wan_if_map=$(echo $wan_if_map | sed -e "s/${1}\[${old_ifname}\]/$1\[${ifname}\]/g")
164 wan_ip_map=$(echo $wan_ip_map | sed -e "s/${1}\[${old_ipaddr}\]/$1\[${ipaddr}\]/g")
165 wan_gw_map=$(echo $wan_gw_map | sed -e "s/${1}\[${old_gateway}\]/$1\[${gateway}\]/g")
166
167 if [ "$old_ifname" != "$ifname" ]; then
168 iptables -D MultiWanPreHandler -t mangle -i $old_$ifname -m state --state NEW -j FW${get_wanid}MARK
169 iptables -A MultiWanPreHandler -t mangle -i $ifname -m state --state NEW -j FW${get_wanid}MARK
170 iptables -D MultiWanPostHandler -t mangle -o $old_$ifname -m mark --mark 0x1 -j FW${get_wanid}MARK
171 iptables -A MultiWanPostHandler -t mangle -o $ifname -m mark --mark 0x1 -j FW${get_wanid}MARK
172 fi
173
174 if [ "$ifname" != "x" -a "$ipaddr" != "x" -a "$gateway" != "x" ]; then
175 failover del $1
176 iprules_config $get_wanid
177 else
178 failover add $1
179 fi
180
181 refresh_routes
182 refresh_loadbalancer
183 refresh_dns
184 update_cache
185 fi
186 }
187
188 update_cache() {
189 if [ ! -d /tmp/.mwan ]; then
190 mkdir /tmp/.mwan > /dev/null 2>&1
191 fi
192
193 rm /tmp/.mwan/cache > /dev/null 2>&1
194 touch /tmp/.mwan/cache
195
196 echo "# Automatically Generated by Multi-WAN Agent Script. Do not modify or remove. #" > /tmp/.mwan/cache
197 echo "wan_id_map=\"$wan_id_map\"" >> /tmp/.mwan/cache
198 echo "wan_if_map=\"$wan_if_map\"" >> /tmp/.mwan/cache
199 echo "wan_ip_map=\"$wan_ip_map\"" >> /tmp/.mwan/cache
200 echo "wan_gw_map=\"$wan_gw_map\"" >> /tmp/.mwan/cache
201 echo "wan_fail_map=\"$wan_fail_map\"" >> /tmp/.mwan/cache
202 echo "wan_recovery_map=\"$wan_recovery_map\"" >> /tmp/.mwan/cache
203 echo "wan_monitor_map=\"$wan_monitor_map\"" >> /tmp/.mwan/cache
204 }
205
206 query_config() {
207 case $1 in
208 ifname) echo $wan_if_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';;
209 ipaddr) echo $wan_ip_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';;
210 gateway) echo $wan_gw_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';;
211 wanid) echo $wan_id_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';;
212 failchk) echo $wan_fail_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';;
213 recvrychk) echo $wan_recovery_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';;
214 monitor) echo $wan_monitor_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';;
215 group) echo $wan_id_map | grep -o "\w*\[$2\]" | awk -F "[" '{print $1}';;
216 esac
217 }
218
219 mwan_kill() {
220 local otherpids=$(ps 2>&1 | grep 'multiwan agent' | grep -v $$ | awk '{print $1}')
221 [ -n "$otherpids" ] && kill $otherpids > /dev/null 2>&1
222 sleep 2
223 }
224
225 # For system shutdownl: stop
226 # A plain stop will leave network in a limp state, without wan access
227 # stop single: restore to a single wan
228 # stop restart: restart multiple wan's
229 stop() {
230 mwan_kill
231 flush $1
232
233 if [ "$1" == "single" ]; then
234 # ifup is quite expensive--do it only when single wan is requested
235 echo "## Refreshing Interfaces ##"
236 local i=0
237 while [ $((i++)) -lt $wancount ]; do
238 local group=$(query_config group $i)
239 ifup $group >&- 2>&- && sleep 1
240 done
241
242 echo "## Unloaded, updating syslog and exiting. ##"
243 mwnote "Succesfully Unloaded on $(exec date -R)."
244 rm -fr /tmp/.mwan >&- 2>&-
245 fi
246 ip route flush cache
247
248 if [ "$1" == "restart" ]; then
249 echo "## Restarting Multi-WAN. ##"
250 mwnote "Reinitializing Multi-WAN Configuration."
251 rm -fr /tmp/.mwan >&- 2>&-
252 /etc/init.d/multiwan start >&- 2>&-
253 fi
254
255 exit
256 }
257
258 clear_rules() {
259 local restore_single=$1
260 local group
261
262 iptables -t mangle -D PREROUTING -j MultiWan
263 iptables -t mangle -D FORWARD -j MultiWan
264 iptables -t mangle -D OUTPUT -j MultiWan
265 iptables -t mangle -D POSTROUTING -j MultiWan
266 iptables -t mangle -F MultiWan
267 iptables -t mangle -X MultiWan
268 iptables -t mangle -F MultiWanRules
269 iptables -t mangle -X MultiWanRules
270 iptables -t mangle -F MultiWanDNS
271 iptables -t mangle -X MultiWanDNS
272 iptables -t mangle -F MultiWanPreHandler
273 iptables -t mangle -X MultiWanPreHandler
274 iptables -t mangle -F MultiWanPostHandler
275 iptables -t mangle -X MultiWanPostHandler
276 iptables -t mangle -F LoadBalancer
277 iptables -t mangle -X LoadBalancer
278 iptables -t mangle -F FastBalancer
279 iptables -t mangle -X FastBalancer
280 iptables -t mangle -F MultiWanLoadBalancer
281 iptables -t mangle -X MultiWanLoadBalancer
282
283 local i=0
284 while [ $((i++)) -lt $wancount ]; do
285 iptables -t mangle -F FW${i}MARK
286 iptables -t mangle -X FW${i}MARK
287 done
288
289 if [ ! -z "$CHKFORQOS" ]; then
290 iptables -t mangle -F PREROUTING
291 iptables -t mangle -F FORWARD
292 iptables -t mangle -F OUTPUT
293 iptables -t mangle -F POSTROUTING
294 iptables -t mangle -F MultiWanQoS
295 iptables -t mangle -X MultiWanQoS
296
297 i=0
298 while [ $((i++)) -lt $wancount ]; do
299 group=$(query_config group $i)
300 iptables -t mangle -F qos_${group}
301 iptables -t mangle -F qos_${group}_ct
302 iptables -t mangle -X qos_${group}
303 iptables -t mangle -X qos_${group}_ct
304 done
305 fi
306
307 [ "$restore_single" == 'single' ] &&
308 /etc/init.d/qos restart > /dev/null 2>&1
309 }
310
311 qos_init() {
312 local ifname
313 local queue_count
314 local get_wan_tc
315 local get_wan_iptables
316 local add_qos_iptables
317 local add_qos_tc
318 local execute
319 local iprule
320 local qos_if_test
321
322 ifname=$(query_config ifname $1)
323
324 if [ "$ifname" == "x" ]; then
325 return
326 fi
327
328 qos_if_test=$(echo $qos_if_done | grep $ifname.)
329
330 if [ ! -z "$qos_if_test" ]; then
331 return
332 fi
333
334 qos_if_done=$(echo ${qos_if_done}.${ifname})
335
336 queue_count=$(tc filter list dev $ifname | tail -n 1 | awk -F " " '{print $10}' | sed "s/0x//g")
337
338 if [ -z "$queue_count" ]; then
339 return
340 fi
341
342 queue_count=$(($queue_count + 1))
343
344 iptables -t mangle -N qos_${1}
345 iptables -t mangle -N qos_${1}_ct
346
347 get_wan_tc=$(tc filter list dev $ifname | grep "0x" | sed -e "s/filter /tc filter add dev $ifname /g" -e "s/pref/prio/g" -e "s/fw//g")
348 get_wan_iptables=$(iptables-save | egrep '(-A Default )|(-A Default_ct )' | grep -v "MultiWanQoS" | sed -e "s/Default /qos_${1} /g" -e "s/Default_ct /qos_${1}_ct /g" -e "s/-A/iptables -t mangle -A/g")
349
350
351 local i=0
352 while [ $i -lt $queue_count ]; do
353 echo "s/\(0x$i \|0x$i\/0xffffffff\)/0x$(($2 * 10 + $i)) /g" >> /tmp/.mwan/qos.$1.sedfilter
354 i=$(($i + 1))
355 done
356
357 add_qos_iptables=$(echo "$get_wan_iptables" | sed -f /tmp/.mwan/qos.$1.sedfilter)
358 echo "$add_qos_iptables" | while read execute; do ${execute}; done
359
360 rm /tmp/.mwan/qos.$1.sedfilter
361 i=1
362 while [ $i -lt $queue_count ]; do
363 echo "s/0x$i /0x${2}${i} fw /g" >> /tmp/.mwan/qos.$1.sedfilter
364 i=$(($i + 1))
365 done
366
367 add_qos_tc=$(echo "$get_wan_tc" | sed -f /tmp/.mwan/qos.$1.sedfilter)
368 echo "$add_qos_tc" | while read execute; do ${execute}; done
369 rm /tmp/.mwan/qos.$1.sedfilter
370
371 i=0
372 while [ $i -lt $queue_count ]; do
373 if [ $i -lt $(($queue_count - 1)) ]; then
374 ip rule add fwmark 0x$(($2 * 10 + $i + 1)) table $(($2 + 170)) prio $(( $2 * 10 + $i + 2))
375 fi
376 iptables -t mangle -A MultiWanQoS -m mark --mark 0x$(($2 * 10 + $i)) -j qos_${1}
377 i=$(($i + 1))
378 done
379 }
380
381 mwanrule() {
382 local src
383 local dst
384 local ports
385 local proto
386 local wanrule
387
388 config_get src $1 src
389 config_get dst $1 dst
390 config_get port_type $1 port_type 'dports'
391 config_get ports $1 ports
392 config_get proto $1 proto
393 config_get wanrule $1 wanrule
394
395 if [ -z "$wanrule" ]; then
396 return
397 fi
398
399 if [ "$wanrule" != "balancer" -a "$wanrule" != "fastbalancer" ]; then
400 wanrule=$(query_config wanid ${wanrule})
401 wanrule="FW${wanrule}MARK"
402 elif [ "$wanrule" == "balancer" ]; then
403 wanrule="LoadBalancer"
404 elif [ "$wanrule" == "fastbalancer" ]; then
405 wanrule="FastBalancer"
406 fi
407 if [ "$dst" == "all" ]; then
408 dst=$NULL
409 fi
410 if [ "$proto" == "all" ]; then
411 proto=$NULL
412 fi
413 if [ "$ports" == "all" ]; then
414 ports=$NULL
415 fi
416 add_rule() {
417 if [ "$proto" == "icmp" ]; then
418 ports=$NULL
419 fi
420 if [ "$src" == "all" ]; then
421 src=$NULL
422 fi
423 iptables -t mangle -A MultiWanRules ${src:+-s $src} ${dst:+-d $dst} \
424 -m mark --mark 0x0 ${proto:+-p $proto -m $proto} \
425 ${ports:+-m multiport --$port_type $ports} \
426 -j $wanrule
427 }
428 if [ -z "$proto" -a ! -z "$ports" ]; then
429 proto=tcp
430 add_rule
431 proto=udp
432 add_rule
433 return
434 fi
435 add_rule
436 }
437
438 refresh_dns() {
439 local dns
440 local group
441 local ipaddr
442 local gateway
443 local ifname
444 local failchk
445 local compile_dns
446 local dns_server
447
448 iptables -F MultiWanDNS -t mangle
449
450 rm /tmp/resolv.conf.auto
451 touch /tmp/resolv.conf.auto
452
453 echo "## Refreshing DNS Resolution and Tables ##"
454
455 local i=0
456 while [ $((i++)) -lt $wancount ]; do
457 group=$(query_config group $i)
458 gateway=$(query_config gateway $group)
459 ipaddr=$(query_config ipaddr $group)
460 ifname=$(query_config ifname $group)
461 failchk=$(query_config failchk $group)
462
463 dns=$(uci_get_state multiwan ${group} dns 'auto')
464 [ "$dns" == "auto" ] && network_get_dnsserver dns ${group}
465 dns=$(echo $dns | sed -e "s/ /\n/g")
466
467 if [ ! -z "$dns" -a "$failchk" != "x" -a "$ipaddr" != "x" -a "$gateway" != "x" -a "$ifname" != "x" ]; then
468 echo "$dns" | while read dns_server; do
469 iptables -t mangle -A MultiWanDNS -d $dns_server -p tcp --dport 53 -j FW${i}MARK
470 iptables -t mangle -A MultiWanDNS -d $dns_server -p udp --dport 53 -j FW${i}MARK
471
472 compile_dns="nameserver $dns_server"
473 echo "$compile_dns" >> /tmp/resolv.conf.auto
474 done
475 fi
476 done
477
478 last_resolv_update=$(ls -l -e /tmp/resolv.conf.auto | awk -F " " '{print $5, $9}')
479 }
480
481 iptables_init() {
482 echo "## IPTables Rule Initialization ##"
483 local iprule
484 local group
485 local ifname
486 local execute
487 local IMQ_NFO
488 local default_route_id
489 local i
490
491 if [ ! -z "$CHKFORQOS" ]; then
492 echo "## QoS Initialization ##"
493
494 /etc/init.d/qos restart > /dev/null 2>&1
495
496 IMQ_NFO=$(iptables -n -L PREROUTING -t mangle -v | grep IMQ | awk -F " " '{print $6,$12}')
497
498 iptables -t mangle -F PREROUTING
499 iptables -t mangle -F FORWARD
500 iptables -t mangle -F POSTROUTING
501 iptables -t mangle -F OUTPUT
502
503 echo "$IMQ_NFO" | while read execute; do
504 iptables -t mangle -A PREROUTING -i $(echo $execute | awk -F " " '{print $1}') -j IMQ --todev $(echo $execute | awk -F " " '{print $2}')
505 done
506
507 iptables -t mangle -N MultiWanQoS
508
509 i=0
510 while [ $((i++)) -lt $wancount ]; do
511 qos_init $(query_config group $i) $i
512 done
513
514 fi
515
516 iptables -t mangle -N MultiWan
517 iptables -t mangle -N LoadBalancer
518 iptables -t mangle -N FastBalancer
519 iptables -t mangle -N MultiWanRules
520 iptables -t mangle -N MultiWanDNS
521 iptables -t mangle -N MultiWanPreHandler
522 iptables -t mangle -N MultiWanPostHandler
523 iptables -t mangle -N MultiWanLoadBalancer
524
525 echo "## Creating FW Rules ##"
526 i=0
527 while [ $((i++)) -lt $wancount ]; do
528 iprule=$(($i * 10))
529 iptables -t mangle -N FW${i}MARK
530 iptables -t mangle -A FW${i}MARK -j MARK --set-mark 0x${iprule}
531 iptables -t mangle -A FW${i}MARK -j CONNMARK --save-mark
532 done
533
534 iptables -t mangle -A LoadBalancer -j MARK --set-mark 0x1
535 iptables -t mangle -A LoadBalancer -j CONNMARK --save-mark
536
537 if [ -z "$CHKFORMODULE" ]; then
538 iptables -t mangle -A FastBalancer -j MARK --set-mark 0x2
539 iptables -t mangle -A FastBalancer -j CONNMARK --save-mark
540 else
541 mwnote "Performance load balancer(fastbalanacer) is unavailable due to current kernel limitations."
542 iptables -t mangle -A FastBalancer -j MARK --set-mark 0x1
543 iptables -t mangle -A FastBalancer -j CONNMARK --save-mark
544 fi
545
546 iptables -t mangle -A MultiWan -j CONNMARK --restore-mark
547 iptables -t mangle -A MultiWan -j MultiWanPreHandler
548 iptables -t mangle -A MultiWan -j MultiWanRules
549 iptables -t mangle -A MultiWan -j MultiWanLoadBalancer
550 iptables -t mangle -A MultiWan -j MultiWanDNS
551 iptables -t mangle -A MultiWan -j MultiWanPostHandler
552
553 iptables -t mangle -I PREROUTING -j MultiWan
554 iptables -t mangle -I FORWARD -j MultiWan
555 iptables -t mangle -I OUTPUT -j MultiWan
556 iptables -t mangle -I POSTROUTING -j MultiWan
557
558
559 refresh_dns
560
561 config_load "multiwan"
562 config_foreach mwanrule mwanfw
563
564 if [ "$default_route" != "balancer" -a "$default_route" != "fastbalancer" ]; then
565 default_route_id=$(query_config wanid $default_route)
566 iptables -t mangle -A MultiWanRules -m mark --mark 0x0 -j FW${default_route_id}MARK
567 elif [ "$default_route" == "fastbalancer" ]; then
568 iptables -t mangle -A MultiWanRules -m mark --mark 0x0 -j FastBalancer
569 else
570 iptables -t mangle -A MultiWanRules -m mark --mark 0x0 -j LoadBalancer
571 fi
572
573 i=0
574 while [ $((i++)) -lt $wancount ]; do
575 group=$(query_config group $i)
576 ifname=$(query_config ifname $group)
577 iptables -t mangle -A MultiWanPreHandler -i $ifname -m state --state NEW -j FW${i}MARK
578 iptables -t mangle -A MultiWanPostHandler -o $ifname -m mark --mark 0x1 -j FW${i}MARK
579 done
580
581 if [ ! -z "$CHKFORQOS" ]; then
582 iptables -t mangle -A MultiWan -j MultiWanQoS
583 fi
584 }
585
586 refresh_loadbalancer() {
587 local group
588 local gateway
589 local ifname
590 local failchk
591 local weight
592 local nexthop
593 local pre_nexthop_chk
594 local rand_probability
595
596 echo "## Refreshing Load Balancer ##"
597
598 ip rule del prio 9 > /dev/null 2>&1
599 ip route flush table 170 > /dev/null 2>&1
600
601 for TABLE in 170; do
602 ip route | grep -Ev ^default | while read ROUTE; do
603 ip route add table $TABLE to $ROUTE
604 done
605 done
606
607 iptables -F MultiWanLoadBalancer -t mangle
608
609 local total_weight=0
610
611 local i=0
612 while [ $((i++)) -lt $wancount ]; do
613 group=$(query_config group $i)
614 failchk=$(query_config failchk $group)
615 gateway=$(query_config gateway $group)
616 ifname=$(query_config ifname $group)
617 weight=$(uci_get_state multiwan ${group} weight)
618 if [ "$gateway" != "x" -a "$ifname" != "x" -a "$failchk" != "x" -a "$weight" != "disable" ]; then
619 total_weight=$(($total_weight + $weight))
620 fi
621 done
622
623 i=0
624 while [ $((i++)) -lt $wancount ]; do
625 group=$(query_config group $i)
626 failchk=$(query_config failchk $group)
627 gateway=$(query_config gateway $group)
628 ifname=$(query_config ifname $group)
629
630 weight=$(uci_get_state multiwan ${group} weight)
631
632 if [ "$gateway" != "x" -a "$ifname" != "x" -a "$failchk" != "x" -a "$weight" != "disable" ]; then
633 nexthop="$nexthop nexthop via $gateway dev $ifname weight $weight"
634
635 rand_probability=$(($weight * 100 / $total_weight))
636 total_weight=$(($total_weight - $weight))
637
638 if [ $rand_probability -lt 10 ]; then
639 rand_probability="0.0${rand_probability}"
640 elif [ $rand_probability -lt 100 ]; then
641 rand_probability="0.${rand_probability}"
642 else
643 rand_probability="1.0"
644 fi
645
646 if [ -z "$CHKFORMODULE" ]; then
647 iptables -A MultiWanLoadBalancer -t mangle -m mark --mark 0x2 -m statistic --mode random --probability $rand_probability -j FW${i}MARK
648 fi
649 fi
650
651 done
652
653 pre_nexthop_chk=$(echo $nexthop | awk -F "nexthop" '{print NF-1}')
654 if [ "$pre_nexthop_chk" == "1" ]; then
655 ip route add default via $(echo $nexthop | awk -F " " '{print $3}') dev $(echo $nexthop | awk -F " " '{print $5}') proto static table 170
656 elif [ "$pre_nexthop_chk" -gt "1" ]; then
657 ip route add proto static table 170 default scope global $nexthop
658 fi
659
660 ip rule add fwmark 0x1 table 170 prio 9
661 ip route flush cache
662 }
663
664 refresh_routes() {
665 local iprule
666 local gateway
667 local group
668 local ifname
669 local ipaddr
670
671 echo "## Refreshing Routing Tables ##"
672
673 local i=0
674 while [ $((i++)) -lt $wancount ]; do
675 group=$(query_config group $i)
676 gateway=$(query_config gateway $group)
677 ifname=$(query_config ifname $group)
678 ipaddr=$(query_config ipaddr $group)
679 ip route flush table $(($i + 170)) > /dev/null 2>&1
680
681 TABLE=$(($i + 170))
682 ip route | grep -Ev ^default | while read ROUTE; do
683 ip route add table $TABLE to $ROUTE
684 done
685
686 if [ "$gateway" != "x" -a "$ipaddr" != "x" -a "$ifname" != "x" ]; then
687 ip route add default via $gateway table $(($i + 170)) src $ipaddr proto static
688 route add default gw $gateway > /dev/null 2>&1
689 fi
690 done
691
692 ip route flush cache
693 }
694
695 iprules_config() {
696 local iprule
697 local group
698 local gateway
699 local ipaddr
700
701 group=$(query_config group $1)
702 gateway=$(query_config gateway $group)
703 ipaddr=$(query_config ipaddr $group)
704
705 CHKIPROUTE=$(grep MWAN${1} /etc/iproute2/rt_tables)
706 if [ -z "$CHKIPROUTE" ]; then
707 echo "$(($1 + 170)) MWAN${1}" >> /etc/iproute2/rt_tables
708 fi
709
710 ip rule del prio $(($1 * 10)) > /dev/null 2>&1
711 ip rule del prio $(($1 * 10 + 1)) > /dev/null 2>&1
712
713 if [ "$gateway" != "x" -a "$ipaddr" != "x" ]; then
714 ip rule add from $ipaddr table $(($1 + 170)) prio $(($1 * 10))
715 ip rule add fwmark 0x$(($1 * 10)) table $(($1 + 170)) prio $(($1 * 10 + 1))
716 fi
717 }
718
719 flush() {
720 local restore_single=$1
721 echo "## Flushing IP Rules & Routes ##"
722
723 ip rule flush > /dev/null 2>&1
724 ip rule add lookup main prio 32766 > /dev/null 2>&1
725 ip rule add lookup default prio 32767 > /dev/null 2>&1
726
727 ip route flush table 170 > /dev/null
728
729 local i=0
730 while [ $((i++)) -lt $wancount ]; do
731 ip route del default > /dev/null 2>&1
732 ip route flush table $(($i + 170)) > /dev/null 2>&1
733 done
734
735 echo "## Clearing Rules ##"
736 clear_rules $restore_single > /dev/null 2>&1
737
738 rm $jobfile > /dev/null 2>&1
739 }
740
741 main_init() {
742 local RP_PATH IFACE
743 local group
744 local health_interval
745
746 echo "## Main Initialization ##"
747
748 mkdir /tmp/.mwan > /dev/null 2>&1
749
750 mwan_kill
751 flush
752
753 echo "## IP Rules Initialization ##"
754
755 CHKIPROUTE=$(grep LoadBalancer /etc/iproute2/rt_tables)
756 if [ -z "$CHKIPROUTE" ]; then
757 echo "#" >> /etc/iproute2/rt_tables
758 echo "170 LoadBalancer" >> /etc/iproute2/rt_tables
759 fi
760
761 local i=0
762 while [ $((i++)) -lt $wancount ]; do
763 iprules_config $i
764 done
765
766 refresh_routes
767 iptables_init
768
769 refresh_loadbalancer
770
771 RP_PATH=/proc/sys/net/ipv4/conf
772 for IFACE in $(ls $RP_PATH); do
773 echo 0 > $RP_PATH/$IFACE/rp_filter
774 done
775 mwnote "Succesfully Initialized on $(date -R)."
776 fail_start_check
777
778 while :; do
779 schedule_tasks
780 do_tasks
781 done
782 }
783
784 monitor_wan() {
785 local ifname ipaddr gateway icmp_hosts_acquire icmp_test_host
786 local check_test
787
788 . /tmp/.mwan/cache
789
790 local timeout=$(uci_get_state multiwan ${1} timeout)
791 local icmp_hosts=$(uci_get_state multiwan ${1} icmp_hosts)
792 local icmp_count=$(uci_get_state multiwan ${1} icmp_count '1')
793 local health_interval=$(uci_get_state multiwan ${1} health_interval)
794 local ifname_cur=$(query_config ifname $1)
795 local ipaddr_cur=$(query_config ipaddr $1)
796 local gateway_cur=$(query_config gateway $1)
797
798 while :; do
799 [ "${health_monitor%.*}" = 'parallel' ] && sleep $health_interval
800
801 network_get_device ifname ${1} || ifname=x
802 network_get_ipaddr ipaddr ${1} || ipaddr=x
803 network_get_gateway gateway ${1} || gateway=x
804
805 if [ "$ifname_cur" != "$ifname" -o "$ipaddr_cur" != "$ipaddr" -o "$gateway_cur" != "$gateway" ]; then
806 add_task "$1" acquire
807 if [ "${health_monitor%.*}" = 'parallel' ]; then
808 exit
809 else
810 return
811 fi
812 else
813 [ "$gateway" != "x" ] && ! ip route | grep -o $gateway >&- 2>&- &&
814 add_task route refresh
815 fi
816
817 if [ "$icmp_hosts" != "disable" -a "$ifname" != "x" -a "$ipaddr" != "x" -a "$gateway" != "x" ]; then
818
819 if [ "$icmp_hosts" == "gateway" -o -z "$icmp_hosts" ]; then
820 icmp_hosts_acquire=$gateway
821 elif [ "$icmp_hosts" == "dns" ]; then
822 icmp_hosts_acquire=$(uci_get_state multiwan $1 dns 'auto')
823 [ "$icmp_hosts_acquire" == "auto" ] &&
824 network_get_dnsserver icmp_hosts_acquire $1
825 else
826 icmp_hosts_acquire=$icmp_hosts
827 fi
828
829 icmp_hosts=$(echo $icmp_hosts_acquire | sed -e "s/\,/ /g" | sed -e "s/ /\n/g")
830
831 ping_test() {
832 echo "$icmp_hosts" | while read icmp_test_host; do
833 ping -c "$icmp_count" -W $timeout -I $ifname $icmp_test_host 2>&1 | grep -o "round-trip"
834 done
835 }
836
837 check_test=$(ping_test)
838
839 if [ -z "$check_test" ]; then
840 add_task "$1" fail
841 else
842 add_task "$1" pass
843 fi
844
845 elif [ "$icmp_hosts" == "disable" ]; then
846 add_task "$1" pass
847 fi
848
849 [ "$health_monitor" = 'serial' ] && {
850 wan_monitor_map=$(echo $wan_monitor_map | sed -e "s/$1\[\w*\]/$1\[$(date +%s)\]/g")
851 update_cache
852 break
853 }
854 done
855 }
856
857 # Add a task to the $jobfile while ensuring
858 # no duplicate tasks for the specified group
859 add_task() {
860 local group=$1
861 local task=$2
862 grep -o "$group.$task" $jobfile >&- 2>&- || echo "$group.$task" >> $jobfile
863 }
864
865 # For health_monitor "parallel", start a background monitor for each group.
866 # For health_monitor "serial", queue monitor tasks for do_tasks.
867 schedule_tasks() {
868 local group health_interval monitored_last_at current_time diff delay
869 local i=0
870
871 get_health_interval() {
872 group=$(query_config group $1)
873 health_interval=$(uci_get_state multiwan ${group} health_interval 'disable')
874 [ "$health_interval" = "disable" ] && health_interval=0
875 }
876
877 [ "$health_monitor" = 'parallel' ] && {
878 while [ $((i++)) -lt $wancount ]; do
879 get_health_interval $i
880 if [ "$health_interval" -gt 0 ]; then
881 monitor_wan $group &
882 sleep 1
883 fi
884 done
885 echo "## Started background monitor_wan ##"
886 health_monitor="parallel.started"
887 }
888
889 [ "$health_monitor" = 'serial' ] && {
890 local monitor_disabled=1
891
892 until [ -f $jobfile ]; do
893 current_time=$(date +%s)
894 delay=$max_interval
895 i=0
896
897 while [ $((i++)) -lt $wancount ]; do
898 get_health_interval $i
899 if [ "$health_interval" -gt 0 ]; then
900 monitor_disabled=0
901
902 monitored_last=$(query_config monitor $group)
903 [ -z "$monitored_last" ] && {
904 monitored_last=$current_time
905 wan_monitor_map="${wan_monitor_map}${group}[$monitored_last]"
906 update_cache
907 }
908
909 will_monitor_at=$(($monitored_last + $health_interval))
910 diff=$(($will_monitor_at - $current_time))
911 [ $diff -le 0 ] && add_task "$group" 'monitor'
912
913 delay=$(($delay > $diff ? $diff : $delay))
914 fi
915 done
916
917 [ "$monitor_disabled" -eq 1 ] && {
918 # Although health monitors are disabled, still
919 # need to check up on iptables rules in do_tasks
920 sleep "$iptables_interval"
921 break
922 }
923 [ $delay -gt 0 ] && sleep $delay
924 done
925 }
926 }
927
928 rule_counter=0
929 # Process each task in the $jobfile in FIFO order
930 do_tasks() {
931 local check_iptables
932 local queued_task
933 local current_resolv_file
934
935 while :; do
936
937 . /tmp/.mwan/cache
938
939 if [ "$((++rule_counter))" -eq 5 -o "$health_monitor" = 'serial' ]; then
940
941 check_iptables=$(iptables -n -L MultiWan -t mangle | grep "references" | awk -F "(" '{print $2}' | cut -d " " -f 1)
942
943 if [ -z "$check_iptables" -o "$check_iptables" -lt 4 ]; then
944 mwnote "Netfilter rules appear to of been altered."
945 /etc/init.d/multiwan restart
946 exit
947 fi
948
949 current_resolv_file=$(ls -l -e /tmp/resolv.conf.auto | awk -F " " '{print $5, $9}')
950
951 if [ "$last_resolv_update" != "$current_resolv_file" ]; then
952 refresh_dns
953 fi
954
955 rule_counter=0
956 fi
957
958 if [ -f $jobfile ]; then
959
960 mv $jobfile $jobfile.work
961
962 while read LINE; do
963
964 execute_task() {
965 case $2 in
966 fail) fail_wan $1;;
967 pass) recover_wan $1;;
968 acquire)
969 acquire_wan_data $1
970 [ "${health_monitor%.*}" = 'parallel' ] && {
971 monitor_wan $1 &
972 echo "## Started background monitor_wan ##"
973 }
974 ;;
975 monitor) monitor_wan $1;;
976 refresh) refresh_routes;;
977 *) echo "## Unknown task command: $2 ##";;
978 esac
979 }
980
981 queued_task=$(echo $LINE | awk -F "." '{print $1,$2}')
982 execute_task $queued_task
983 done < $jobfile.work
984
985 rm $jobfile.work
986 fi
987
988 if [ "$health_monitor" = 'serial' ]; then
989 break
990 else
991 sleep 1
992 fi
993 done
994 }
995
996 fail_start_check(){
997 local ipaddr
998 local gateway
999 local ifname
1000 local group
1001
1002 local i=0
1003 while [ $((i++)) -lt $wancount ]; do
1004 group=$(query_config group $i)
1005 ifname=$(query_config ifname $group)
1006 ipaddr=$(query_config ipaddr $group)
1007 gateway=$(query_config gateway $group)
1008
1009 if [ "$ifname" == "x" -o "$ipaddr" == "x" -o "$gateway" == "x" ]; then
1010 failover add $group
1011 fi
1012 done
1013 }
1014
1015 wancount=0
1016 max_interval=$(((1<<31) - 1))
1017
1018 config_load "multiwan"
1019 config_get_bool enabled config enabled '1'
1020 [ "$enabled" -gt 0 ] || exit
1021 config_get default_route config default_route
1022 config_get health_monitor config health_monitor
1023 config_get iptables_interval config iptables_interval '30'
1024 config_get debug config debug
1025
1026 [ "$health_monitor" = 'serial' ] || health_monitor='parallel'
1027
1028 config_foreach acquire_wan_data interface
1029
1030 update_cache
1031
1032 CHKFORQOS=$(iptables -n -L Default -t mangle 2>&1 | grep "Chain Default")
1033 CHKFORMODULE=$(iptables -m statistic 2>&1 | grep -o "File not found")
1034
1035 jobfile="/tmp/.mwan/jobqueue"
1036
1037 case $1 in
1038 agent) silencer main_init;;
1039 stop) silencer stop;;
1040 restart) silencer stop restart;;
1041 single) silencer stop single;;
1042 esac