From: Jo-Philipp Wich Date: Fri, 16 Apr 2010 16:05:03 +0000 (+0000) Subject: [packages] add multiwan, a simple to use multi wan configuration agent X-Git-Url: http://git.openwrt.org/?p=openwrt%2Fsvn-archive%2Farchive.git;a=commitdiff_plain;hb=b806c9e3c599a1f6a3a08314f030dbb1f35f52b7 [packages] add multiwan, a simple to use multi wan configuration agent SVN-Revision: 20925 --- diff --git a/net/multiwan/Makefile b/net/multiwan/Makefile new file mode 100644 index 0000000000..30d6dbb4a6 --- /dev/null +++ b/net/multiwan/Makefile @@ -0,0 +1,41 @@ +# +# Copyright (C) 2010 OpenWrt.org +# +# This is free software, licensed under the GNU General Public License v2. +# See /LICENSE for more information. +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=multiwan +PKG_VERSION:=1.0k +PKG_RELEASE:=1 + +include $(INCLUDE_DIR)/package.mk + +define Package/multiwan + SECTION:=net + CATEGORY:=Network + DEPENDS:=+ip +iptables +iptables-utils +iptables-mod-conntrack +iptables-mod-conntrack-extra + TITLE:=Simple multi WAN configuration + URL:=ftp://ftp.netlab7.com/ +endef + +define Package/multiwan/description +An agent script that makes Multi-WAN configuration simple, +easy and manageable. Complete with load balancing, failover and an easy +to manage traffic ruleset. Allows for configuration of up to 9 wan links. +endef + +define Package/multiwan/conffiles +/etc/config/multiwan +endef + +define Build/Compile +endef + +define Package/multiwan/install + $(CP) ./files/* $(1) +endef + +$(eval $(call BuildPackage,multiwan)) diff --git a/net/multiwan/files/etc/config/multiwan b/net/multiwan/files/etc/config/multiwan new file mode 100644 index 0000000000..9ba84743a9 --- /dev/null +++ b/net/multiwan/files/etc/config/multiwan @@ -0,0 +1,63 @@ + +config 'multiwan' 'config' + option 'default_route' 'balancer' + option 'resolv_conf' '/tmp/resolv.conf.auto' + +config 'interface' 'wan' + option 'weight' '5' + option 'health_interval' '10' + option 'icmp_hosts' 'dns' + option 'timeout' '3' + option 'health_fail_retries' '3' + option 'health_recovery_retries' '5' + option 'failover_to' 'balancer' + +config 'interface' 'wan2' + option 'weight' '5' + option 'health_interval' '10' + option 'icmp_hosts' 'dns' + option 'timeout' '3' + option 'health_fail_retries' '3' + option 'health_recovery_retries' '5' + option 'failover_to' 'wan3' + +config 'interface' 'wan3' + option 'weight' 'disable' + option 'health_interval' 'disable' + option 'icmp_hosts' 'gateway' + option 'timeout' '3' + option 'health_fail_retries' '3' + option 'health_recovery_retries' '5' + option 'failover_to' 'disable' + +config 'interface' 'wan4' + option 'weight' '3' + option 'health_interval' '20' + option 'icmp_hosts' '208.67.222.222 208.67.220.220' + option 'timeout' '3' + option 'health_fail_retries' '3' + option 'health_recovery_retries' '5' + option 'failover_to' 'wan' + +config 'mwanfw' + option 'src' '192.168.1.0/24' + option 'dst' 'ftp.netlab7.com' + option 'proto' 'tcp' + option 'ports' '21' + option 'wanrule' 'wan4' + +config 'mwanfw' + option 'proto' 'tcp' + option 'ports' '21' + option 'wanrule' 'wan2' + +config 'mwanfw' + option 'src' '192.168.0.3' + option 'proto' 'icmp' + option 'wanrule' 'wan' + +config 'mwanfw' + option 'dst' 'www.whatismyip.com' + option 'wanrule' 'balancer' + + diff --git a/net/multiwan/files/etc/init.d/multiwan b/net/multiwan/files/etc/init.d/multiwan new file mode 100755 index 0000000000..6d0c5b3050 --- /dev/null +++ b/net/multiwan/files/etc/init.d/multiwan @@ -0,0 +1,15 @@ +#!/bin/sh /etc/rc.common +START=99 + +start () { + sh /usr/bin/multiwan agent +} + +stop () { + sh /usr/bin/multiwan stop +} + +restart () { + sh /usr/bin/multiwan restart +} + diff --git a/net/multiwan/files/usr/bin/multiwan b/net/multiwan/files/usr/bin/multiwan new file mode 100755 index 0000000000..3160218096 --- /dev/null +++ b/net/multiwan/files/usr/bin/multiwan @@ -0,0 +1,961 @@ +#!/bin/sh + +. /etc/functions.sh + +silencer() { +if [ -z "$debug" -o "$debug" == "0" ]; then +$* > /dev/null 2>&1 +else +$* +fi +} + +mwnote() { +logger "[Multi-WAN Notice]: $1" +} + +failover() { +local failover_to +local failover_to_wanid +local failchk +local wanid +local existing_failover + +wanid=$(query_config wanid $2) +failover_to=`uci -q -P /var/state get multiwan.${2}.failover_to` +failover_to_wanid=$(query_config wanid $failover_to) + +existing_failover=$(iptables -n -L FW${wanid}MARK -t mangle | echo $(expr $(wc -l) - 2)) + +add() { +if [ "$existing_failover" == "2" ]; then + if [ "$failover_to" != "balancer" -a "$failover_to" != "disable" -a "$failover_to_wanid" != "$wanid" ]; then + iptables -I FW${wanid}MARK 2 -t mangle -j FW${failover_to_wanid}MARK + elif [ "$failover_to" == "balancer" ]; then + iptables -I FW${wanid}MARK 2 -t mangle -j LoadBalancer + fi +fi + mwnote "$1 has failed and is currently offline." +} + +del() { +if [ "$existing_failover" == "3" ]; then + if [ "$failover_to" != "balancer" -a "failover_to" != "disable" -a "$failover_to_wanid" != "$wanid" ]; then + iptables -D FW${wanid}MARK -t mangle -j FW${failover_to_wanid}MARK + elif [ "$failover_to" == "balancer" ]; then + iptables -D FW${wanid}MARK -t mangle -j LoadBalancer + fi +fi + mwnote "$1 has recovered and is back online!" +} + +case $1 in +add) add $2;; +del) del $2;; +esac +} + +fail_wan() { +local failchk +local recvrychk +local new_fail_count +local health_fail_retries +local weight + +health_fail_retries=`uci -q -P /var/state get multiwan.${1}.health_fail_retries` +weight=`uci -q -P /var/state get multiwan.${1}.weight` + +failchk=$(query_config failchk $1) +recvrychk=$(query_config recvrychk $1) +wan_recovery_map=$(echo $wan_recovery_map | sed -e "s/${1}\[${recvrychk}\]//g") + +if [ -z "$failchk" ]; then +wan_fail_map="$wan_fail_map $1[1]" + if [ "$health_fail_retries" == "1" ]; then + fail_wan $1 + fi +else + if [ "$failchk" != "x" ]; then + new_fail_count=$(expr $failchk + 1) + if [ "$new_fail_count" -lt "$health_fail_retries" ]; then + wan_fail_map=$(echo $wan_fail_map | sed -e "s/${1}\[${failchk}\]/$1\[${new_fail_count}\]/g") + else + wan_fail_map=$(echo $wan_fail_map | sed -e "s/${1}\[${failchk}\]/$1\[x\]/g") + if [ "$weight" != "disable" ]; then + refresh_loadbalancer + fi + refresh_dns + failover add $1 + fi + fi +fi +} + +recover_wan() { +local failchk +local recvrychk +local new_fail_count +local wanid +local health_recovery_retires +local weight + +health_recovery_retries=`uci -q -P /var/state get multiwan.${1}.health_recovery_retries` +weight=`uci -q -P /var/state get multiwan.${1}.weight` + +failchk=$(query_config failchk $1) +recvrychk=$(query_config recvrychk $1) +wanid=$(query_config wanid $1) + +if [ "$failchk" == "x" ]; then + if [ -z "$recvrychk" ]; then + wan_recovery_map="$wan_recovery_map $1[1]" + if [ "$health_recovery_retries" == "1" ]; then + recover_wan $1 + fi + else + new_recovery_count=$(expr $recvrychk + 1) + if [ "$new_recovery_count" -lt "$health_recovery_retries" ]; then + wan_recovery_map=$(echo $wan_recovery_map | sed -e "s/${1}\[${recvrychk}\]/$1\[${new_recovery_count}\]/g") + else + wan_recovery_map=$(echo $wan_recovery_map | sed -e "s/${1}\[${recvrychk}\]//g") + wan_fail_map=$(echo $wan_fail_map | sed -e "s/${1}\[${failchk}\]//g") + if [ "$weight" != "disable" ]; then + refresh_loadbalancer + fi + refresh_dns + failover del $1 + fi + fi +fi +} + +acquire_wan_data() { +if [ $wancount -lt 9 ]; then + +local ipaddr +local gateway +local ifname +local check_old_map +local get_wanid +local old_ifname +local old_ipaddr +local old_gateway + +ifname=`uci -q -P /var/state get network.${1}.ifname` +ipaddr=`uci -q -P /var/state get network.${1}.ipaddr` +gateway=`uci -q -P /var/state get network.${1}.gateway` + +if [ -z "$ifname" ]; then +ifname="x" +fi +if [ -z "$ipaddr" ]; then +ipaddr="x" +fi +if [ -z "$gateway" ]; then +gateway="x" +fi + +check_old_map=`echo $wan_id_map 2>&1 | grep -o "$1\["` + + if [ -z $check_old_map ]; then + wancount=`expr $wancount + 1` + wan_if_map="$wan_if_map $1[${ifname}] " + wan_id_map="$wan_id_map $1[${wancount}] " + wan_gw_map="$wan_gw_map $1[${gateway}] " + wan_ip_map="$wan_ip_map $1[${ipaddr}] " + else + old_ipaddr=$(query_config ipaddr $1) + old_gateway=$(query_config gateway $1) + old_ifname=$(query_config ifname $1) + get_wanid=$(query_config wanid $1) + + wan_if_map=$(echo $wan_if_map | sed -e "s/${1}\[${old_ifname}\]/$1\[${ifname}\]/g") + wan_ip_map=$(echo $wan_ip_map | sed -e "s/${1}\[${old_ipaddr}\]/$1\[${ipaddr}\]/g") + wan_gw_map=$(echo $wan_gw_map | sed -e "s/${1}\[${old_gateway}\]/$1\[${gateway}\]/g") + + if [ "$old_ifname" != "$ifname" ]; then + iptables -D MultiWanPreHandler -t mangle -i $old_$ifname -m state --state NEW -j FW${get_wanid}MARK + iptables -A MultiWanPreHandler -t mangle -i $ifname -m state --state NEW -j FW${get_wanid}MARK + iptables -D MultiWanPostHandler -t mangle -o $old_$ifname -m mark --mark 0x123 -j FW${get_wanid}MARK + iptables -A MultiWanPostHandler -t mangle -o $ifname -m mark --mark 0x123 -j FW${get_wanid}MARK + fi + + refresh_routes + refresh_loadbalancer + refresh_dns + + if [ "$ifname" != "x" -a "$ipaddr" != "x" -a "$gateway" != "x" ]; then + iprules_config $get_wanid + qos_init $1 $get_wanid + failover del $1 + else + failover add $1 + fi + fi +else +wancount=9 +fi +} + +query_config() { +case $1 in + ifname) echo $wan_if_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';; + ipaddr) echo $wan_ip_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';; + gateway) echo $wan_gw_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';; + wanid) echo $wan_id_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';; + failchk) echo $wan_fail_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';; + recvrychk) echo $wan_recovery_map | grep -o "$2\[\w*.*\]" | awk -F "[" '{print $2}' | awk -F "]" '{print $1}';; + group) echo $wan_id_map | grep -o "\w*\[$2\]" | awk -F "[" '{print $1}';; +esac +} + +mwan_kill() { +local otherpids +local execute +otherpids=$(ps -a 2>&1 | grep 'multiwan agent' | grep -v $$ | awk -F " " '{print $1}') +echo "$otherpids" | while read execute +do +kill -9 ${execute} > /dev/null 2>&1 +done +} + +stop() { +local group +local i + +mwan_kill +flush + +if [ "$1" != "restart" ]; then +echo "## Refreshing Interfaces ##" + i=0 + while [ $i -lt $wancount ]; do + i=`expr $i + 1` + group=$(query_config group $i) + fdown $group > /dev/null 2>&1 + ifup $group > /dev/null 2>&1 & + done + +if [ ! -z "$CHKFORQOS" ]; then +/etc/init.d/qos restart & > /dev/null 2>&1 +fi + +echo "## Unloaded, updating syslog and exiting. ##" +mwnote "Succesfully Unloaded on $(exec date -R)." + +else + +echo "## Restarting Multi-WAN. ##" +mwnote "Reinitializing Multi-WAN Configuration." +/etc/init.d/multiwan start & > /dev/null 2>&1 + +fi + +ip route flush cache + +exit +} + +clear_rules() { +local group +local i + +iptables -t mangle -F PREROUTING +iptables -t mangle -F FORWARD +iptables -t mangle -F POSTROUTING +iptables -t mangle -F OUTPUT +iptables -t mangle -F MultiWan +iptables -t mangle -X MultiWan +iptables -t mangle -F MultiWanRules +iptables -t mangle -X MultiWanRules +iptables -t mangle -F MultiWanDNS +iptables -t mangle -X MultiWanDNS +iptables -t mangle -F MultiWanPreHandler +iptables -t mangle -X MultiWanPreHandler +iptables -t mangle -F MultiWanPostHandler +iptables -t mangle -X MultiWanPostHandler +iptables -t mangle -F LoadBalancer +iptables -t mangle -X LoadBalancer + +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +iptables -t mangle -F FW${i}MARK +done + +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +iptables -t mangle -X FW${i}MARK +done + +if [ ! -z "$CHKFORQOS" ]; then + +iptables -t mangle -F MultiWanQoS +iptables -t mangle -X MultiWanQoS + +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +group=$(query_config group $i) +iptables -t mangle -F MultiWanQoS_${group} +iptables -t mangle -F MultiWanQoS_${group}_ct +iptables -t mangle -X MultiWanQoS_${group} +iptables -t mangle -X MultiWanQoS_${group}_ct +done + +fi +} + +qos_init() { +local ifname +local queue_count +local get_wan_tc +local get_wan_iptables +local qos_done_chk +local add_qos_iptables +local add_qos_tc +local execute +local i +local p + +qos_done_chk=`echo $qos_done | grep -o "$1\."` + +if [ ! -z "$qos_done_chk" ]; then +return +fi + +ifname=$(query_config ifname $1) + +if [ "$ifname" == "x" ]; then +return +fi + +queue_count=$(tc filter list dev $ifname | tail -n 1 | awk -F " " '{print $10}' | sed "s/0x//g") + +if [ -z "$queue_count" ]; then +return +fi + +queue_count=`expr $queue_count + 1` + +iptables -t mangle -N MultiWanQoS_${1} +iptables -t mangle -N MultiWanQoS_${1}_ct + +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") +get_wan_iptables=$(iptables-save | egrep '(-A Default )|(-A Default_ct )' | grep -v "MultiWanQoS" | sed -e "s/Default /MultiWanQoS_${1} /g" -e "s/Default_ct /MultiWanQoS_${1}_ct /g" -e "s/-A/iptables -t mangle -A/g") + +rm /tmp/.mwan.$1.sedfilter > /dev/null 2>&1 +i=0 +while [ $i -lt $queue_count ]; do +echo "s/\(0x$i \|0x$i\/0xffffffff\)/0x${2}${i} /g" >> /tmp/.mwan.$1.sedfilter +i=`expr $i + 1` +done + +add_qos_iptables=$(echo "$get_wan_iptables" | sed -f /tmp/.mwan.$1.sedfilter) +echo "$add_qos_iptables" | while read execute; do ${execute}; done + +rm /tmp/.mwan.$1.sedfilter +i=1 +while [ $i -lt $queue_count ]; do +echo "s/0x$i /0x${2}${i} fw /g" >> /tmp/.mwan.$1.sedfilter +i=`expr $i + 1` +done + +add_qos_tc=$(echo "$get_wan_tc" | sed -f /tmp/.mwan.$1.sedfilter) +echo "$add_qos_tc" | while read execute; do ${execute}; done +rm /tmp/.mwan.$1.sedfilter + +i=0 +while [ $i -lt $queue_count ]; do + p=`expr $i + $2 \* 10` +if [ $i -lt $(expr $queue_count - 1) ]; then + ip rule add fwmark 0x$(expr $p + 1) table $(expr $2 \* 10) prio $(expr $p + 2) +fi + iptables -t mangle -A MultiWanQoS -m mark --mark 0x$p -j MultiWanQoS_${1} + i=`expr $i + 1` +done + +qos_done="$qos_done $1." + +} + +mwanrule() { + local src + local dst + local ports + local proto + local wanrule + + config_get src $1 src + config_get dst $1 dst + config_get ports $1 ports + config_get proto $1 proto + config_get wanrule $1 wanrule + ports_first=${ports%-*} + ports_last=${ports#*-} + + if [ -z "$wanrule" ]; then + return + fi + + if [ "$wanrule" != "balancer" ]; then + wanrule=$(query_config wanid ${wanrule}) + wanrule="FW${wanrule}MARK" + elif [ "$wanrule" == "balancer" ]; then + wanrule="LoadBalancer" + fi + if [ "$dst" == "all" ]; then + dst=$NULL + fi + if [ "$proto" == "all" ]; then + proto=$NULL + fi + if [ "$ports" == "all" ]; then + ports=$NULL + fi + if [ "$ports_first" -ne "$ports_last" ]; then + ports="$ports_first:$ports_last" + fi + add_rule() { + if [ "$proto" == "icmp" ]; then + ports=$NULL + fi + if [ "$src" == "all" ]; then + src=$NULL + fi + iptables -t mangle -A MultiWanRules -m mark --mark 0x0\ + ${proto:+-p $proto} \ + ${src:+-s $src} \ + ${dst:+-d $dst} \ + ${ports:+--dport $ports} \ + -j $wanrule + } + if [ -z "$proto" -a ! -z "$ports" ]; then + proto=tcp + add_rule + proto=udp + add_rule + return + fi + add_rule +} + +refresh_dns() { +local dns +local group +local ipaddr +local gateway +local ifname +local failchk +local compile_dns +local resolv_conf +local dns_server +local i + +iptables -F MultiWanDNS -t mangle + +rm $resolv_conf +touch $resolv_conf + +echo "## Refreshing DNS Resolution and Tables ##" + +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +group=$(query_config group $i) +gateway=$(query_config gateway $group) +ipaddr=$(query_config ipaddr $group) +ifname=$(query_config ifname $group) +failchk=$(query_config failchk $group) + +dns=`uci -q -P /var/state get network.${group}.dns` +dns=$(echo $dns | sed -e "s/ /\n/g") + +if [ ! -z "$dns" -a "$failchk" != "x" -a "$ipaddr" != "x" -a "$gateway" != "x" -a "$ifname" != "x" ]; then +echo "$dns" | while read dns_server +do + iptables -t mangle -A MultiWanDNS -d $dns_server -p UDP --dport 53 -j FW${i}MARK + + compile_dns="nameserver $dns_server" + echo "$compile_dns" >> $resolv_conf +done +fi +done +} + +iptables_init() { +echo "## IPTables Rule Initialization ##" +local iprule +local group +local ifname +local execute +local IMQ_NFO +local default_route_id +local i + +if [ ! -z "$CHKFORQOS" ]; then +echo "## QoS Initialization ##" + +/etc/init.d/qos restart > /dev/null 2>&1 + +IMQ_NFO=`iptables -n -L PREROUTING -t mangle -v | grep IMQ | awk -F " " '{print $6,$12}'` + +iptables -t mangle -F PREROUTING +iptables -t mangle -F FORWARD +iptables -t mangle -F POSTROUTING +iptables -t mangle -F OUTPUT + +echo "$IMQ_NFO" | while read execute +do +iptables -t mangle -A PREROUTING -i $(echo $execute | awk -F " " '{print $1}') -j IMQ --todev $(echo $execute | awk -F " " '{print $2}') +done + +iptables -t mangle -N MultiWanQoS + +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +qos_init $(query_config group $i) $i +done + +fi + +iptables -t mangle -N MultiWan +iptables -t mangle -N LoadBalancer +iptables -t mangle -N MultiWanRules +iptables -t mangle -N MultiWanDNS +iptables -t mangle -N MultiWanPreHandler +iptables -t mangle -N MultiWanPostHandler + +echo "## Creating FW Rules ##" +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +iprule=$(expr $i \* 10) +iptables -t mangle -N FW${i}MARK +iptables -t mangle -A FW${i}MARK -j MARK --set-mark 0x${iprule} +iptables -t mangle -A FW${i}MARK -j CONNMARK --save-mark +done + +iptables -t mangle -A LoadBalancer -j MARK --set-mark 0x123 +iptables -t mangle -A LoadBalancer -j CONNMARK --save-mark + +iptables -t mangle -I PREROUTING -j MultiWan +iptables -t mangle -I FORWARD -j MultiWan +iptables -t mangle -I OUTPUT -j MultiWan +iptables -t mangle -I POSTROUTING -j MultiWan + +iptables -t mangle -A MultiWan -j CONNMARK --restore-mark +iptables -t mangle -A MultiWan -j MultiWanPreHandler + +refresh_dns + +config_load "multiwan" +config_foreach mwanrule mwanfw + +if [ "$default_route" != "balancer" ]; then +default_route_id=$(query_config wanid $default_route) +iptables -t mangle -A MultiWanRules -m mark --mark 0x0 -j FW${default_route_id}MARK +else +iptables -t mangle -A MultiWanRules -m mark --mark 0x0 -j LoadBalancer +fi + +iptables -t mangle -A MultiWan -j MultiWanRules +iptables -t mangle -A MultiWan -j MultiWanDNS +iptables -t mangle -A MultiWan -j MultiWanPostHandler + +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +group=$(query_config group $i) +ifname=$(query_config ifname $group) +iptables -t mangle -A MultiWanPreHandler -i $ifname -m state --state NEW -j FW${i}MARK +iptables -t mangle -A MultiWanPostHandler -o $ifname -m mark --mark 0x123 -j FW${i}MARK +done + +if [ ! -z "$CHKFORQOS" ]; then +iptables -t mangle -A MultiWan -j MultiWanQoS +fi +} + +refresh_loadbalancer() { +local group +local gateway +local ifname +local failchk +local weight +local nexthop +local pre_nexthop_chk +local i + + +echo "## Refreshing Load Balancer ##" + +CHKIPROUTE=`cat /etc/iproute2/rt_tables | grep LoadBalancer` + if [ -z "$CHKIPROUTE" ]; then +echo "123 LoadBalancer" >> /etc/iproute2/rt_tables + fi +ip rule del prio 123 > /dev/null 2>&1 +ip route flush table 123 > /dev/null 2>&1 + + for TABLE in 123 + do + ip route | grep link | while read ROUTE + do + ip route add table $TABLE to $ROUTE + done + done + +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +group=$(query_config group $i) +failchk=$(query_config failchk $group) +gateway=$(query_config gateway $group) +ifname=$(query_config ifname $group) + +weight=`uci -q -P /var/state get multiwan.${group}.weight` + +if [ "$gateway" != "x" -a "$ifname" != "x" -a "$failchk" != "x" -a "$weight" != "disable" ]; then +nexthop="$nexthop nexthop via $gateway dev $ifname weight $weight" +fi +done + +pre_nexthop_chk=`echo $nexthop | awk -F "nexthop" '{print NF-1}'` +if [ "$pre_nexthop_chk" == "1" ]; then +ip route add default via $(echo $nexthop | awk -F " " '{print $3}') dev $(echo $nexthop | awk -F " " '{print $5}') proto static table 123 +elif [ "$pre_nexthop_chk" -gt "1" ]; then +ip route add proto static table 123 default scope global $nexthop +fi + +ip rule add fwmark 0x123 table 123 prio 123 +ip route flush cache +} + +refresh_routes() { +local iprule +local gateway +local group +local ifname +local ipaddr +local i + +echo "## Refreshing Routing Tables ##" + +i=0 +while [ $i -lt $wancount ] +do +i=`expr $i + 1` +group=$(query_config group $i) +gateway=$(query_config gateway $group) +ifname=$(query_config ifname $group) +ipaddr=$(query_config ipaddr $group) + +iprule=$(expr $i \* 10) +ip route flush table $iprule > /dev/null 2>&1 + + for TABLE in $iprule + do + ip route | grep link | while read ROUTE + do + ip route add table $TABLE to $ROUTE + done + done + +if [ "$gateway" != "x" -a "$ipaddr" != "x" -a "$ifname" != "x" ]; then +ip route add default via $gateway table $iprule src $ipaddr proto static +route add default gw $gateway dev $ifname +fi +done + +ip route flush cache +} + +iprules_config() { + +local iprule +local group +local gateway +local ipaddr + +iprule=$(expr $1 \* 10) +group=$(query_config group $1) +gateway=$(query_config gateway $group) +ipaddr=$(query_config ipaddr $group) + +CHKIPROUTE=`cat /etc/iproute2/rt_tables | grep MWAN${1}` + if [ -z "$CHKIPROUTE" ]; then +echo "$iprule MWAN${1}" >> /etc/iproute2/rt_tables + fi + +ip rule del prio $iprule > /dev/null 2>&1 +ip rule del prio $(expr $iprule + 1) > /dev/null 2>&1 + +if [ "$gateway" != "x" -a "$ipaddr" != "x" ]; then +ip rule add from $ipaddr table $iprule prio $iprule +ip rule add fwmark 0x${iprule} table $iprule prio $(expr $iprule + 1) +fi +} + +flush() { +local iprule +local i + +echo "## Flushing IP Rules & Routes ##" + +ip rule flush > /dev/null 2>&1 +ip rule add lookup main prio 32766 > /dev/null 2>&1 +ip rule add lookup default prio 32767 > /dev/null 2>&1 + +ip route flush table 123 > /dev/null + + i=0 + while [ $i -lt $wancount ]; do + i=`expr $i + 1` + iprule=$(expr $i \* 10) + ip route del default > /dev/null 2>&1 + ip route flush table $iprule > /dev/null 2>&1 + done + +echo "## Clearing Rules ##" +clear_rules > /dev/null 2>&1 + +rm $jobfile > /dev/null 2>&1 +} + +main_init() { +local RP_PATH +local group +local health_interval +local i + +echo "## Main Initialization ##" + +mwan_kill +flush + +refresh_loadbalancer + +echo "## IP Rules Initialization ##" +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +iprules_config $i +done + +refresh_routes +iptables_init + +RP_PATH=/proc/sys/net/ipv4/conf +for IFACE in `ls $RP_PATH`; do + echo 0 > $RP_PATH/$IFACE/rp_filter +done +echo "## Initialization Complete, switching to background mode. ##" +mwnote "Succesfully Initialized on $(exec date -R)." +fail_start_check + +stagger_health_monitors() { +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +group=$(query_config group $i) +health_interval=`uci -q -P /var/state get multiwan.${group}.health_interval` +if [ ! -z "$health_interval" -a "$health_interval" != "disable" -a "$health_interval" -gt 0 ]; then +health_monitor $group & +sleep 3 +fi +done +} + +stagger_health_monitors & +bg_task & + +exit +} + +health_monitor() { +local ipaddr_cur +local gateway_cur +local ifname_cur +local ifname +local ipaddr +local gateway +local failchk +local icmp_hosts +local icmp_hosts_acquire +local default_routes_check +local icmp_test_host +local timeout +local check_test +local health_interval +local check_for_job + +timeout=`uci -q -P /var/state get multiwan.${1}.timeout` +icmp_hosts=`uci -q -P /var/state get multiwan.${1}.icmp_hosts` +health_interval=`uci -q -P /var/state get multiwan.${1}.health_interval` +ifname_cur=$(query_config ifname $1) +ipaddr_cur=$(query_config ipaddr $1) +gateway_cur=$(query_config gateway $1) + +while [ 1 ]; do + +ifname=`uci -q -P /var/state get network.${1}.ifname` +ipaddr=`uci -q -P /var/state get network.${1}.ipaddr` +gateway=`uci -q -P /var/state get network.${1}.gateway` + +if [ -z "$ifname" ]; then +ifname="x" +fi + +if [ -z "$ipaddr" ]; then +ipaddr="x" +fi + +if [ -z "$gateway" ]; then +gateway="x" +fi + +if [ "$ifname_cur" != "$ifname" -o "$ipaddr_cur" != "$ipaddr" -o "$gateway_cur" != "$gateway" ]; then +echo $1.acquire >> $jobfile +exit +else + if [ "$gateway" != "x" ]; then + default_routes_check=`ip route | grep -o $gateway` + if [ -z "$default_routes_check" ]; then + check_for_job=`cat $jobfile 2>&1 | grep -o "route.refresh"` + if [ -z "$check_for_job" ]; then + echo route.refresh >> $jobfile + fi + fi + fi +fi + +if [ "$icmp_hosts" != "disable" -a "$ifname" != "x" -a "$ipaddr" != "x" -a "$gateway" != "x" ]; then + + if [ "$icmp_hosts" == "gateway" -o -z "$icmp_hosts" ]; then + icmp_hosts_acquire=$gateway + elif [ "$icmp_hosts" == "dns" ]; then + icmp_hosts_acquire=`uci -q -P /var/state get network.$1.dns` + else + icmp_hosts_acquire=$icmp_hosts + fi + +icmp_hosts=$(echo $icmp_hosts_acquire | sed -e "s/\,/ /g" | sed -e "s/ /\n/g") + +ping_test() { +echo "$icmp_hosts" | while read icmp_test_host +do +ping -c 1 -W $timeout -I $ifname $icmp_test_host 2>&1 | grep -o "round-trip" +done +} + +check_test=$(ping_test) + + if [ -z "$check_test" ]; then + echo "$1.fail" >> $jobfile + else + echo "$1.pass" >> $jobfile + fi + +elif [ "$icmp_hosts" == "disable" ]; then +echo "$1.pass" >> $jobfile +fi + +sleep $health_interval +done +} + +bg_task() { +local check_iptables +local queued_task +local bg_counter + +bg_counter=0 + +while [ 1 ]; do + +if [ "$bg_counter" -eq 5 ]; then + +check_iptables=$(iptables -n -L MultiWan -t mangle | grep "references" | awk -F "(" '{print $2}' | cut -d " " -f 1) + + if [ -z "$check_iptables" -o "$check_iptables" -lt 4 ]; then + mwnote "Netfilter rules appear to of been altered." + /etc/init.d/multiwan restart & + exit + fi + +bg_counter=0 + +fi + +if [ -f $jobfile ]; then + +mv $jobfile $jobfile.work + +while read LINE +do + +execute_task(){ +case $2 in +fail) fail_wan $1;; +pass) recover_wan $1;; +acquire) acquire_wan_data $1 && health_monitor $1 &;; +refresh) refresh_routes;; +esac +} + +queued_task=`echo $LINE | awk -F "." '{print $1,$2}'` +execute_task $queued_task +done < $jobfile.work + +rm $jobfile.work +fi + +bg_counter=$(expr $bg_counter + 1) + +sleep 1 +done +} + +fail_start_check(){ +local ipaddr +local gateway +local ifname +local group + +i=0 +while [ $i -lt $wancount ]; do +i=`expr $i + 1` +group=$(query_config group $i) +ifname=$(query_config ifname $group) +ipaddr=$(query_config ipaddr $group) +gateway=$(query_config gateway $group) + +if [ "$ifname" == "x" -o "$ipaddr" == "x" -o "$gateway" == "x" ]; then +failover add $group +wan_fail_map="echo $wan_fail_map $group[x]" +fi +done +} + +wancount=0 + +config_clear +config_load "multiwan" +config_get default_route config default_route +config_get resolv_conf config resolv_conf +config_get debug config debug + +config_foreach acquire_wan_data interface + +CHKFORQOS=`iptables -n -L Default -t mangle 2>&1 | grep "Chain Default"` + +jobfile="/tmp/.mwan.jobqueue" + +case $1 in + agent) silencer main_init;; + restart) silencer stop restart;; + stop) silencer stop;; +esac +