HowTo: 2 WAN-Verbindungen (Dual-WAN) mit Tomato

Hier findet man häufig gestellte Fragen und deren Antworten (sogenante FAQs) sowie HOWTOs, Infos und Anleitungen.
Forumsregeln
Hier findet man häufig gestellte Fragen und deren Antworten (sogenante FAQs) sowie HOWTOs, Infos und Anleitungen.

Es sind keine Diskussionen in diesem Bereich möglich. Wenn ihr Fragen zu den FAQs oder HOWTOs habt, dann stellt diese im entsprechenden Fachbereich des Forums.

HowTo: 2 WAN-Verbindungen (Dual-WAN) mit Tomato

Beitragvon 12woody » Mo 06 Sep, 2010 14:45

Hallo!

Ich nutze seit einiger Zeit einen 2. DSL-Zugang als Backup und wollte diesen unter einen Hut mit dem schon bestehenden ursprünglichen Zugang bringen.


In meinem LAN nutze ich einen Router ähnlich dem allseits beliebten Linksys WRT54G mit Tomato-Firmware. Da diese Router bzw. auch die dafür erhältlichen Firmwares prinzipiell nur für die Nutzung eines Internet-Zugangs ausgelegt sind, habe ich mein System entsprechend angepasst, um beide Internetverbindungen gleichzeitig und parallel nutzen zu können.

Da das Vorhaben in Summe nicht ganz so trivial war, lt. Infos im Internet aber immer wieder mal Interesse so einem DualWAN-Router besteht, habe ich mich entschlossen hier ein kleines HowTo zu schreiben.


HOWTO: Zeitgleicher Betrieb 2er Internet-Verbindungen mit Tomato (Dual-WAN)

Einleitung

Was ermöglicht diese DUAL-WAN-Lösung:
  • Anbinden eines 2. WAN-Uplinks (zB 2. Modem eines 2. Zugangs) an einen Tomato-Router
  • Ãœbernahme der Remote-Services (SSH, Remote-Webinterface) auf das 2. WAN-Interface (damit sind die Dienste auch über die IP des 2. Zugangs erreichbar)
  • Ãœbernahme der Portforwarding-Einstellungen auf das 2. WAN-Interface
  • Optional aktivierbar: Round Robin Load-Balancing
  • Optional konfigurierbar: Definierbares statisches Routing für bestimmte Verbindungen (zB Verbindungen zum Firmen-VPN-Server generell immer über das 2. Modem, da dieser Zugang zB die erforderliche fixe IP hat)
  • Zukünftig / in Arbeit: Failover-Mechanismus: Umlenken des Traffics auf den Ersatz-Zugang, sobald einer ausfällt

Was klappt mit dieser Modifizierung NICHT:
  • QOS - habe ich im DUAL-WAN-Betrieb noch nicht aktiviert --> Lösung: Ausweichen auf TCP Vegas, od. Erweiterung der Scripts weiter unten um QOS-Unterstützung
  • Volle Anzahl Switch-Ports - leider muss einer der Ethernet-Ports vom LAN-seitigen Switch entkoppelt werden, um daran das Modem des 2. Internet-Zugangs zu betreiben. Die Anzahl der LAN-Ports vermindert sich so um 1

Voraussetzungen:
  • TomatoUSB (es reicht die Mini-Version)- leider fehlt der ursprünglichen Version von Tomato die MULTIPATH-Option im verwendeten Kernel, d.h. für den Dual-WAN-Betrieb muss auf TomatoUSB ausgewichen werden, welches die erforderliche Unterstützung im Kernel mit ein kompiliert hat
  • Tomato-kompatibler Router - für das System sind alle Tomato-kompatiblen Router geeignet, sowie einige "exklusiv" von TomatoUSB unterstützten Modelle; Ãœbersicht: http://tomatousb.org/doc:build-types
  • 2 Modems / Router für die Internet-Zugänge, ansprechbar über verschiedene IP-Adressen in verschiedenen Subnetzen (sind entsprechend zu konfigurieren)
  • Optional: Portworwarding auf den Internet-Routern aller Ports auf den jeweils mit dem Modem verbundenen WAN-Port des Tomato-Routers - falls der Router bzw. das eigene LAN von außen erreichbar sein soll; Anmerkung: Meine Speedtouch 585v7 zicken herum, wenn ich alle Port weiterleite. Ich leite deshalb jeweils die Ports 1-65000 (UDP und TCP) an den WAN-Port des Tomto-Routers weiter --> ein guter Kompromiss

Ãœbersicht Netzwerk-Aufbau

Code: Alles auswählen
                                                                           /--------------\
                                                                           |              |
                                                              10.0.0.138/24| ST585 v7     |IP1
                                                            ---------------|              |---
                  /------------------------\               / PF 1-65000    | DSL 1        |
                  |                        |  10.0.0.1/24 /   -> 10.0.0.1  |              |
                  |         Linksys        |--------------                 \--------------/
                  |        WRN2000v2       |    vlan1
    192.168.0.1/24|                        |                               /--------------\
   ---------------|        Firmware        |  10.1.0.1/24                  |              |
    br0 ((W)LAN)  |     TomatoUSB-Mod      |--------------\   10.1.0.138/24| ST585 v7     |IP2
                  |   www.tomatousb.org    |    vlan2      \---------------|              |---
                  |                        |                 PF 1-65000    | DSL 2        |
                  \------------------------/                  -> 10.1.0.1  |              |
                                                                           \--------------/



Einrichtung

1. Vorbereitung / Einrichtung 2. WAN-Port
Wie oben schon angeführt wird einer der Ethernet-Ports die ursprünglich für das LAN verwendet werden, der Port zum Verbinden des 2. Internet-Modems.
Ich hab mich bei mir für den Port unmittelbar neben dem WAN-Port entschieden (bei den LEDs am Gerät als Port 4 bezeichnet)

Um dem Switch einen Ethernet-Port wegzunehmen, sehen wir uns erst mal die aktuelle Port-Zuweisung für die LAN-Schnittstelle (Switch) an:

Code: Alles auswählen
root@router:/tmp/home/root# nvram get vlan0ports
4 3 2 1 5*


Bei meinem Router war der vorletzte Port (1) jener unmittelbar nebem dem WAN-Interface (Achtung: Hier ist er als "1" bezeichnet, auf der Vorderseite des Gehäuses (LEDs) in umgekehrter Reihenfolge als "4")

Je nach Routermodell könnte der Port neben dem WAN-Interface auch der erste in der obigen Liste sein. Ist man sich nicht ganz sicher muss man probieren - es sollte aber meines Wissens nach entweder der 1. in der Liste oder der vorletzte Port in der Liste sein. Natürlich steht die Wahl des zu verwendeten LAN-Ports einem völlig frei - ich allerdings habe mich für den neben dem WAN-Port entschieden.

Hat man sich für einen Port entschieden (in meinem Fall die Nr. "1" lt. obiger Liste), so muss dieser nun aus dem LAN-Switch ausgehängt werden.
Code: Alles auswählen
nvram set vlan0ports="4 3 2 5*"


Danach wird gleich noch ein neues Netzwerk-Interface angelegt + der soeben freigemacht Port dem neuen Device zugewiesen --> das ist später das 2. WAN-Device.
Code: Alles auswählen
nvram set vlan2ports="1 5"
nvram set vlan2hwname=et0
nvram set wan2_ifname=vlan2


Im Anschluss daran setzen wir gleich noch die IP-Konfiguration für das neue WAN-Interface, die in weitere Folge dann von den Init-Scripts weiter unten ausgelesen wird.
Code: Alles auswählen
nvram set wan2_ipaddr="10.1.0.1"
nvram set wan2_netmask="255.255.255.0"
nvram set wan2_gateway="10.1.0.138"
nvram set wan2_dns="10.1.0.138"


Zum Abschluss noch ein
Code: Alles auswählen
nvram commit


Damit wäre die Konfiguration auf der Shell abgeschlossen. Nach einem Reboot wird diese übernommen und ifconfig -a sollte bereits ein zusätzliches Netzwerk-Interface "vlan2" anzeigen (das zu diesem Zeitpunkt allerdings noch nicht konfiguriert und aktiv ist)


2. Aktivierung DUAL-WAN-Betrieb

Nun zur eigentlichen Sache, der Inbetriebnahme der Dual-WAN-Fähigkeiten des Routers.
Dies geschieht ganz einfach über das Webinterface des Routers, im Bereich Administration / Scripts

Im Tab Firewall den folgenden Inhalt ablegen, mittels Copy/Paste (anderen Inhalt vorher löschen, falls vorhanden):
Code: Alles auswählen
#!/bin/sh

######################
#
# Script DUAL-WAN
# CORE
#
# for TomatoUSB 1.28
#
# Date: 2010-09-04
#
######################

####
##
## USER-CONFIG
##
####

### Enables (1) oder disables (0) kernel based
### load balancing between the 2 WAN connections
ENABLE_KERNEL_WAN_LOAD_BALANCING=1


####
##
## CONSTANTS
##
####

### Internal config
FOLDER_DUALWAN=/tmp/dualwan
FILE_DUALWAN_CONFIGURED=$FOLDER_DUALWAN/configured

SCRIPT_EXTENSION_NVRAM=script_shut
SCRIPT_EXTENSION_FS=$FOLDER_DUALWAN/dualwan_extension.sh

CONFIG_FILES_KERNEL_REVERSEPATH_FILTERING=/proc/sys/net/ipv4/conf/*/rp_filter

TABLE_WAN1=100
TABLE_WAN2=200

MARK_WAN1=0x100
MARK_WAN2=0x200

### NVRAM stored config
WAN_IFNAME=`nvram get wan_ifname`
WAN_IPADDR=`nvram get wan_ipaddr`
WAN_GATEWAY=`nvram get wan_gateway`
WAN_DNS=`nvram get wan_dns`

WAN2_IFNAME=`nvram get wan2_ifname`
WAN2_IPADDR=`nvram get wan2_ipaddr`
WAN2_NETMASK=`nvram get wan2_netmask`
WAN2_GATEWAY=`nvram get wan2_gateway`
WAN2_DNS=`nvram get wan2_dns`

LAN_IPADDR=`nvram get lan_ipaddr`

PORT_FORWARDING_CONFIGURATION=`nvram get portforward`

PING_FROM_WAN_BLOCKED=`nvram get block_wan`

HTTPD_REMOTE_ENABELD=`nvram get remote_management`
HTTPD_REMOTE_HTTPS_ENABLED=`nvram get remote_mgt_https`
HTTPD_WANPORT=`nvram get http_wanport`
HTTPD_LANPORT=`nvram get http_lanport`
HTTPD_LANPORT_HTTPS=`nvram get https_lanport`

SSHD_REMOTE_ENABLED=`nvram get sshd_remote`
SSHD_REMOTE_PORT=`nvram get sshd_rport`
SSHD_PORT=`nvram get sshd_port`


###
##
## Function library
##
###
configureWan2Device() {

   ### skip if already configured
   if test -e $FILE_DUALWAN_CONFIGURED;
   then
      return
   fi

   logger "Setting up second WAN-device: interface $WAN2_IFNAME, ip $WAN2_IPADDR, netmask $WAN2_NETMASK"

   ifconfig $WAN2_IFNAME $WAN2_IPADDR netmask $WAN2_NETMASK up

   mkdir -p `dirname $FILE_DUALWAN_CONFIGURED`
   touch $FILE_DUALWAN_CONFIGURED
}

expandRoutingTablesAndRules() {

   ### rules
   ip rule flush

   ip rule add lookup main prio 32766
   ip rule add lookup default prio 32767

   ip rule add from $WAN_IPADDR table $TABLE_WAN1 prio 100
   ip rule add fwmark $MARK_WAN1 table $TABLE_WAN1 prio 101

   ip rule add from $WAN2_IPADDR table $TABLE_WAN2 prio 200
   ip rule add fwmark $MARK_WAN2 table $TABLE_WAN2 prio 201

   ### routing tables
   ip route flush table $TABLE_WAN1 >/dev/null 2>&1
   ip route flush table $TABLE_WAN2 >/dev/null 2>&1

   for TABLE in $TABLE_WAN1 $TABLE_WAN2
   do
         ip route | grep link | while read ROUTE
         do
              ip route add table $TABLE to $ROUTE
         done
   done

   ip route add table $TABLE_WAN1 default via $WAN_GATEWAY
   ip route add table $TABLE_WAN2 default via $WAN2_GATEWAY
}

expandIptables() {

   ### filter table
   checkIptablesFilterTableExpanded

   if [ $? -ne 0 ];
   then
      expandIptablesFilterTable
   fi

   ### nat table
   expandIptablesNatTable
}

checkIptablesFilterTableExpanded() {
   iptables --list -v |grep -q $WAN2_IFNAME
}

expandIptablesFilterTable() {

   iptables -I INPUT 2 -i br0 -d $WAN2_IPADDR -j DROP

   positionWanRules=`iptables --list FORWARD -v --line-numbers | grep -m 1 $WAN_IFNAME | sed -n "s/\([0-9]\+\).*/\1/p"`

   iptables -I FORWARD `expr $positionWanRules + 2` -i $WAN2_IFNAME -j wanin
   iptables -I FORWARD `expr $positionWanRules + 3` -o $WAN2_IFNAME -j wanout
}

expandIptablesNatTable() {

   lanNet=`iptables --list PREROUTING -v -t nat --line-numbers |sed -n "s/^1.* \(\([0-9]\{1,3\}\.\)\{3\}[0-9]\{1,3\}\/[0-9]\{2\}\)/\1/p"`

   iptables -t nat -I PREROUTING 2 -i $WAN2_IFNAME -d $lanNet -j DROP
   iptables -t nat -A POSTROUTING -o $WAN2_IFNAME -j MASQUERADE
}

enableDualWanRouting() {

   enableDualWanRoutingSetUpIptablesEntries
   enableDualWanRoutingConfigureKernelRpFilter
}

enableDualWanRoutingSetUpIptablesEntries() {

   ### Set connmark for new incoming (--> not already marked) connections according to their iface
   iptables -t mangle -A PREROUTING -i $WAN_IFNAME -m connmark --mark 0 -j CONNMARK --set-mark $MARK_WAN1
   iptables -t mangle -A PREROUTING -i $WAN2_IFNAME -m connmark --mark 0 -j CONNMARK --set-mark $MARK_WAN2

   ### Set packet mark from connmark for already marked (--> established and new incoming-> see rules obove) connections
   iptables -t mangle -A PREROUTING -m connmark ! --mark 0 -j CONNMARK --restore-mark
   iptables -t mangle -A OUTPUT -m connmark ! --mark 0 -j CONNMARK --restore-mark

   ### Set connmark if unmarked packages (--> packages of new connections) passing an WAN interface,
   ### according to the kernel made routing decision
   iptables -t mangle -A POSTROUTING -o $WAN_IFNAME -m connmark --mark 0 -j CONNMARK --set-mark $MARK_WAN1
   iptables -t mangle -A POSTROUTING -o $WAN2_IFNAME -m connmark --mark 0 -j CONNMARK --set-mark $MARK_WAN2
}

enableDualWanRoutingConfigureKernelRpFilter() {

   ### Disable reverse path filtering for all devices
   for rpFilterConfigFile in `ls $CONFIG_FILES_KERNEL_REVERSEPATH_FILTERING`;
   do
      echo 0 > $rpFilterConfigFile
   done
}

setUpRemoteServices() {

   ### Remote-Ping
   if [ $PING_FROM_WAN_BLOCKED -eq 0 ];
   then
      iptables -t nat -A PREROUTING -p icmp -d $WAN2_IPADDR -j DNAT --to $LAN_IPADDR
   fi

   ### Remote-Web-Access
   if [ $HTTPD_REMOTE_ENABELD -ne 0 ];
   then
      if [ $HTTPD_REMOTE_HTTPS_ENABLED -ne 0 ];
      then
         localWanHttpdPort=$HTTPD_LANPORT_HTTPS;
      else
         localWanHttpdPort=$HTTPD_LANPORT;
      fi

      iptables -t nat -A PREROUTING -p tcp --dport $HTTPD_WANPORT -d $WAN2_IPADDR -j DNAT --to $LAN_IPADDR:$localWanHttpdPort
   fi

   ### Remote-SSH
   if [ $SSHD_REMOTE_ENABLED -ne 0 ];
   then
      iptables -t nat -A PREROUTING -p tcp --dport $SSHD_REMOTE_PORT -d $WAN2_IPADDR -j DNAT --to $LAN_IPADDR:$SSHD_PORT
   fi
}


enablePortForwardingWan2() {

   oldIFS="$IFS"
   IFS=">"

   ### traverse each defined rule
   for portForwardingEntry in $PORT_FORWARDING_CONFIGURATION;
   do
      # parse current rule
      ruleEnabled=`echo $portForwardingEntry |cut -d "<" -f 1`
      protocol=`echo $portForwardingEntry |cut -d "<" -f 2`
      sourceAddress=`echo $portForwardingEntry |cut -d "<" -f 3`
      sourcePort=`echo $portForwardingEntry |cut -d "<" -f 4`
      destinationPort=`echo $portForwardingEntry |cut -d "<" -f 5`
      destinationAddress=`echo $portForwardingEntry |cut -d "<" -f 6`
      ruleName=`echo $portForwardingEntry |cut -d "<" -f 7`

      # skip disabled rules
      if [ "$ruleEnabled" -ne 1 ];
      then
         continue
      fi

      # deny forwarding of multiple ports --> not yet implemented
      if echo $sourcePort |grep -q -e "[:,]";
      then
         logger "Forwarding of multiple ports not yet implemented! NOT setting up forwarding rule $ruleName for 2nd WAN-device"
         continue
      fi      

      ### rewrite variables

      # source address
      if [ -z "$sourceAddress" ];
      then
         sourceAddress="0.0.0.0"
      fi

      # destination address
      if [ -z "$destinationPort" ];
      then
         destinationPort=$sourcePort
      fi


      ### set up iptables rules

      # tcp
      if [ $protocol -eq 1 -o $protocol -eq 3 ];
      then
         iptables -t nat -A PREROUTING -p tcp --dport $sourcePort -d $WAN2_IPADDR -j DNAT --to $destinationAddress:$destinationPort
      fi

      # udp
      if [ $protocol -eq 2 -o $protocol -eq 3 ];
      then
         iptables -t nat -A PREROUTING -p udp --dport $sourcePort -d $WAN2_IPADDR -j DNAT --to $destinationAddress:$destinationPort
      fi
   done

   IFS=$oldIFS
}

setUpKernelConnectionLoadBalancing() {

   if [ $ENABLE_KERNEL_WAN_LOAD_BALANCING -ne 0 ];
   then
      ip route change default scope global equalize nexthop via $WAN_GATEWAY dev $WAN_IFNAME nexthop via $WAN2_GATEWAY dev $WAN2_IFNAME
   else
      ip route change default via $WAN_GATEWAY dev $WAN_IFNAME
   fi

}

finalizeConfiguration() {

   ### Flush routing cache
   ip route flush cache
}


###
##
##   Execution
##
###

### Core config
configureWan2Device
expandRoutingTablesAndRules
expandIptables
enableDualWanRouting
setUpRemoteServices
enablePortForwardingWan2
setUpKernelConnectionLoadBalancing
finalizeConfiguration

### Extended external config
nvram get $SCRIPT_EXTENSION_NVRAM > $SCRIPT_EXTENSION_FS
chmod u+x $SCRIPT_EXTENSION_FS
$SCRIPT_EXTENSION_FS


Im Tab Shutdown den folgenden Inhalt ablegen, mittels Copy/Paste (anderen Inhalt vorher löschen, falls vorhanden):
Anmerkung: Das Script wird nicht tatsächlich beim Shutdown ausgeführt - die Ablage hier ist lediglich ein Workaround, da im Bereich Firewall die Scriptgröße auf insgesamt 8 KByte beschränkt ist; Das Script hier wird implizit vom Firewall-Script aufgerufen mit zur richtigen Zeit mit ausgeführt
Code: Alles auswählen
#!/bin/sh

######################
#
# Script DUAL-WAN
# EXTENDED CONFIG
#
# for TomatoUSB 1.28
#
# Date: 2010-09-04
#
######################

### This script is not intended to be executed from Tomato
if echo $0 |grep -q script;
then
   exit 0
fi


####
##
## USER-CONFIG
##
####

### List of destinations to be routed via a specific interface,
### delimited by ","
###
### Destination: IP, Port or IP:Port
### Example: 1.2.3.4,4.4.4.4:80,22

DESTINATIONS_WAN1=
DESTINATIONS_WAN2=1.2.3.4,8080,195.3.96.67:53


####
##
## CONSTANTS
##
####

MARK_WAN1=0x100
MARK_WAN2=0x200


###
##
## Function library
##
###
setUpStaticRouting() {

   if [ -z $1 -o -z $2 ];
   then
      return
   fi

   destinations=$1
   connectionMark=$2

   oldIFS=$IFS
   IFS=","

   for destination in $destinations;
   do
      if echo $destination |grep -q ":";
      then
         destinationIp=`echo $destination |cut -d ":" -f 1`
         destinationPort=`echo $destination |cut -d ":" -f 2`

         iptables -t mangle -I PREROUTING -p tcp -d $destinationIp --dport $destinationPort -m connmark --mark 0 -j CONNMARK --set-mark $connectionMark
         iptables -t mangle -I PREROUTING -p udp -d $destinationIp --dport $destinationPort -m connmark --mark 0 -j CONNMARK --set-mark $connectionMark

      else
         if echo $destination |grep -q "\.";
         then
            iptables -t mangle -I PREROUTING -d $destination -m connmark --mark 0 -j CONNMARK --set-mark $connectionMark
         else
            iptables -t mangle -I PREROUTING -p tcp --dport $destination -m connmark --mark 0 -j CONNMARK --set-mark $connectionMark
            iptables -t mangle -I PREROUTING -p udp --dport $destination -m connmark --mark 0 -j CONNMARK --set-mark $connectionMark
         fi
      fi
   done

   IFS=$oldIFS
}


###
##
##   Execution
##
###

setUpStaticRouting $DESTINATIONS_WAN1 $MARK_WAN1
setUpStaticRouting $DESTINATIONS_WAN2 $MARK_WAN2



3. Anpassung der Konfiguration
Die so hochgeladene Konfiguration kann nun noch den eigenen Wünschen entsprechend angepasst werden.

Das umfasst folgende Möglichkeiten:
  • Aktivierung/Deaktivierung Round Robin Load Balancing
  • Festlegen statischer Routen (Ziele zu denen immer über das selbe Modem verbunden wird)

Die Konfiguration ist jeweils zu Beginn der beiden Scripte anpassbar.

Round Robin Load Balancing
CORE-Script (Firewall-Tab)
Code: Alles auswählen
####
##
## USER-CONFIG
##
####

### Enables (1) oder disables (0) kernel based
### load balancing between the 2 WAN connections
ENABLE_KERNEL_WAN_LOAD_BALANCING=0


Static Routing
EXTENED CONFIG - Script (Shutdown-Tab)
Code: Alles auswählen
####
##
## USER-CONFIG
##
####

### List of destinations to be routed via a specific interface,
### delimited by ","
###
### Destination: IP, Port or IP:Port
### Example: 1.2.3.4,4.4.4.4:80,22

DESTINATIONS_WAN1=
DESTINATIONS_WAN2=1.2.3.4,8080,195.3.96.67:53

(Das Beispiel hier routet bestimmte Verbindungen immer über den 2. Internet-Zugang - die Konfiguration für den 1. bleibt jedoch leer --> also keine Verbindungen statisch über diese Leitung routen --> kann natürlich jederzeit geändert werden)


4. Abschluss

Nach einem Speichern der so im Webinterface angelegten Scripts und einem Reboot ist die Konfiguration aktiv. Fertig!


Anmerkungen

Für Wünsche, Anregungen und sonstige Vorschläge bin ich natürlich jederzeit offen - auch Ergänzungen und Anpassungen der Skripte werden gerne angenommen :ok:
12woody
Junior Board-Mitglied
Junior Board-Mitglied
 
Beiträge: 30
Registriert: Do 29 Jul, 2010 22:37

Zurück zu FAQs & HOWTOs

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 15 Gäste