Fault tolerance su Mikrotik

Stanco degli approcci limitati e poco parametrici mi sono messo al lavoro.

Dopo una estate di prove ecco lo script per la fault tolerance su Mikrotik.

L’idea è semplice:

– ho un router mikrotik

– su questo router ho N connettività (adsl, 3g, satellite,…)

– su questo router ho una rete LAN

– voglio che la rete LAN navighi in internet

– voglio che l’uscita sia automaticamente direzionata sull’uscita migliore (nell’ordine)

Fin qui niente di strano. Basta usare le distanze nelle varie rotte di default. Ma….

– se una connessione ha un ip dinamico? La rotta è fornita e ha sempre distanza pari a uno.

– se una connessione è funzionante verso il router adiacente ma fallisce all’interno della rete del provider?

Volevo uno script che fosse il più parametrico possibile.

Eccolo!

Il funzionamento è semplice.

Prendo un router Mikrotik.

Collego nella porta N la mia rete LAN e la configuro come solito. Se voglio metto il DHCP server, il DNS,…

Collego nella porta 1 la prima connessione. Configuro questa connessione affinchè funzioni la navigazione ad internet (metto la rotta se ho in ip statico, metto il masquerade,…).

Quando la prima connessione funziona e la rete LAN naviga stacco la prima connessione e procedo con la seconda.

Collego la seconda connessione e la configuro affinchè funzioni la navigazione ad internet (metto la rotta se ho in ip statico, metto il masquerade,…).

Procedo in questo modo con tutte le connessioni che ho a disposizione.

A questo punto copio lo script (System > Script)e lo metto in esecuzione ogni secondo (System > Schedule).

L’unica configurazione necessaria è cambiare la riga :local wanInterfaces “wan1,wlan1,wan3,3g”; indicando i nomi delle interfacce che ho usato (le connessioni) nell’ordine che desidero vengano utilizzate.

`

Multi interfaces fault tolerance (with or without dhcp)

Vittore Zen (http://www.zen.pn.it)

#

Instructions:

1. Configure router as usual.

2. Check that when only a single wan is connect you must browse internet. E.g. disconnect all wans, connect wan2 and check connection from your client.

2. Set variable wanInterfaces in script with all wans interface names. Order is relevant.

3. Put script in scheduler every 1 sec.

All done.`

:local wanInterfaces “wan1,wlan1,wan3,3g”;

### ###

### Don’t modify below ###

### ###

:local PingTarget 8.8.8.8

:local intfinder “”

:local gw “”

:local wanInterfacesArray [:toarray $wanInterfaces];

:local distance “”

:local tag “Created by zen-ft script”

:local mark2

:local i

:local mark

#

# function that find interface associated to a route

#

:local getRouteInterface do={

:local intfinder “”

:set $intfinder [:tostr [/ip route get number=$1 value-name=gateway-status]]

:set $intfinder [:pick $intfinder ([:find $intfinder “via”]+5) [:len $intfinder]]

:return $intfinder

}

#

# function that replace a value in an array

#

:local replaceValue do={

:local array $1

:local position $2

:local newValue $3

:for i from=0 to=([:len $array]-1) do={

:if ($i=$position) do={

:if ($i=0) do {

:set $newArray {$newValue}

} else {

:set $newArray ($newArray, $newValue)

}

} else {

:if ($i=0) do {

:set $newArray { [:pick $array $i]}

} else {

:set $newArray ($newArray, [:pick $array $i])

}

}

}

:return $newArray

}

#

# Check default routes and market routes (if needed)

#

:foreach counter in=[/ip route find dst-address=0.0.0.0/0 disabled=no comment!=$tag] do={

:set $intfinder [$getRouteInterface $counter]

:put (“interface: “.$intfinder)

:set $ftPos [:find $wanInterfacesArray $intfinder]

:if ($ftPos!=-1) do={

:set distance ($ftPos+1)

:put (“distance: “.$distance);

:foreach counter2 in=[/ip route find dst-address=0.0.0.0/0 disabled=no] do={

:set $intfinder2 [$getRouteInterface $counter2]

:if ($intfinder2=$intfinder) do={

:set gw [ /ip route get number=$counter2 value-name=gateway]

/ip route add dst-address=0.0.0.0/0 disabled=no distance=$distance gateway=$gw comment=$tag

/ip route add dst-address=0.0.0.0/0 disabled=no distance=$distance gateway=$gw comment=$tag routing-mark=$intfinder

/ip route remove numbers=$counter2

}

}

}

}

:for i from=0 to=([:len $wanInterfacesArray]-1) do={

:set $mark [:pick $wanInterfacesArray $i]

:put (“mark: “.$mark)

:foreach counter2 in=[/ip route find dst-address=0.0.0.0/0 disabled=no ] do={

:set mark2 [ /ip route get number=$counter2 value-name=routing-mark]

:if ($mark2=$mark) do={

:set $PingResult [ping $PingTarget count=1 routing-table=$mark]

:set gw [ /ip route get number=$counter2 value-name=gateway]

:put (“gw: “.$gw)

:foreach counter3 in=[/ip route find dst-address=0.0.0.0/0 disabled=no gateway=$gw ] do={

:if ($PingResult = 0) do={

:set $distance ($i+1)

} else {

:set $distance (10*($i+1))

}

/ip route set number=$counter3 distance=$distance

}

}

}

}

Una nota.

Molti script che si trovano in rete usano l’approccio del ping sull’interfaccia (/ping interface=wan3 8.8.8.8). Ma questo non funziona. Come si legge nel manuale RouterOS il parametro interfaccia funziona solo se l’host utilizzato è ipv6. Quindi tutti questi script non funzionano se non in casi particolari.

Ovviamente sono benvenuti tutti i miglioramenti a questo script.