#!/bin/sh # izbalancing is a GNU/Linux Firewall/Router Bash Script feauturing Incoming/Outgoing MultiHomed/LoadBalanced Subsystem Management # Written by Ugo Viti # Visit http://www.initzero.it for commercial support VERSION="20050712" # description: InitZero GNU/Linux Firewall/Router Incoming/Outgoing MultiHomed/LoadBalanced Subsystem # chkconfig: 35 99 10 # ---------------------------------------------------------------------------- # # Copyright (C) 2005 Ugo Viti # # 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 # # ---------------------------------------------------------------------------- # For ChangeLog and Contributors go to the end of this script # What is this? # ============= # This bash script allow you to easly and fastly configure a complex Load Balancing Multi Homed Internet Gateway # for inbound and outbound traffic # Key Features: # ============= # - Multiple Balanced Default Gateway Configuration # - Load Balanced outgoing connections from LAN to INTERNET connections # - Management of multiple incoming connection from many INTERNET ISP lines to DMZ/LAN Servers # - SystemV compliant script... you can run easly at boot up (like Red Hat, Fedora, SuSE, Mandrake, etc...) # - Automatically discover your local IP addresses... you can change your IP without reconfigure this script, just restart # - Start and Stop Cleanly your MultiHomed Configuration with simple command (izbalancing start|stop|restart) # - Adding new Internet Connections is very easy and fast # - You only must know the TABLE ID to assign to the new line, Ethernet Name of your NIC, and the Router IP Address # Requirements: # ============= # - GNU/Linux Firewall running Kernel >=2.6.10 (with iptables module CONNMARK available) # - Bash Shell >= 2.0 # - Standard GNU/Linux coreutils utilities (cat, echo, grep, if, etc...) # - GNU Version of awk and sed utilities # - GNU/Linux Netfilter user space utilities (iptables >= 1.2.11) # - iproute2 utilities # - Two or more Internet connections (also from different ISPs and IP classes) # - An ethernet card for each ISP Router # Tested On: # ========== # - GNU/Linux Fedora Core 3 with 2 Internet Connections # - GNU/Linux Fedora Core 4 with 2 Internet Connections # Script Usage: # ============= # 1) Configure or add the following variables: # TABLEn = Table number of internet connection 'n' # IFn = The Ethernet Interface name of internet connection 'n' # GWn = The Router IP Address of Internet connection 'n' # 2) Add a line for each internet connection in the izbalancing function # 3) Modify the command "ip route add default equalize nexthop via ..." adding all ISP's Routers IP # 4) Comment out the iptables rules # 5) Save this file and execute it a boot time (for Red Hat systems you can copy this script in /etc/rc.d/init.d/ directory # and launch 'chkconfig --add izbalancing') # That's all... # Network Topology Example: # ========================= # # +----------+ +-------------------+ 192.168.254.254+----------+ +-------+ # | Server x +<--+ | 192.168.254.1:eth1+<--------------->+ Router 1 +<----------->+ ISP 1 +<--+ # +----------+ | | | +----------+ ADSL line 1 +-------+ | # | | GNU/Linux | | # +----------+ | 192.168.1.1:eth0| | 192.168.253.254+----------+ +-------+ | # | Server y +<--+---+LAN+---------->+ 192.168.253.1:eth2+<--------------->+ Router 2 +<----------->+ ISP 2 +<--+---->INTERNET # +----------+ | | | +----------+ HDSL line 2 +-------+ | # | | Firewall | | # +----------+ | | | 192.168.nnn.nnn+----------+ +-------+ | # | Server z +<--+ | 192.168.nnn.n:ethn+<--------------->+ Router n +<----------->+ ISP n +<--+ # +----------+ +-------------------+ +----------+ T3 line n +-------+ # Mandatory variables TABLE1=1 # The TABLE ID associated to your 1st ISP IF1=eth1 # The NIC name connected to your 1st ISP GW1=192.168.254.254 # 1st or Default Internet Service Provider Gateway (Router IP Address) TABLE2=2 # The TABLE ID associated to your 2th ISP IF2=eth2 # The NIC name connected to your 2th ISP GW2=192.168.253.254 # 2th Internet Server Provider Gateway (Router IP Address) #TABLE2=n # The TABLE ID associated to your n.. ISP # This line is an example # IF2=ethn # The NIC name connected to your n... ISP # This line is an example # GW2=192.168.nnn.nnn # n... Internet Provider Gateway # This line is an example izbalancing() { # Command Syntax: $1 "InterfaceName" "TableID" "IPDefaultGateway" # Add a Command line for any external internet connection $1 $IF1 $TABLE1 $GW1 $1 $IF2 $TABLE2 $GW2 #$1 $IFn $TABLEn $GWn # This line is an example if [ "$1" = "start" ] then # Misc $IP route del default $IP route add default equalize nexthop via $GW1 nexthop via $GW2 #$IP route add default equalize nexthop via $GW1 nexthop via $GW2 nexthop via $GWn # ...so on... ## NOTE!! # You must execute the following iptables rules if you want act as Load Balanced/MultiHomed GNU/Linux Firewall # > mangle table < # $IPTABLES -t mangle -A PREROUTING -p ALL -j CONNMARK --restore-mark # $IPTABLES -t mangle -A PREROUTING -p ALL -i $IF1 -m mark --mark 0 -j MARK --set-mark $TABLE1 # $IPTABLES -t mangle -A PREROUTING -p ALL -i $IF2 -m mark --mark 0 -j MARK --set-mark $TABLE2 # $IPTABLES -t mangle -A PREROUTING -p ALL -i $IFn -m mark --mark 0 -j MARK --set-mark $TABLEn # This line is an example # $IPTABLES -t mangle -A POSTROUTING -p ALL -o $IF1 -m state --state NEW -j MARK --set-mark $TABLE1 # $IPTABLES -t mangle -A POSTROUTING -p ALL -o $IF2 -m state --state NEW -j MARK --set-mark $TABLE2 # $IPTABLES -t mangle -A POSTROUTING -p ALL -o $IFn -m state --state NEW -j MARK --set-mark $TABLEn # This line is an example # $IPTABLES -t mangle -A POSTROUTING -p ALL -m state --state NEW -j CONNMARK --save-mark # > nat table < # $IPTABLES -t nat -A POSTROUTING -p ALL -o $IF1 -m mark --mark $TABLE1 -j SNAT --to-source $(find_primary_ip $IF1) # $IPTABLES -t nat -A POSTROUTING -p ALL -o $IF2 -m mark --mark $TABLE2 -j SNAT --to-source $(find_primary_ip $IF2) # $IPTABLES -t nat -A POSTROUTING -p ALL -o $IFn -m mark --mark $TABLEn -j SNAT --to-source $(find_primary_ip $IFn) # This line is an example fi } # Default commands path IP=/sbin/ip IPTABLES=/sbin/iptables ############################################################################################### ############################################################################################### ## CONFIGURATION IS OVER, DON'T EDIT ANYTHING BELLOW ## ############################################################################################### ############################################################################################### ### $1 = Ethernet Interface Name ### $2 = Table Number ### $3 = Default Gateway # Init default policies and variables init() { # Enable fast failover of broken gateways links (this isn't a real failover) echo "10" > /proc/sys/net/ipv4/route/gc_timeout # Make this machine a Routing Machine(tm) :-) echo "1" > /proc/sys/net/ipv4/ip_forward # Variables IF=$1 TABLE=$2 FWIP=$(find_primary_ip $IF) GWIP=$3 #echo "Init: IF=$IF TABLE=$TABLE FWIP=$FWIP GWIP=$GWIP IP=$IP" } ## STOP # Stop izbalancing stop() { init $1 $2 $3 route_stop rule_stop } # Reset routing tables route_stop() { # Flush whole routing table of current table if [ ! -z "$($IP route show table $TABLE)" ] then $IP route flush table $TABLE fi # Reset to default Single Gateway if [ ! -z "$GW1" ] then $IP route del default $IP route add default via $GW1 fi # If you don't want to reset the routing cache every time you run this script, comment the following line $IP route flush cache } # Reset rule tables rule_stop() { # Flush whole rule table of current table (except for fwmark rules) $IP rule list | grep "lookup $TABLE" | grep -v "from all fwmark" | awk '{print $2" "$3" "$4" "$5" "$6" "$7}' $1 | while read RULE do $IP rule del $RULE done # Flush whole fwmark rule table of current table $IP rule list | grep "lookup $TABLE" | grep "from all fwmark" | awk '{print $4" "$5" "$6" "$7}' $1 | while read RULE do $IP rule del $RULE done } ## START # Start izbalancing Subsystem start() { #echo "1 Before init ($1 $2 $3)" init $1 $2 $3 #echo "2 Before stop ($1 $2 $3)" stop $1 $2 $3 #echo "3 Before route_start ($1 $2 $3)" route_start #echo "4 Before rule_start ($1 $2 $3)" rule_start } route_start() { # Import from table 'default' to 'current table' the whole routing settings $IP route show table main | grep -Ev ^default | grep -Ev nexthop | while read ROUTE; do $IP route add table $TABLE $ROUTE; done # Add the default interface gateway to the current table $IP route add table $TABLE default via $GWIP } # Add iproute2 rules in current table rule_start() { $IP rule add from $FWIP lookup $TABLE $IP rule add fwmark $TABLE lookup $TABLE for IP_ALIAS in $(find_secondary_ip $IF) do $IP rule add from $IP_ALIAS lookup $TABLE done } ######################################################### # Autodetect IP number of specified network interface find_primary_ip() { if [ ! -z $1 ] then echo $($IP addr show $1 | grep 'inet' | grep -v ":" | awk '{print $2}' | sed -e 's/\/.*//') fi } find_secondary_ip() { if [ ! -z $1 ] then echo $($IP addr show $1 | grep 'inet' | grep "$1:" | awk '{print $2}' | sed -e 's/\/.*//') fi } ############################################################################################### ## Valid script input from command line case $1 in stop) izbalancing stop ;; start) izbalancing start ;; restart) izbalancing start ;; *) echo "InitZero GNU/Linux Firewall/Router Incoming/Outgoing MultiHomed/LoadBalanced Subsystem" echo "Written by Ugo Viti " echo "Version $VERSION" echo echo "Usage: $0 [OPTIONS]" echo echo "Available Options:" echo " start, Start the izbalancing subsystem" echo " stop, Stop the izbalancing subsystem" echo " restart, ReStart the izbalancing subsystem" echo echo " example: $0 start" exit 0 esac ## The End ############################################################################################### # ChangeLog: # ========== # 20050712 - Some Cleanups # 20050708 - First Version # # ToDo: # ===== # - Suggestions are welcome :-) # # Contributors: # ============= # - If you want help me enanching this script, please send patchs to my email address. # # Thanks: # ======= # - Many thanks to "Nguyễn Đình Nam" of for your fantastic tips! #