RouterOS 7.25/7.24: cached root NS added to unrelated empty AAAA replies, causing Unbound SERVFAIL

Hi,

I have observed the following DNS cache/response problem on an RB4011iGS+
running RouterOS 7.24.5, and confirmed that the same failure still occurs
after upgrading to RouterOS 7.25. Has anyone encountered this, and is there
a known fix or a supported workaround that preserves normal DNS caching?

Test status

  • RouterOS 7.24.5: clean-cache baseline, single ". NS" trigger and recovery
    after cache flush were directly observed.
  • RouterOS 7.25: the same incorrect AAAA replies and downstream SERVFAIL
    were directly observed after the upgrade, over both UDP and TCP.
  • Important distinction: the 7.25 cache already contained all 13 root NS
    at the start of verification. The root NS query was repeated and the
    failure remained. This 7.25 pass did not include a cache flush, so it
    does not establish a fresh empty-cache trigger or recovery on 7.25.

Summary

The RouterOS caching DNS forwarder adds cached root-zone NS records to the
Authority section of replies for unrelated names. This also happens when
the upstream server returns a successful empty AAAA answer with no Authority
records. Unbound, configured to forward the affected names through RouterOS,
then returns SERVFAIL to its clients.

On 7.24.5, starting with an empty NS cache, a single query for ". IN NS"
through RouterOS was sufficient to trigger the issue. Flushing RouterOS
DNS cache restored correct AAAA replies and stopped downstream SERVFAIL.
The incorrect replies and downstream failure persist on 7.25 when the
root NS RRset is cached, as shown by the post-upgrade verification below.

The root NS records themselves are legitimate. The issue is their reuse in
the Authority section of an unrelated empty AAAA response, changing an empty
NOERROR response into a referral-shaped response.

Environment

  • Device: RB4011iGS+.
  • Architecture: arm.
  • RouterOS versions with directly observed failure: 7.24.5 (stable) and 7.25.
  • Current RouterOS version: 7.25, verified through SSH after the upgrade.
  • Downstream resolver: Unbound in the Mailcow Docker stack. Version reported
    during report preparation: 1.26.1.
  • Upstream DNS servers: two Pi-hole instances, 192.168.2.253 and 192.168.2.252.
  • MikroTik DNS address: 192.168.2.1.
  • Unbound DNS address in the Mailcow network: 172.22.1.254.
  • All DNS probes in this reproduction used IPv4 transport, including AAAA
    queries. This is not a test of IPv6 network connectivity.

DNS path for the affected names

Mailcow client -> Unbound 172.22.1.254 -> MikroTik 192.168.2.1 -> Pi-hole
192.168.2.253 or 192.168.2.252.

The affected names are intentionally overridden on both Pi-hole servers:

address=/mail21.mydevil.net/192.168.33.21
local=/mail21.mydevil.net/
address=/mail55.mydevil.net/192.168.33.55
local=/mail55.mydevil.net/

The private A records are intentional and required for an internal tunnel.
The names have no local AAAA records. Direct AAAA queries to either Pi-hole
return NOERROR, Answer=0, Authority=0.

Relevant RouterOS DNS configuration

Observed during the 7.24.5 reproduction and unchanged in the 7.25 read-back:

servers: 192.168.2.253,192.168.2.252
dynamic-servers: empty
use-doh-server: empty
allow-remote-requests: yes
cache-size: 2048KiB
cache-max-ttl: 1d
query-server-timeout: 2s
query-total-timeout: 10s
max-udp-packet-size: 4096
max-concurrent-queries: 100
max-concurrent-tcp-sessions: 20
address-list-extra-time: 0s
vrf: main

No static FWD entries or adlists were found in the earlier configuration
inspection. No RouterOS static records match the affected names.
An existing failover script can select public resolvers if both Pi-hole
servers fail. No public resolver was configured in the DNS configuration
read immediately after this controlled reproduction. Both Pi-hole servers
answered the direct control queries successfully. An upstream outage was
not deliberately induced or needed to reproduce the issue.

Controlled reproduction on 7.24.5

Run only as a controlled diagnostic test: on the affected version, step 3
can cause DNS failures for other clients using this resolver chain. The
final cache flush removes the immediate effect of the test.

  1. Flush RouterOS DNS cache:

    /ip dns cache flush

  2. Confirm that there are no cached NS records:

    /ip dns cache all print detail where type=NS

    Then query both names through RouterOS and Unbound:

    dig -4 @192.168.2.1 mail21.mydevil.net AAAA
    dig -4 @192.168.2.1 mail55.mydevil.net AAAA
    dig -4 @172.22.1.254 mail21.mydevil.net AAAA
    dig -4 @172.22.1.254 mail55.mydevil.net AAAA

    Baseline: all four replies are NOERROR, Answer=0, Authority=0.

  3. Send ONE root NS query to RouterOS:

    dig -4 @192.168.2.1 . NS

  4. Read the RouterOS NS cache again:

    /ip dns cache all print detail where type=NS

    Thirteen root NS records now appear, with name="" and a remaining TTL
    close to 24 hours.

  5. Repeat the four AAAA queries from step 2. Also compare both upstreams:

    dig -4 @192.168.2.252 mail21.mydevil.net AAAA
    dig -4 @192.168.2.253 mail21.mydevil.net AAAA
    dig -4 @192.168.2.252 mail55.mydevil.net AAAA
    dig -4 @192.168.2.253 mail55.mydevil.net AAAA

    RouterOS: NOERROR, Answer=0, Authority=13, containing the cached root NS.
    Unbound: SERVFAIL for both names.
    Either Pi-hole directly: NOERROR, Answer=0, Authority=0 for both names.

  6. Flush RouterOS DNS cache again:

    /ip dns cache flush

    Repeat step 2: RouterOS and Unbound again return NOERROR with empty
    Answer and Authority sections. No RouterOS or Mailcow configuration
    changes were required for this recovery.

Observed output and timeline on 7.24.5

Timestamps below are UTC from the diagnostic client.

2026-10-27 22:36:03-22:36:04 UTC, after the administrator flushed cache:
RouterOS NS cache: empty.
Both names, all four DNS servers:
status: NOERROR; ANSWER: 0; AUTHORITY: 0

2026-10-27 22:36:07.861 UTC, single ". NS" query to RouterOS:
status: NOERROR; ANSWER: 13; AUTHORITY: 13
The root NS RRset was present in both Answer and Authority sections.

RouterOS cache read immediately afterwards:
name="" type=NS data=g.root-servers.net. ttl=23h59m58s
name="" type=NS data=h.root-servers.net. ttl=23h59m58s
name="" type=NS data=i.root-servers.net. ttl=23h59m58s
name="" type=NS data=j.root-servers.net. ttl=23h59m58s
name="" type=NS data=k.root-servers.net. ttl=23h59m58s
name="" type=NS data=l.root-servers.net. ttl=23h59m58s
name="" type=NS data=m.root-servers.net. ttl=23h59m58s
name="" type=NS data=a.root-servers.net. ttl=23h59m58s
name="" type=NS data=b.root-servers.net. ttl=23h59m58s
name="" type=NS data=c.root-servers.net. ttl=23h59m58s
name="" type=NS data=d.root-servers.net. ttl=23h59m58s
name="" type=NS data=e.root-servers.net. ttl=23h59m58s
name="" type=NS data=f.root-servers.net. ttl=23h59m58s

2026-10-27 22:36:15 UTC, AAAA queries after that single NS query:

@192.168.2.1 mail21.mydevil.net AAAA:
status: NOERROR; ANSWER: 0; AUTHORITY: 13
Authority contains ". IN NS" records for a.root-servers.net through
m.root-servers.net, with TTL approximately 86393 seconds.

@192.168.2.1 mail55.mydevil.net AAAA:
status: NOERROR; ANSWER: 0; AUTHORITY: 13
Same root NS RRset in Authority.

@192.168.2.252 or @192.168.2.253, either name, AAAA:
status: NOERROR; ANSWER: 0; AUTHORITY: 0

@172.22.1.254, either name, AAAA:
status: SERVFAIL; ANSWER: 0; AUTHORITY: 0

Direct ". NS" queries to either Pi-hole:
status: NOERROR; ANSWER: 13; AUTHORITY: 0
Both upstreams legitimately provide the root NS RRset when asked for it.

2026-10-27 22:42:43 UTC, after the administrator flushed RouterOS cache again:
RouterOS NS cache: empty.
RouterOS and Unbound, either name, AAAA:
status: NOERROR; ANSWER: 0; AUTHORITY: 0

Post-upgrade verification on 7.25

Device and version read-back:

VERSION=7.25
BOARD=RB4011iGS+
ARCH=arm

Before any new ". NS" query in this verification, the RouterOS cache
already contained all 13 root NS, with remaining TTL=23h55m26s.
Their origin before this verification was not captured.

2026-10-27 22:52:31 UTC:
The following matrix was tested for BOTH mail21.mydevil.net and
mail55.mydevil.net over BOTH UDP/IPv4 and TCP/IPv4 (16 queries total):

  Server          Status     Answer   Authority   Authority contents
  192.168.2.1     NOERROR    0        13          a-m.root-servers.net
  192.168.2.252   NOERROR    0        0           empty
  192.168.2.253   NOERROR    0        0           empty
  172.22.1.254    SERVFAIL   0        0           empty

Example commands, also tested with +tcp:

dig -4 @192.168.2.1 mail21.mydevil.net AAAA
dig -4 @192.168.2.252 mail21.mydevil.net AAAA
dig -4 @192.168.2.253 mail21.mydevil.net AAAA
dig -4 @172.22.1.254 mail21.mydevil.net AAAA

2026-10-27 22:52:38.331 UTC, repeated ". NS" query on 7.25:

dig -4 @192.168.2.1 . NS
status: NOERROR; ANSWER: 13; AUTHORITY: 13
The root NS RRset was again present in both sections, TTL=86093.

2026-10-27 22:52:38.401-22:52:38.642 UTC, subsequent AAAA probes:

@192.168.2.1, either mail server name:
status: NOERROR; ANSWER: 0; AUTHORITY: 13
All 13 root NS are present in Authority.

@172.22.1.254, either mail server name:
status: SERVFAIL; ANSWER: 0; AUTHORITY: 0

The NS cache read immediately afterwards still showed all 13 entries,
with name="" and remaining TTL=23h54m51s.

Conclusion limited to the observations: upgrading to 7.25 did not eliminate
the cached-root-NS response behavior or the resulting downstream SERVFAIL
in this environment. No cache flush or configuration change was performed
during this 7.25 verification.

Additional observations

  • Before the controlled reproduction, an earlier passive packet capture
    inside an upstream Pi-hole showed it replying to the MikroTik with
    NOERROR, Answer=0, Authority=0 for mail55.mydevil.net AAAA. The client
    querying the MikroTik received NOERROR, Answer=0, Authority=13. This
    demonstrates that the root NS records were added by RouterOS on that
    exchange, not supplied by Pi-hole in the corresponding AAAA reply.
  • The earlier failure was observed over both UDP and TCP, with and without
    EDNS. Unbound queries with the CD flag also returned SERVFAIL.
  • After a previous flush, 78 DNS queries in six rounds over approximately
    two minutes succeeded without triggering the issue. The controlled
    ". NS" query subsequently provided a short reproducible trigger.
  • No IMAP credentials, mailbox settings or mail transfer are involved in
    this reproduction. The failure occurs at DNS resolution time.

Expected behavior

Caching the legitimate root NS RRset should not alter the meaning of later
empty AAAA replies for unrelated names. RouterOS should preserve an upstream
successful NODATA answer as a successful NODATA answer, without adding root
NS records that make it resemble a referral. A downstream recursive
forwarder should continue to receive the final empty answer.

Impact

Name resolution for the affected mail servers fails through Unbound after
an unrelated root NS query passes through the shared RouterOS DNS cache.
This affects applications using that DNS chain. Clearing cache recovers
service temporarily, but a later root NS query can trigger the problem
again on the reproduced version.

Questions

  1. Is this cached-NS/empty-AAAA behavior a known RouterOS issue?
  2. Is there a fix, and which exact release contains it?
  3. Is this separate from the 7.25 DNS fix for names ending with a dot?
    The cached-NS/empty-AAAA failure is still directly observable on 7.25.
  4. Is there a supported way to prevent cached NS records from being added
    to unrelated negative/NODATA responses while keeping normal DNS caching?
  5. If further diagnostics are required, which captures or logging settings
    would help distinguish the DNS cache insertion and response assembly?

Related public reports

These show related symptoms; they do not establish a confirmed fix for
the exact reproduction above:

7.25 release notes:

Attachments / limitations

  • This draft contains observations and extracted command output from the
    completed live test. No PCAP file or supout.rif is attached.
  • No supout.rif was generated as part of preparing this draft.
  • The 7.25 pass verified the failure with an already-populated NS cache.
    The complete empty-cache/trigger/flush sequence was captured on 7.24.5.
  • The precise internal reason for Unbound rejecting the changed response
    was not traced in source code or verbose logs. The before/after response
    changes and the resulting SERVFAIL were directly observed.

Thank you for any pointers to an existing issue, a fixed version, or a way
to keep normal RouterOS DNS caching without altering these empty replies.

Hi, I observed a simiar issue probaby about one year ago.

I was chasing an issue where a Mitel SIP IP-Phone and a Patton SIP to ISDM Gateway were crashing with some weird resolver buffer overflows. Some devices were affected, other not. The devices crashing all were using a Mikrotik as their DNS server.

Those are simple devices, not supporting DNS ENDS0 thus expecting a DNS UDP Packet to be not more than 512 bytes.

When I traced DNS traffic, I notice the Mikrotik, despite not negotiating EDNS0 was sending replies larger than 512 bytes, violating RFC. To my further surprise, those replies also contained additional records unrelated to the query which blew up the reply packet.

This was halfheartedly fixed on the mikrotik and an option was introduced to specify the max UDP Packetsize for the DNS service which could be lowered to 512 bytes to remain RFC compliant. I don't know if EDNS0 negotiating was fixed.

Since a cache flush clears the bad replies, first confirm the trigger with /ip dns cache print where type=NS to see whether the root NS set is cached, and use /ip dns cache flush as a temporary reset. To keep the Mailcow Unbound unaffected until this is fixed, point its forward zone straight at the two Pi-hole servers so those queries bypass the RouterOS cache. It also helps to compare dig +norecurse AAAA queries against the router and against a Pi-hole, which will show whether only the RouterOS answer carries the extra root NS records in its Authority section. If it reproduces that way, a supout.rif generated on 7.25 attached to a support ticket gives the vendor the exact build and cache state to work from.

Clearing the cache doesn't help—or at most, it helps for a few seconds. The bug is in RouterOS; I reported it to MikroTik via email, and they confirmed that the issue can be reproduced in their lab. They are supposed to release a fix, but it’s not yet clear when.

Interestingly, the timing coincides with CVE-2026-94300.