Hi there. I’m new, this is my first post, AND ALSO I have in fact read the suggested information regarding scripting tips and tricks, basics, and so forth. Yes I understand that every idiot with a first post claiming there’s a bug in the OS, also says that. (PS; "Read before creating yet another new my script does not work topic" provides a link to the Wiki’s Scripting_Tips_and_Tricks page which does not exist.)
I’ve also posted this to the Mikrotik subreddit, despite several days and 2,000+ views, nobody has answered.
I assure you, this is not the standard newbie “script don’t work” post. Please consider this framing before you reply.
BACKGROUND:
I’d like to implement tiers of priority hosts on my network. On IPv4 I have done so using several Address Lists which categorize traffic into the Queue Tree. We’ll focus on interacting with just one, called PRIORITY_HOSTS. I have firewall mangle rules to tag packets based on those address lists. I have a Queue Tree implemented with relevant tag-to-queue rules etc. IPv4 works flawlessly, of course, but IPv6 is a lot more difficult to deal with here. I want to implement the same Address List rules on IPv6, using an Address List generated from a script.
Here’s the idea, using some random IPs in 192.168.0.0/16:
[Variably8919@MikroTik] > /ip/firewall/address-list/print where list=PRIORITY_HOSTS
Columns: LIST, ADDRESS, CREATION-TIME
# LIST ADDRESS CREATION-TIME
0 PRIORITY_HOSTS 192.168.1.125 2025-10-17 11:13:27
1 PRIORITY_HOSTS 192.168.25.156 2025-10-17 11:13:28
2 PRIORITY_HOSTS 192.168.25.222 2025-10-17 11:13:29
3 PRIORITY_HOSTS 192.168.255.252 2025-10-17 11:13:30
4 PRIORITY_HOSTS 192.168.3.244 2025-10-17 11:13:31
Intent:
- Read IPv4 Address List (Working)
- Lookup MAC via IP from DHCP Leases (Working)
- Lookup IPv6 Address via MAC from ND (Working)
- Write IPv6 Address List (Working but Problematic)
THE ACTUAL PROBLEM:
In the IPv6 Address List, I need to ADD an entry if it doesn’t exist, but SET an entry if it does exist. I have written a clause to test if the entry exists, but the test does not work and everything I can see says that it should be working.
The commands I used BY HAND via Terminal, work properly, but when modified to run in the context of a script, one command has no return value WHEN RUN AS A SCRIPT, but when run BY HAND it works and returns a value.
I understand that many commands are expected to behave in a manner similar to this but not in the context I mean.
The script itself provides commands to run to verify operation, and relevant commands return expected values (including the object reference which is not directly usable but proves there IS a return when run by hand.)
Please see the relevant script, which has comments to indicate where/how failures occur etc;
:log info "Start"
:foreach idx in=[/ip/firewall/address-list/find list=PRIORITY_HOSTS] do={
:local ip [/ip/firewall/address-list/get $idx address];
:local tag [/ip/firewall/address-list/get $idx comment];
:local lease [/ip/dhcp-server/lease/find where address=$ip];
:local mac [/ip/dhcp-server/lease/get $lease mac-address];
:foreach n in=[/ipv6/neighbor/find where mac-address=$mac interface=BRIDGE_LAN] do={
:local candidate [/ipv6/neighbor/get $n address]
:log info [:serialize value=$candidate to=json]
:if ([:len $candidate] > 0 && [:pick $candidate 0 4] = "2605") do={
:log info ("/ipv6/firewall/address-list/print where list=PRIORITY_HOSTS address=" . $candidate);
# ^^^ IF I COPY THIS COMMAND FROM LOGS AND RUN IT, THE RETURN INDICATES A VALID MATCH
:log info (":put [/ipv6/firewall/address-list/find list=PRIORITY_HOSTS address=" . $candidate . "]");
# ^^^ IF I COPY THIS COMMAND FROM LOGS AND RUN IT, THE RETURN INDICATES A VALID MATCH
:local existing [/ipv6/firewall/address-list/find list=PRIORITY_HOSTS address=$candidate];
# ^^^ NEVER POPULATED EVEN THOUGH LIST ENTRY IS 100% VERIFIED TO EXIST AND BOTH PRINT AND FIND COMMANDS 100% RETURN A MATCH MANUALLY
:if ([:len $existing] = 0) do={
/ipv6/firewall/address-list/add comment=$tag list=PRIORITY_HOSTS timeout=1:0:0 address=$candidate;
# ^^^ ALWAYS THROWS ERROR AFTER FIRST RUN BECAUSE ENTRY EXISTS
} else={
/ipv6/firewall/address-list/set $existing timeout=4:0:0;
# ^^^ NEVER RUNS BECAUSE `existing` IS NOT POPULATED
}
}
}
}
:log info "End"
So, somehow populating a local variable, from the return of /ipv6/firewall/address-list/find list=PRIORITY_HOSTS address=$candidate does not work, as such a check to see if the entry exists fails, and I cannot ‘set’ an entry which already exists. I have checked, and $candidate IS populated (thus printing into the log) and at run-time $candidate is of type ip6 AND I have attempted to coerce it with :tostr and the resulting variable still does not populate $existing variable.
I am NOT interested in using Timeout to self-remove these entries. I’ve examined this as a fix but it will not fit our needs.
I think this is a script processing bug, but I am uncertain how to proceed.
Can anyone provide some feedback? Please consider the care I went through to justify the question and reinforce that I’ve taken steps to prove my case.