THIS is important - thanks for reminding me, will edit the first post accordingly today. When the board gets rebooted the IDs will / might change.You should not use the numbers from "/ip/route/print" to disable an interface (step 6 in OP)…
Also, without firewall marking, incoming connection are not possible using this approach. So VPN's be tricky with this approach.
# check wan
#
# use this with netwatch or scheduler
# prefer netwatch with src-address
#
# TODO :
# use netwatch src-address
# disable dhclient update recursive route
# version 20230803
:global checkWanStatus
:global checkWanRun
#
# define vars
#
# wan1
:local iface "wan1"
:local tableRoute "route-wan1"
:local gateway xx.xx.xx.xx.xx"
:local srcAddress "xx.xx.xx.xx"
:local distanceDefault 1
:local distancePersist 101
:local dstAddress "0.0.0.0/0"
# wan2
#:local iface "wan2"
#:local tableRoute "route-wan2"
#:local gateway "192.168.6.1"
#:local srcAddress "192.168.6.254"
#:local distanceDefault 9
#:local distancePersist 109
#:local dstAddress "0.0.0.0/0"
:local resetConn 1
:local addrTest1 "1.0.0.1"
:local addrTest2 "9.9.9.10"
:local addrTest3 "8.8.4.4"
:local countTest 3
:local LogHeader "check-wan"
:local email "xxx@xxx.com"
:local Date [/system clock get date];
:local Time [/system clock get time];
:local routeStatus
:local pingStatus
:local prouteStatus
:local trouteStatus
# init
:if ( [:tostr $checkWanStatus] = "" ) do={
:set checkWanStatus ($Time . " " . $Date);
}
:set checkWanRun ($Time . " " . $Date);
:local msg
:local addr
#
# define dynamic vars
#
#:set dstAddress ""
#:set gateway ""
#:set srcAddress ""
if ( [:tostr $distanceDefault] = "" ) do={
:set distanceDefault "1"
:set msg "$LogHeader : defined distance=$distanceDefault"
:put "$msg"
}
if ( [:tostr $dstAddress] = "" ) do={
:set dstAddress "0.0.0.0/0"
:set msg "$LogHeader : defined dst-address=$dstAddress"
:put "$msg"
}
if ( [:tostr $gateway] = "" ) do={
:set gateway ([/ip route print detail as-value where distance=$distanceDefault routing-table=main dst-address=$dstAddress ]->0->"gateway")
:set msg "$LogHeader : defined gateway=$gateway"
:put "$msg"
if ( [:tostr $gateway] = "" ) do={
:set msg "$LogHeader : null gateway=$gateway"
#/tool e-mail send to=$email subject="$msg"
:set checkWanStatus "ERROR"
:error "$smg"
}
}
if ( [:tostr $srcAddress] = "" ) do={
:set srcAddress ([/ip/address print detail as-value where interface=$iface ]->0->"address")
:local delim [:find $srcAddress "/" 0]; :set srcAddress [ :pick $srcAddress 0 $delim ]
:set msg "$LogHeader : defined src-address=$srcAddress"
:put "$msg"
if ( [:tostr $srcAddress] = "" ) do={
:set msg "$LogHeader : null src-address=$srcAddress"
#/tool e-mail send to=$email subject="$msg"
:set checkWanStatus "ERROR"
:error "$smg"
}
}
#
# test table route
#
:set trouteStatus ([/ip route print detail as-value where gateway="$gateway" routing-table=$tableRoute dst-address=$dstAddress disabled=no ]->0->"distance")
if ( [:tostr $trouteStatus] = "" ) do={
:set trouteStatus "FAILED"
:set msg "$LogHeader : current table route dst-address=$dstAddress gateway=$gateway routing-table=$tableRoute FAILED !"
:put "$msg";
:log warning "$msg"
} else={
:set msg "$LogHeader : current table route dst-address=$dstAddress gateway=$gateway routing-table=$tableRoute distance=$trouteStatus alive"
:put "$msg";
:set trouteStatus "OK"
}
#
# test current persistent route
#
:set prouteStatus ([/ip route print detail as-value where gateway="$gateway" distance=$distancePersist routing-table=main dst-address=$dstAddress disabled=no ]->0->"distance")
if ( [:tostr $prouteStatus] != "$distancePersist" ) do={
:set prouteStatus "FAILED"
:set msg "$LogHeader : current persistent route dst-address=$dstAddress gateway=$gateway distance=$distancePersist routing-table=main FAILED !"
:put "$msg";
:log warning "$msg"
} else={
:set msg "$LogHeader : current persistent route dst-address=$dstAddress gateway=$gateway distance=$distancePersist routing-table=main alive"
:put "$msg";
:set prouteStatus "OK"
}
#
# test current route
#
:set routeStatus ([/ip route print detail as-value where gateway="$gateway" distance=$distanceDefault routing-table=main dst-address=$dstAddress disabled=no ]->0->"distance")
if ( [:tostr $routeStatus] != "$distanceDefault" ) do={
:set routeStatus "FAILED"
:set msg "$LogHeader : current route dst-address=$dstAddress gateway=$gateway distance=$distanceDefault routing-table=main FAILED !"
:put "$msg";
:log warning "$msg"
} else={
:set msg "$LogHeader : current route dst-address=$dstAddress gateway=$gateway distance=$distanceDefault routing-table=main alive"
:put "$msg";
:set routeStatus "OK"
}
#
# test ping
#
:set pingStatus "OK"
:set addr "$addrTest1"
if ([/ping $addr src-address=$srcAddress count=$countTest]=0) do={
:set msg "$LogHeader : ping src-address=$srcAddress $addr FAILED !"
:put "$msg"; :log warning "$msg"
:set pingStatus "WARNING"
:set addr "$addrTest2" ;
if ([/ping $addr src-address=$srcAddress count=$countTest]=0) do={
:set msg "$LogHeader : ping src-address=$srcAddress $addr FAILED !"
:put "$msg"; :log warning "$msg"
:set pingStatus "WARNING"
:set addr "$addrTest3" ;
if ([/ping $addr src-address=$srcAddress count=$countTest]=0) do={
:set msg "$LogHeader : ping src-address=$srcAddress $addr FAILED !"
:put "$msg"; :log error "$msg"
:set pingStatus "FAILED"
} else={
:set msg "$LogHeader : ping src-address=$srcAddress $addr alive"
:put "$msg";
#:log info "$msg"
}
} else={
:set msg "$LogHeader : ping src-address=$srcAddress $addr alive"
:put "$msg";
#:log info "$msg"
}
} else={
:set msg "$LogHeader : ping src-address=$srcAddress $addr alive"
:put "$msg";
#:log info "$msg"
}
# status
:set msg "$LogHeader : routeStatus:$routeStatus trouteStatus:$trouteStatus prouteStatus:$prouteStatus pingStatus:$pingStatus"
:put "$msg";
#:log info "$msg"
#
# final decision
#
if ( $pingStatus = "FAILED") do={
:set checkWanStatus "$iface FAILED"
:set msg "$LogHeader : interface $iface FAILED !"
:put "$msg"; :log warning "$msg"
if ($routeStatus = "OK") do={
/ip route set [find gateway=$gateway distance=$distancePersist routing-table=main dst-address=$dstAddress disabled=yes ] disabled=no comment="$iface persistdef - $LogHeader $Time enabled";
/ip route set [find gateway=$gateway distance=$distanceDefault routing-table=main dst-address=$dstAddress disabled=no ] disabled=yes comment="$iface def - $LogHeader $Time disabled";
if ( $resetConn = "1" ) do={
/ip/firewall/connection remove [find]
}
:set checkWanStatus "$iface DISABLED"
:set msg "$LogHeader : route dst-address=$dstAddress gateway=$gateway distance=$distanceDefault routing-table=main reset-conn:$resetConn DISABLED !"
:put "$msg"; :log warning "$msg"
:delay 3;
/tool e-mail send to=$email subject="$msg" } else={
:set msg "$LogHeader : route dst-address=$dstAddress gateway=$gateway distance=$distanceDefault routing-table=main already disabled"
:put "$msg"; :log info "$msg" }
} else={
if ($routeStatus = "FAILED") do={
:set checkWanStatus "$iface RESTORED"
/ip route set [find gateway=$gateway distance=$distancePersist routing-table=main dst-address=$dstAddress disabled=yes ] disabled=no comment="$iface persistdef - $LogHeader $Time restored";
/ip route set [find gateway=$gateway distance=$distanceDefault routing-table=main dst-address=$dstAddress disabled=yes ] disabled=no comment="$iface def - $LogHeader $Time restored";
if ( $resetConn = "1" ) do={
/ip/firewall/connection remove [find]
}
:set msg "$LogHeader : route dst-address=$dstAddress gateway=$gateway distance=$distanceDefault routing-table=main reset-conn:$resetConn RESTORED !"
:put "$msg"; :log warning "$msg"
:delay 3;
/tool e-mail send to=$email subject="$msg"} else={
:set msg "$LogHeader : interface $iface alive"
:put "$msg";
:log info "$msg"
:set checkWanStatus "$iface OK"
}
}
/ip firewall mangle add action=mark-routing chain=output dst-address=3.3.3.3 routing-table=!mytable new-routing-mark=mytable /ip route add dst-address=3.3.3.3/32 gateway=3.3.3.3 routing-mark=mytable
/ip route add dst-address=3.3.3.3/32 gateway=3.3.3.3 routing-mark=mytable /ip route rule add dst-address=3.3.3.3/32 table=mytable
/routing table add fib name=mytable /ip firewall mangle add action=mark-routing chain=output dst-address=3.3.3.3 routing-mark=!mytable new-routing-mark=mytable /ip route add dst-address=3.3.3.3/32 gateway=3.3.3.3 routing-table=mytable
/routing table add fib name=mytable /ip route add dst-address=3.3.3.3/32 gateway=3.3.3.3 routing-table=mytable /routing rule add dst-address=3.3.3.3/32 table=mytable
It is always wrong to use the firewall to decide the routes (except in exceptional cases).
For routes must be used... routes...
Sorry for the late reply, @derolf - here's the answer:I want to do the same (5G + DSL-Failover).
- Do you have your box in bridge or router mode?
- What cable do you connect on what port on your box?
Felt not offended - we're all here to learn. And usually this board is a good example of respecting every stage of knowledge and diving into each others' problems.I just explained how things should be done, that's the purpose of the forum.
/ip firewall connection
:foreach idc in=[find where timeout>60] do={
remove [find where .id=$idc]
}
@anav is point is right, masquerade does a lot of heavy-lifting without any more config. IMO, if you want simple... don't mess with connections or trying optimize failover for ALL traffic.Isnt that partially taken care of by using masquerade on source nat vice action=srcnat ( for a fixed static IP?)..
If one does want to go down the road at attempting to speed recovery times, you need packet/connection marks & action=reject reject-with= filter rules based on WAN_X does not match.I like the idea of the "cross backup" for this case of two different sources (home and business traffic)
[...]this should make the transition from one connection to the other faster, but I wonder if it has any drawback or causes any collateral damage.Code: Select all/ip firewall connection :foreach idc in=[find where timeout>60] do={ remove [find where .id=$idc] }
The topic is well-described these days: https://help.mikrotik.com/docs/display/ ... Masquerade1) is masquerade preferrable also on static setup ( because of the way It handles inherently the existing connections in case of failover)
If you want "unplug for failover", you need masquerade. Stuff like LTE always will generally disconnect, so you'd want masquerade there too. Now recursive route induced failover is not a "disconnect", so masquerade won't help to clear connections. And src-nat does not ever clear connections. Why I do not think recursive routes should be involved in "simpler failover"... Every time when interface disconnects and/or its IP address changes, the router will clear all masqueraded connection tracking entries related to the interface, this way improving system recovery time after public IP change. If srcnat is used instead of masquerade, connection tracking entries remain and connections can simply resume after a link failure.
VRRP only help if you had TWO routers. And, for example, someone tripping one routers power/other cable, or your doing up updage/config change. But does not really help with WAN network failure (outside more ISP situtions).Separate from jaclaz question, why not consider VRRP as a way to create a seamless connection from the client (lan) perspective, or will not work in your zooom example. ????