I have written a script to add host routes to the IPv4 routing table, please see the complete script below. The problem however is that on each invocation, the script creates duplicate entries in the routing table, and of course it does not delete old entries (which it created when the IP addresses were different). Can you please advise me some way to detect obsolete entries? It would be nice to use some timestamps on configuration entries, but I don’t know of such a feature existing in RouterOS.
The script itself:
# extract addresses in the list
:local AddressList [/ip firewall address-list find comment~"api\\."];
:local ipAddress;
:foreach entry in=$AddressList do={
:set ipAddress ([/ip firewall address-list get $entry]->"address");
:put ($ipAddress."/32");
/ip/route/add comment=([/ip firewall address-list get $entry]->"comment") disabled=no distance=1 dst-address=($ipAddress."/32") gateway=10.x.x.x routing-table=main;
};
Of course I could delete all the generated routes on each script invocation, like in
# delete all API routes
/ip/route/remove [find comment~"api\\."];
But this will probably cause traffic disruptions if I run the script from cron.
Scroll through the list of addresses.
For each of theroutes you find that are the same as the ones you need,
update the comment with a prefix and today’s date (for example “$comment 2025/01/24 14:30”)
add the routes that don’t exist, always with the same comment “$comment 2025/01/24 14:30”
Finally, delete among all the routes that contain “api.” those with a comment that not containing “2025/01/24 14:30”
/ip/route/remove [find where (comment~“api\.”) and !(comment~“2025/01/24 14:30”)]
Basically, yes, but for be more “nice” on the point 2: on foreach cycle at the same time you UPDATE the comment if the rule already exist AND add new rules with :timestamp.
This do not delete what already exist (and must be keeped) and do not (temporarly) duplicate rules.
Why would I care to take into account what already exists when I can create a bunch of new routes with the current timestamp (even if they are duplicates of the older routes, it does not seem to cause any harm) and then delete everything with non-current timestamps? This looks much simpler, unless it is wrong for some reason.
Use route marking. Make a mangle rule that mark packets from your list with routing mark and stay away from routing table where the only route rule for all that addresses (route mark) is needed. No matter when and how you update the list only members of it would get the needed routing with no hickups
Tip no. 2:
The list that you prepare should be timebased so when you add an entry to it then you should set timer for the entry for eg. 6 hours if you refresh that list every 6 hours. When you readd the entry during that period you just refresh/reset that timer, if not the entry just vanishes. No need to worry of any leftovers.
Policy routing > is the method to steer traffic matching certain criteria to a certain gateway. …
RouterOS gives you two options to choose from: firewall mangle > - it gives more control over the criteria to be used to steer traffic, for example, per connection or per packet balancing, etc. For more info on how to use mangle marking > see Firewall Marking examples> …
The problem IMHO is that mangling is in the Firewall menu even if it provides mostly nonfirewall services but that place suggest that mangle is firewall thing. For me the most firewall-like actions are the green ones.
change-dscp - change the Differentiated Services Code Point (DSCP) field value specified by the new-dscp parameter
change-mss - change the Maximum Segment Size field value of the packet to a value specified by the new-mss parameter
change-ttl - change the Time to Live field value of the packet to a value specified by the new-ttl parameter
clear-df - clear ‘Do Not Fragment’ Flag
fasttrack-connection - shows fasttrack counters, useful for statistics
mark-connection - place a mark specified by the new-connection-mark parameter on the entire connection that matches the rule
mark-packet - place a mark specified by the new-packet-mark parameter on a packet that matches the rule
mark-routing - place a mark specified by the new-routing-mark parameter on a packet. This kind of mark is used for policy routing purposes only. Do not apply any other routing marks besides “main” for the packets processed by FastTrack, since FastTrack can only work in the main routing table.
route - forces packets to a specific gateway IP by ignoring normal routing decisions (prerouting chain only)
set-priority - set priority specified by the new-priority parameter on the packets sent out through a link that is capable of transporting priority (VLAN or WMM-enabled wireless interface). Read more
sniff-pc - send a packet to a remote RouterOS CALEA server.
sniff-tzsp - send a packet to a remote TZSP compatible system (such as Wireshark). Set remote target with sniff-target and sniff-target-port parameters (Wireshark recommends port 37008)
strip-ipv4-options - strip IPv4 option fields from IP header, the action does not actually remove IPv4 options but rather replaces all option octets with NOP, further matcher with ipv4-options=any will still match the packet.
I agree that your proposal looks nicer, but as I am writing this script to solve a very small personal problem (changing IP addresses of load balancers), I prefer the solution to be quick and simple, and I am ready for it to be dirty. I only have to write a couple of scripts in RouterOS and will probably never need the language again for several years.
Oh no. In fact, I tried to solve my problem first with address-lists + PBR (policy based routing). There are many examples of PBR for Mikrotik in the internet, using the firewall and multiple routing tables.
It worked but (!) TCP worked SO slowly that kubectl and Lens did not tolerate such response times and produced errors. I was never able to find the reason why packets going via PBR were so slow and had to revert to regular routing which works fast.
I even thought of using BGP to announce those dozen /32 routes to Mikrotik, but the solution with DNS → routing seems simpler to implement though it requires scripting (and I am a newbie in RouterOS scripting).
Note that not all packets of the connection can be FastTracked, so it is likely to see some packets going through a slow path even though the connection is marked for FastTrack. This is the reason why fasttrack-connection is usually followed by an identical "action=accept" rule.
If using connection-mark then excluding these from the fasttrack rule should work:
This brings about a question. How are address-lists resolved and refreshed? If I create an address-list from the name “api.mycluster.example” and it resolves into 3 dynamic address-lists with IP addresses, how do I make sure that these dynamic lists do not become stale and my code
As rextended suggested use comment for tagging your “dynamic” routes: http://forum.mikrotik.com/t/garbage-collect-old-routes-and-duplicate-routes/181445/2
You have to have global variable holding the last used TAG. Add new/current routes with a new tag and delete all with old one.
If routes are doubled then only the one of them is active and even if active one is just removed the second takes over.
Do not kow if changeing the distance for the old ones to +1 could help as the first step to let the new entries get active immediately but it is just an idea.
The main question is where the “api*” list come from? Is it a list of PPoE interfaces or it is based on DHCP. If yes maybe you should consider using on/off scripts to activate/deactivate particular routes and netwatch script to clear the stale ones?
You can check it easily: make a list based on any noncrucial DNS name and then set local static DNS name with different IP and set the low test TTL for that. Then watch how and when the address list reacts to changes to static entry or disabling it.