Fixing the VLAN 30 IoT DNS Isolation Leak to Pi-hole
I expect the IoT VLAN to stay isolated: no initiating to trusted segments, DNS that matches the policy, and firewall rules that actually enforce the story. Pi-hole logs were useful here—they showed IoT hostnames resolving through the cluster—but the forward chain on RouterOS did not match how I thought isolation worked. A generic “allow DNS to internal resolvers” rule was winning before the IoT drop, so isolation was weaker than it looked on paper.
This is what was really going on, what I tried first, and what I settled on.
What looked wrong
The first clue was the mismatch between documentation and behavior. IoT clients were using the Pi-hole IPs from DHCP, which I wanted. What I did not want was a broad DNS allow that applied to every source before the rule that actually isolates IoT. First match wins; the allow was too early in the chain.
My state file already labeled VLAN 30 as IoT-only. DHCP for 10.0.30.0/24 was still handing clients the Pi-hole IPs as their DNS servers, which is consistent with “use internal DNS” on paper. The gap was not the DHCP option in isolation. The gap was how RouterOS applied firewall rules around DNS.
What actually caused it
Two things stacked.
DHCP pushed Pi-hole addresses to IoT clients, so every device on VLAN 30 had a perfectly good reason to send DNS to the same servers the rest of the house uses.
Firewall order did the rest. I had a broad allow for DNS toward an address list of internal resolvers—think “DNS_Servers”—that ran before the rule that drops IoT traffic to internal destinations. First match wins on MikroTik. So IoT could reach Pi-hole over DNS even when later rules said “isolate IoT.” The isolation rule never got a chance to fire for that traffic.
So the leak was not magic. It was predictable: DHCP pointed IoT at Pi-hole, and an early allow rule blessed the path.
What I tried and discarded
The quick fix people reach for is “point IoT at 1.1.1.1 and 9.9.9.9 in DHCP and call it done.” I considered that for about as long as it took to remember the exceptions.
A few IoT devices live in address lists that are allowed to reach specific internal services or the WAN when something breaks and I need a controlled escape hatch. If I moved the whole VLAN to public DNS in DHCP, I would have “fixed” the symptom while quietly breaking Pi-hole for the devices that are supposed to stay on internal resolvers when I add them back. I did not want a DHCP setting that fought with exception lists.
So I rejected “public DNS for everyone on VLAN 30” as the final shape of the fix.
What I shipped instead
The durable fix had two parts.
Keep VLAN 30 on Pi-hole in DHCP so the policy stays one story: IoT uses the same resolver IPs I intend to manage, and exception devices still behave when I put them in the right lists.
Fix RouterOS rule ordering so the IoT isolation drop runs before the generic “allow DNS to DNS_Servers” rule. Once that order is correct, IoT traffic to internal DNS stops matching the broad allow. The isolation rule does what the name says.
I also keep a disabled “IoT to internet” style rule in the config for emergencies. It is not part of normal operation; it is a labeled escape hatch if I need to test without hunting through history.
Everything is deployed through Ansible so the router state matches what is in repo, not what I typed once on a late night.
How I think about it now
Address lists are tidy until they interact with rule order. A single “allow DNS to these servers” rule is convenient for trusted VLANs and a footgun for isolated ones if it sits too high in the chain.
state/network.yaml, DHCP options, and forward-chain order all have to tell the same story. If one of them drifts, you get exactly this class of bug: the logs look impossible until you read the chain from the top.
Verification
After the reorder, the forward chain should tell the same story as your docs. I re-checked from an IoT client: for traffic that used to match the generic DNS allow before isolation could run, the first hit is now the isolation rule. The broad allow toward DNS_Servers no longer shortcuts the model.
If you run a similar layout, the practical check is boring and worth it: pick one IoT client, confirm its DNS servers from DHCP, then trace which filter rule hits first for the flows you care about (UDP 53 to the resolvers, plus whatever else your isolation rule covers). First match should match your intent, not an old convenience rule you forgot was above the drop.
The network runs a MikroTik RB4011 for routing and filtering and a MikroTik CRS326 for switching; Pi-hole lives with the rest of the services VLAN. Same stack as in my broader VLAN write-up.
Disclosure: This article contains affiliate links. If you purchase through these links, I may earn a commission at no extra cost to you.
Related reading
Selective internet access for IoT devices with RouterOS address lists
VLAN 30 blocks all IoT traffic from the internet by default. This is how I punch selective holes for specific devices without rewriting the firewall per device.
Troubleshooting RouterOS Local Gateway IP Unreachability
SSH to the router worked from other VLANs but not from the same VLAN as the gateway. What I ruled out, what still does not have a clean root cause, and the workaround that kept management sane.
Auditing static DHCP leases in RouterOS: ten mismatches and four missing devices
What happens when your DHCP config drifts from your network state file. How I found fourteen lease issues in RouterOS and fixed them with Ansible and a device-by-device review.
Ready to Transform Your Career?
Let's work together to unlock your potential and achieve your professional goals.