Mikrotik failover

Gondoltam megosztom az elmenyeket errol a remek kis eszkozrol. Az egesz ugy kezdodott, hogy hazakoltoztem es "remote worker" lettem. Az elso ~24 oras UPC kieses utan ugy dontottem, hogy ez azert nem is annyira stabil es 24 oran keresztul 3g netrol tolni nem annyira jo, szoval kell egy backup vonal, meg is erkezett az adsl backup. Mindketton dinamikus ip, tanul default routeot mindket helyen, meg dnst sot meg arra is figyeltek, hogy melyik defaultnak mennyi legyen az admin distanceje. (lan-nal 0, pppoe-nel 1) szoval ez is mukodik out-of-the-box. Ebben megnyugodva, hogy majd automatan atvalt ha a upc atvalt hatradoltem miutan beallitottam egy kis pbr-t, hogy azert tudjam monitorozni a backup vonalat. Aztan ahogy az lenni szokott, jott a pofara eses.

Ugyanis upc meghalt de a modem/router kis izejuk osztotta az eszet es kozolte, hogy akkor nekem 192.168.0.101 lesz az ipcimem es 192.168.0.100-on keresztul tudom elerni az internetet:/ Szoval jott dhcp, volt benne default-gw meg minden. Hat fantasztikus gondoltam magamban es miutan kozolte a UPC kedves ugyfelszolgalata, hogy teruleti hiba van es a problemat probaljuk mihamarabb orvosolni gyorsan manulaba lelottem az interfacet, igy megvolt a failover de azert az megse modi, hogy halozati mernoknek manualisan kelljen a failovert megcsinalni, szoval elkezdtem bujni a netet, hogy megis mit lehetne csinalni. Hat rovid keresgeles utan jott a megoldas, scheduler es custom script. Na, hat egy kis kihivas, egy masik eddig egy uj scriptnyelv. Ilyennel meg nem talalkoztam, de ha a juniper slax scripttel megbirkoztam ez is menni fog. Kis keresgeles, sok script nezegetes utan eljutottam oda, hogy megtudom nezni, hogy egy "target" ip elerheto-e az adott interfacen keresztul es itt jott az elso sokk, hogy nem lehet dinamikus routeon distancet allitgatni:/. Van benne logika, valahol, melyen biztos, de most jol jott volna ha lehetne. Szoval akkor megint kis fejvakaras, hogy lehet megoldani, hogy teszt alapjan routoljunk ket dinamikusan tanult route kozott.

Hat erre talatam egy routing-mark nevu szerkezetet ami tulajdonkeppen mindenfele routeok megjelelolesere hasznalando de lehet kulonfele tuzfal szabalyokon is matchelni es taggelni vele. Szoval a kovetkezo tuzfal szabalyokat allitottam fel:


@MikroTik] > ip firewall nat print detail 
 0   chain=srcnat action=masquerade routing-mark=via_upc out-interface=UPC - port 5 
 1   chain=srcnat action=masquerade routing-mark=via_thome out-interface=pppoe-out1 
@MikroTik] > ip firewall mangle print detail     
 3   ;;; UPC - port 5
     chain=prerouting action=mark-routing new-routing-mark=via_upc passthrough=yes in-interface=bridge1 
 4 X ;;; pppoe-out1
     chain=prerouting action=mark-routing new-routing-mark=via_thome passthrough=yes in-interface=bridge1 

Ami tulajdonkeppen nem csinal mast mint megjeloli a bejovo csomagokat vagy upc, vagy thome-al es a nat ennek megfeleloen fog eljarni, hogy most a upc-re vagy t-homera natolja.

Ezek utan a feladat egyszeru a mangle 3-as vagy 4-es rulejat kell kapcsolgatni es ha mar itt tartunk akkor allitgassuk a DNSt is, hogy a router tudjon dns kiszolgalokent is mukodni. Hat erre a kovetkezo nem tul elegans de mukodo scriptet tudtam letrehozni:


:global gw1;
:global gw2;
:global gw1ping 0;
:global gw2ping 0;
:global gw1outint "UPC - port 5";
:global gw2outint "pppoe-out1";
:global gw1dns "213.46.246.53,213.46.246.54";
:global gw2dns "84.2.44.1,84.2.46.1";
:global target 8.8.8.8;
:global gw1ruleid [ ip firewall mangle find comment=$gw1outint];
:global gw2ruleid [ ip firewall mangle find comment=$gw2outint];
:global gw1rulestate [ip firewall mangle get $gw1ruleid disabled];
:global gw2rulestate [ip firewall mangle get $gw2ruleid disabled];
:foreach i in  [ ip route find dst-address=0.0.0.0/0 ] do={ 
   :local gw [toip [ip route get $i gateway]];
   if ([:typeof $gw] != "nothing") do={
      if ([ip route get $i gateway-status]~"via  $gw2outint") do={
          :global gw2 $gw;
          :global gw2id $i;
          :global gw2ping [:tonum [/ping address=$target interface=$gw2outint count=5 interval 1s]];
          :log info $gw2ping;
          :log info [typeof $gw2ping];
      } else={;
        if ([ip route get $i gateway-status]~"via  $gw1outint") do={
                :global gw1 $gw;
                :global gw1id $i;
                :global gw1ping [:tonum [/ping address=$target interface=$gw1outint count=5 interval 1s]];
                :log info $gw1ping;
                :log info [typeof $gw1ping];
        };
      };
   };
};
if ( ($gw2ping > $gw1ping) or ( [typeof $gw1ping= "nothing"] )) do={
   if (! $gw1rulestate ) do={
        ip firewall mangle set $gw1ruleid disabled=yes;
        ip firewall mangle set $gw2ruleid disabled=no;
        ip dns set servers=$gw2dns;
        :log info "$gw2outint is active";
        /tool e-mail send to=<somethign something> subject="FAILOVER to $gw2outint" body="FAILOVER to $gw2outint"
   };
} else={;
   if ( $gw1rulestate ) do={
        ip firewall mangle set $gw2ruleid disabled=yes;
        ip firewall mangle set $gw1ruleid disabled=no;
        ip dns set servers=$gw1dns;
        :log info "$gw1outint is active";
        /tool e-mail send to=<something something> subject="FAILOVER to $gw1outint" body="FAILOVER to $gw1outint"
   }
}

Ezek utan mar csak berakjuk ezt a scriptet a schedulerbe es mivel 10mp-ig tuti futni fog 15mpkent futtassuk le, mivel en aggressziv vagyok googlenek meg birnia kell:D

Hozzászólások

arra van valami megoldas (barmi kulso server, stb), hogy egy ilyen valtaskor a tcp kapcsolatok ne szakadjanak meg? elegge szavar ha 10 ssh lebont meg upc megszakadt.

meg ez a script nem fogja pattogtatni a ket vonal kozott a kijaratot (a ping figyeles miatt kerdeztem?)

amugy de jo lenne egy ilyen linuxra is :(

--
A vegtelen ciklus is vegeter egyszer, csak kelloen eros hardver kell hozza!

a TCP azert fog megszakadni, mert hirtelen mas IP-re natolodsz. Meg lehet oldani, ha szerzel valami fixIPs VPN szolgaltatot, es a tunnelt valtogatod a ket kapcsolat kozott.

A pattogas az lehet, hogy problema lesz de eddig meg nem volt az. Gondolkozok, hogy egy valtas utan kellene meg kellene novelni a failback kondiciot, hogy ha mondjuk a UPC-nel packetloss van gyakran akkor mondjuk ne legyen failback amig nem tisztazzak a szitut. Ez majd a script 2.0-ban.

linux ala is tudsz ilyet csinalni, az ip route parancsal tudsz valtoztatni metricet a default routon es akkor a masquarade ugyanugy a megfelelo dolgot fogja csinalni.

Az, hogy a tunnel milyen uton modon epul ki az masodlagos a vpn szempontjabol. A lenyeg, hogy kell valami ami csinal egy encapot es lehetove teszi, hogy aktiv kapcsolattol fuggetlenul ugyanazt a forras ipcimet hasznalhasd _es_ a conntrack table ne torlodjon failover/failback eseteben. Azt, hogy ezt a mikortik megcsinalja-e es ha igen hogyan az masik kerdes.

Kicsit updatelni kellett a scriptet, mert kell egy nem dinamikus route ahhoz, hogy tudjon az ember PBR-t csinalni rendesen. En elfelejtettem, hogy van mar egy ilyenem amikor irtam a scriptet, de most ahogy nezegettem ez meg hianyzott szoval kiegeszitettem a scriptet azzal, hogy felallit 2 masik default route-ot 100-as distanceal, megjelolve es mindig updateelve, ha esetleg valtozas tortenne valamelyik ipcimben/defgw-ben. Szoval az updated script:


:global gw1;
:global gw2;
:global gw1ping 0;
:global gw2ping 0;
:global gw1outint "UPC - port 5";
:global gw2outint "pppoe-out1";
:global gw1dns "213.46.246.53,213.46.246.54";
:global gw2dns "84.2.44.1,84.2.46.1";
:global target 8.8.8.8;
:global gw1ruleid [ ip firewall mangle find comment=$gw1outint];
:global gw2ruleid [ ip firewall mangle find comment=$gw2outint];
:global gw1routeid [ ip route find comment=$gw1outint];
:global gw2routeid [ ip route find comment=$gw2outint];
:global gw1rulestate [ip firewall mangle get $gw1ruleid disabled];
:global gw2rulestate [ip firewall mangle get $gw2ruleid disabled];
:foreach i in  [ ip route find dst-address=0.0.0.0/0 ] do={
   :local gw [toip [ip route get $i gateway]];
   :local routingmark [ip route get $i routing-mark];
   if ([:typeof $gw] != "nothing" and [len $routingmark] = 0 ) do={
      if ([ip route get $i gateway-status]~"via  $gw2outint") do={
          :global gw2 $gw;
          :global gw2id $i;
          :global gw2ping [:tonum [/ping address=$target interface=$gw2outint count=5 interval 1s]];
      } else={;
        if ([ip route get $i gateway-status]~"via  $gw1outint") do={
                :global gw1 $gw;
                :global gw1id $i;
                :global gw1ping [:tonum [/ping address=$target interface=$gw1outint count=5 interval 1s]];
        };
      };
   };
};
if ( [len $gw1routeid] = 0 ) do={
   ip route add dst-address=0.0.0.0/0 gateway=$gw1 comment=$gw1outint routing-mark=via_upc distance=100;
   :log info "$gw1outint pbr route didn't exist has been added";
} else={;
   ip route set $gw1routeid dst-address=0.0.0.0/0 gateway=$gw1 comment=$gw1outint routing-mark=via_upc distance=100;
};
if ( [len $gw2routeid] = 0 ) do={
   ip route add dst-address=0.0.0.0/0 gateway=$gw2 comment=$gw2outint routing-mark=via_thome distance=100;
   :log info "$gw2outint pbr route didn't exist has been added";
} else={;
   ip route set $gw2routeid dst-address=0.0.0.0/0 gateway=$gw2 comment=$gw2outint routing-mark=via_thome distance=100;
};
if (([typeof $gw1ping] = "nothing") or ($gw2ping > $gw1ping)) do={
   if (! $gw1rulestate ) do={
        ip firewall mangle set $gw1ruleid disabled=yes;
        ip firewall mangle set $gw2ruleid disabled=no;
        ip dns set servers=$gw2dns;
        :log info "$gw2outint is active";
        /tool e-mail send to=kalebris@gmail.com subject="FAILOVER to $gw2outint" body="FAILOVER to $gw2outint"
   };
} else={;
   if ( $gw1rulestate ) do={
        ip firewall mangle set $gw2ruleid disabled=yes;
        ip firewall mangle set $gw1ruleid disabled=no;
        ip dns set servers=$gw1dns;
        :log info "$gw1outint is active";
        /tool e-mail send to=kalebris@gmail.com subject="FAILOVER to $gw1outint" body="FAILOVER to $gw1outint"
   }
}

Ez igy kicsit tulerzekenyre sikeredett szoval update kovetkezik.

Hat a mai napon a UPC szarakodasanak koszonhetoen volt idom kicsit csiszolgatni a failover scripten. Nincs letisztazva tehat boven van benne feleslegese valtozo de mostmar dolgozni kell, szoval igy marad egy darabig. Alapjaban veve valtozatlan a felallas, kituzott cel, de most csak a primaryrol pingeljuk, mert ha az szar akkor inkabb failover, jobb eselyunk ugy sincs.


:global gw1;
:global gw2;
:global gw1ping 0;
:global gw2ping 0;
:global gw1outint "UPC - port 5";
:global gw2outint "pppoe-out1";
:global gw1dns "213.46.246.53,213.46.246.54";
:global gw2dns "84.2.44.1,84.2.46.1";
:global target 8.8.8.8;
:global failover;
:global failback;
:global gw1ruleid [ ip firewall mangle find comment=$gw1outint];
:global gw2ruleid [ ip firewall mangle find comment=$gw2outint];
:global gw1routeid [ ip route find comment=$gw1outint];
:global gw2routeid [ ip route find comment=$gw2outint];
:global gw1rulestate [ip firewall mangle get $gw1ruleid disabled];
:global gw2rulestate [ip firewall mangle get $gw2ruleid disabled];
:foreach i in  [ ip route find dst-address=0.0.0.0/0 ] do={
   :local gw [toip [ip route get $i gateway]];
   :local routingmark [ip route get $i routing-mark];
   if ([:typeof $gw] != "nothing" and [len $routingmark] = 0 ) do={
      if ([ip route get $i gateway-status]~"via  $gw1outint") do={
                :global gw1 $gw;
                :global gw1id $i;
                :global gw1ping [:tonum [/ping address=$target interface=$gw1outint count=5 interval 1s]];
                if (([typeof $gw1ping] = "nothing") or ($gw1ping<5)) do={
                      :set failback 10;
                      if ([typeof $failover] ="nothing") do={
                           :set failover 1;
                      } else={;
                           :set failover ($failover +1);
                      };
                } else={;
                      if ($gw1ping=5) do={
                           :set failover 0;
                           if (([:typeof $failback]!="nothing") and ($failback >0) ) do={
                                :set failback ($failback -1);
                           }
                      };
                };
        } else={;
                if ([ip route get $i gateway-status]~"via  $gw2outint") do={
                         :global gw2 $gw;
                         :global gw2id $i;
                };
        };

   };
};

if ( [len $gw1routeid] = 0 ) do={
   ip route add dst-address=0.0.0.0/0 gateway=$gw1 comment=$gw1outint routing-mark=via_upc distance=100;
   :log info "$gw1outint pbr route didn't exist has been added";
} else={;
   ip route set $gw1routeid dst-address=0.0.0.0/0 gateway=$gw1 comment=$gw1outint routing-mark=via_upc distance=100;
};
if ( [len $gw2routeid] = 0 ) do={
   ip route add dst-address=0.0.0.0/0 gateway=$gw2 comment=$gw2outint routing-mark=via_thome distance=100;
   :log info "$gw2outint pbr route didn't exist has been added";
} else={;
   ip route set $gw2routeid dst-address=0.0.0.0/0 gateway=$gw2 comment=$gw2outint routing-mark=via_thome distance=100;
};
if ($failover>3) do={
   if (! $gw1rulestate ) do={
        ip firewall mangle set $gw1ruleid disabled=yes;
        ip firewall mangle set $gw2ruleid disabled=no;
        ip dns set servers=$gw2dns;
        :log info "$gw2outint is active";
        /tool e-mail send to=kalebris@gmail.com subject="FAILOVER to $gw2outint" body="FAILOVER to $gw2outint"
        :set failback 10;
   };
} else={;
   if ( $gw1rulestate and $failback=0) do={
        ip firewall mangle set $gw2ruleid disabled=yes;
        ip firewall mangle set $gw1ruleid disabled=no;
        ip dns set servers=$gw1dns;
        :log info "$gw1outint is active";
        /tool e-mail send to=kalebris@gmail.com subject="FAILOVER to $gw1outint" body="FAILOVER to $gw1outint"
   }
}