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