![]() |
#!/bin/bash
# makeroutes.sh - load balance two or more internet connections
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Written by Travis Morgan
# Basic idea taken from a script by Robert Kurjata Sep, 2003.
# Jul 2004 - 1.0
# May 21 2004 - 1.1 - greatly modularized
# Oct 5 2005 - 1.2 - include provisions for static addresses and improve network info detection
# Dec 12 2005 - 1.3 - allow external interfaces that are not load balanced
# Feb 1 2006 - 1.4 - removed Telus Interface Declarations
# Feb 5 2006 - 1.4.1 - start marking rules at 5 instead of 4 so iptables rules don't have to be adjusted
#########################################################################
#### User defined variables ####
#########################################################################
# define which interfaces will be load balanced
#LB_IFS=( eth0 eth1 )
#LB_IFS=( eth1 )
LB_IFS=( eth0 )
# weights of the load balanced interfaces - lower means more traffic
#WEIGHTS=( 1 2 )
WEIGHTS=( 1 )
# define all EXTERNAL interfaces to be configured
# internal interfaces should not appear in this because they don't get their own routing table.. they instead hit the multipath table
#EXT_IFS=( eth0 eth1 )
EXT_IFS=( eth0 )
#EXT_IFS=( eth2 )
# define the interfaces that need to get their address from dhcp
#DHCP_IFS=( eth1 )
# define the interfaces that need static addresses set
STATIC_IFS=( eth0 )
# define the ips for static interfaces
STATIC_IPS=( 216.194.110.140 )
# define the netmasks for static interfaces
STATIC_NMS=( 255.255.255.0 )
# define the broadcasts for static interfaces
STATIC_BCS=( 216.194.110.255 )
# define the gateways (if any) for static interfaces
STATIC_GWS=( 216.194.110.1 )
# you can adjust the coloring with these
COLOR="[33m[1m"
NOCOLOR="[0m"
# adjust these paths to be proper for your system
IP=/sbin/ip
WHATMASK=/usr/bin/whatmask
DHCPCD=/sbin/dhcpcd
DHCPCD_OPTS="-n"
IFCONFIG=/sbin/ifconfig
ROUTE=/sbin/route
LOWMARK=4 # the lowest interface will be seeing packets marked with 0x4
# LOGFILE="2>>/var/log/makeroutes.log" # log to a file
LOGFILE="" # log to stdout and stderr
#########################################################################
#### Get dhcp on external interfaces that require it ####
#########################################################################
echo "${COLOR}Getting DHCP on ${#DHCP_IFS[@]} interfaces..${NOCOLOR}"
for ((i=0; $i < ${#DHCP_IFS[@]} ; i++)); do
${DHCPCD} ${DHCPCD_OPTS} ${DHCP_IFS[$i]}
done
#########################################################################
#### Set the static address on interfaces that require it ####
#########################################################################
echo "${COLOR}Setting static addresses on ${#STATIC_IFS[@]} interfaces..${NOCOLOR}"
for ((i=0; $i < ${#STATIC_IFS[@]} ; i++)); do
if [[ ! ${STATIC_IFS[$i]} =~ ':' ]]
then
echo ${IFCONFIG} ${STATIC_IFS[$i]} down
${IFCONFIG} ${STATIC_IFS[$i]} down
fi
echo ${IFCONFIG} ${STATIC_IFS[$i]} ${STATIC_IPS[$i]} netmask ${STATIC_NMS[$i]} broadcast ${STATIC_BCS[$i]}
${IFCONFIG} ${STATIC_IFS[$i]} ${STATIC_IPS[$i]} netmask ${STATIC_NMS[$i]} broadcast ${STATIC_BCS[$i]}
done
#########################################################################
#### Gather network information ####
#########################################################################
echo "${COLOR}The following ${#EXT_IFS[@]} interfaces have been configured..${NOCOLOR}"
for ((i=0; $i < ${#EXT_IFS[@]} ; i++)) ; do
# we must check if it's dhcp or static
isdhcp="false"
for ((j=0; $j < ${#DHCP_IFS[@]} ; j++)) ; do
if [ "${DHCP_IFS[$j]}" = "${EXT_IFS[$i]}" ] ; then
isdhcp="true";
fi
done
if [ "${isdhcp}" = "true" ] ; then
# get ip address
EXT_IPS[$i]=`${IFCONFIG} | grep ${EXT_IFS[$i]}\ -A 1 | tail -n 1| awk -F: {'print $2'} | awk {'print $1'}`
# get netmask
EXT_NMS[$i]=`${ROUTE} -n | grep ${EXT_IFS[$i]} | grep -v -e '^0.0.0.0' | awk {'print $3'}`
# convert netmask to / notation
EXT_NMS[$i]=`${WHATMASK} ${EXT_NMS[$i]} | grep CIDR | awk -F/ {'print $2'}`
# calculate gateway
EXT_GWS[$i]=`${WHATMASK} ${EXT_IPS[$i]}/${EXT_NMS[$i]} | grep "First Usable" | sed -e 's/.*: \([0-9].*\)/\1/'`
else
# find the index number in the static array
static_index=0
for ((j=0; $j < ${#STATIC_IFS[@]} ; j++)) ; do
if [ "${STATIC_IFS[$j]}" = "${EXT_IFS[$i]}" ] ; then
static_index=$j
fi
done
# now we can add the interface info to EXT
EXT_IPS[$i]=${STATIC_IPS[$static_index]}
# convert and assign the netmask in / notation
EXT_NMS[$i]=`${WHATMASK} ${STATIC_NMS[$static_index]} | grep CIDR | awk -F/ '{print $2}'`
EXT_GWS[$i]=${STATIC_GWS[$static_index]}
fi
EXT_NWS[$i]=`${WHATMASK} ${EXT_IPS[$i]}/${EXT_NMS[$i]} | grep ^Network | sed -e 's/.*: \(.*\)/\1/'`
echo -n "${COLOR}*${NOCOLOR} ${EXT_IFS[$i]} ${EXT_IPS[$i]} netmask /${EXT_NMS[$i]}"
if [ "${EXT_GWS[$i]}" != "" ]
then
echo " gw ${EXT_GWS[$i]}"
else
echo
fi
done
#########################################################################
#### Remove default routes set by dhcp ####
#########################################################################
echo "${COLOR}Removing default routes from table main..${NOCOLOR}"
${IP} route show table main | grep ^default | while read LINE ; do
echo ${IP} route del "$LINE" table main
#${IP} route del "$LINE" table main
echo ${IP} route del default
${IP} route del default
done
#########################################################################
#### Flush rules and tables ####
#########################################################################
echo "${COLOR}Removing old rules and flushing tables..${NOCOLOR}"
${IP} rule | while read LINE ; do
prio=`echo $LINE | awk -F\: '{print $1}'`
if [ $prio -eq 50 ] ; then
${IP} rule del prio $prio table main ${LOGFILE}
elif [ $prio -ge 100 ]&&[ $prio -le 120 ] ; then
${IP} rule del prio $prio ${LOGFILE}
${IP} route flush table $prio ${LOGFILE}
elif [ $prio -ge 200 ]&&[ $prio -le 220 ] ; then
ruleip=`echo $LINE | awk -F\ '{print $3}'`
${IP} rule del prio $prio from $ruleip table $prio ${LOGFILE}
${IP} route flush table $prio ${LOGFILE}
elif [ $prio -eq 221 ] ; then
${IP} rule del prio $prio table $prio ${LOGFILE}
${IP} route flush table $prio ${LOGFILE}
fi
done
#########################################################################
#### Create new rules for marked packets ####
#########################################################################
echo "${COLOR}Building new route rules and tables..${NOCOLOR}"
echo "${COLOR}*${NOCOLOR} rule main"
${IP} rule add prio 50 table main ${LOGFILE}
for (( i=0; $i < ${#EXT_IFS[@]} ; i++ )); do
# we must check if it's supposed to be load balanced
isbalanced="false"
for ((j=0; $j < ${#LB_IFS[@]} ; j++)) ; do
if [ "${LB_IFS[$j]}" = "${EXT_IFS[$i]}" ] ; then
isbalanced="true";
fi
done
if [ "$isbalanced" == "true" ]
then
echo "${COLOR}*${NOCOLOR} rule/table $(( 100 + $i )) (force mark $(( $LOWMARK + $i )) packets to ${EXT_IFS[$i]})"
${IP} rule add prio $(( 100 + $i )) fwmark $(( $LOWMARK + $i )) table $(( 100 + $i )) ${LOGFILE}
${IP} route show table main | grep -Ev ^default | while read LINE ; do
${IP} route add table $(( 100 + $i )) $LINE ${LOGFILE}
done
${IP} route add table $(( 100 + $i )) default via ${EXT_IPS[$i]} ${LOGFILE}
fi
done
#########################################################################
#### Force traffic coming from an address in one of our ####
#### external link scopes to go out the correct interface ####
#########################################################################
for (( i=0; $i < ${#EXT_IFS[@]} ; i++ )); do
echo "${COLOR}*${NOCOLOR} rule/table $(( 200 + $i )) (${EXT_IFS[$i]})"
${IP} rule add prio $(( 200 + $i )) from ${EXT_NWS[$i]}/${EXT_NMS[$i]} table $(( 200 + $i )) ${LOGFILE}
${IP} route add default `if [ "${EXT_GWS[$i]}" != "" ] ; then echo via ${EXT_GWS[$i]} ; fi` dev `echo ${EXT_IFS[$i]}|awk -F: '{print $1}'` src ${EXT_IPS[$i]} proto static table $(( 200 + $i )) ${LOGFILE}
${IP} route append prohibit default table $(( 200 + $i )) metric 1 proto static ${LOGFILE}
done
#############################################################################
#### Create Multipath Table (for inside traffic bound for the internet) ####
#############################################################################
echo "${COLOR}*${NOCOLOR} 221 (multipath)"
${IP} rule add prio 221 table 221 ${LOGFILE}
multistring=""
for (( i=0; $i < ${#EXT_IFS[@]} ; i++ )); do
# we must check if it's supposed to be load balanced
isbalanced="false"
for ((j=0; $j < ${#LB_IFS[@]} ; j++)) ; do
if [ "${LB_IFS[$j]}" = "${EXT_IFS[$i]}" ] ; then
isbalanced="true";
fi
done
if [ "$isbalanced" == "true" ]
then
multistring="${multistring} nexthop via ${EXT_GWS[$i]} dev ${EXT_IFS[$i]} weight ${WEIGHTS[$i]}"
fi
done
${IP} route add default table 221 proto static ${multistring} ${LOGFILE}
#########################################################################
#### Flush routing cache and test connectivity ####
#########################################################################
echo "${COLOR}Flushing route cache..${NOCOLOR}"
${IP} route flush cache ${LOGFILE}
echo "${COLOR}Pinging gateways..${NOCOLOR}"
for (( i=0; $i < ${#EXT_IFS[@]} ; i++ )); do
if [ "${EXT_GWS[$i]}" != "" ]
then
echo "${COLOR}*${NOCOLOR} `ping -c 1 ${EXT_GWS[$i]} | grep 'bytes\ from'`"
fi
done
|
![]() |