Skip to content

LAN DNS traffic is no longer redirected to dnsmasq #1871

Closed

Description

@m-dilorenzi

Steps to reproduce

  • Enable Threat Shield DNS from the UI (Security > Threat Shield DNS) selecting the lan zone
  • Check the resulting configuration: uci show adblock.global.adb_nftdevforce → 'lan'
  • Resolve the actual device behind that zone: the zone lan maps to network green, which maps to device eth0
  • Inspect the generated ruleset: nft list chain inet adblock pre-routing
  • From a LAN client, send a DNS query to an external resolver, bypassing the firewall's DNS: dig @8.8.8.8 -x <client_ip> +short

Expected behavior

DNS traffic from the selected zones is redirected to the local dnsmasq instance on port 53, and DoT on port 853 is rejected, so that clients configured with a custom DNS server are still filtered by Threat Shield DNS.

Actual behavior

The enforcement rules are generated using the firewall zone name as iifname. Since iifname matches on the actual network device name, the rules never match any packet and the counters stay at zero:

root@NethSec:~# nft list chain inet adblock pre-routing
table inet adblock {
	chain pre-routing {
		type nat hook prerouting priority mangle; policy accept;
		iifname "lan" meta nfproto { ipv4, ipv6 } meta l4proto { tcp, udp } th dport 53 counter packets 0 bytes 0 redirect to :53
		iifname "lan" meta nfproto { ipv4, ipv6 } meta l4proto { tcp, udp } th dport 853 counter packets 0 bytes 0 goto _reject
	}
}

The value should be a network device (eth0 in this setup), not a zone name:

adblock.global.adb_nftdevforce='lan'    # actual
adblock.global.adb_nftdevforce='eth0'   # expected

Workaround

Add the enforcement rules manually, using the real device name instead of the zone name. Retrieve the device of each zone you want to enforce:

. /lib/functions/network.sh
network_get_device dev green && echo "$dev"

Then add the rules to the existing chain (replace eth0 with the device from the previous command):

nft add rule inet adblock pre-routing iifname "eth0" \
    meta nfproto { ipv4, ipv6 } meta l4proto { udp, tcp } th dport 53 counter redirect to :53
nft add rule inet adblock pre-routing iifname "eth0" \
    meta nfproto { ipv4, ipv6 } meta l4proto { udp, tcp } th dport 853 counter goto _reject

Verify with nft list chain inet adblock pre-routing that the counters start increasing.

Caveat: these rules live in memory only. They are lost on reboot and every time adblock is reloaded or restarted — including the scheduled cron reload — so they need to be re-applied, e.g. from a hotplug/startup script.

Activity

  1. added theissue type on Aug 6, 2026
  2. moved this from ToDo 🕐 to In Progress 🛠 in NethSecurityon Aug 26, 2026
  3. added this to the 8.8.1 milestone on Aug 26, 2026
  4. m-dilorenzi commented on Aug 27, 2026

    @m-dilorenzi
    CollaboratorAuthor

    QA

    Image: dev image

    Fresh image install (config from scratch)

    1. Install NethSecurity from the new image.
    2. Log in to the NethSecurity.
    3. Go to Security > Threat Shield DNS, select the lan zone (the green zone) and enable the service.
    4. Verify the user selection is stored as a zone:
      uci show adblock.global.ns_tsdns_zones
      # expected: adblock.global.ns_tsdns_zones='lan'
      
    5. Verify the derived value contains the device and not the zone name:
      uci show adblock.global.adb_nftdevforce
      # expected: adblock.global.adb_nftdevforce='eth0'   (device of 'green'/'lan')
      # must NOT be 'lan'
      
    6. Verify the nft rules match on the device iifname:
      nft list chain inet adblock pre-routing
      # expected: iifname "eth0" ... th dport 53 ... redirect to :53
      #           iifname "eth0" ... th dport 853 ... goto _reject
      
    7. From a LAN client, force a DNS query to an external resolver (bypassing the firewall's DNS):
      dig @8.8.8.8 example.com +short
      
    8. On the firewall, verify the counters on the port-53 rule have increased (no longer 0):
      nft list chain inet adblock pre-routing
      # expected: counter packets > 0 on the dport 53 rule
      

    Migration of an old broken system (broken → repaired)

    1. Start from a system with NethSecurity 8.8.0
    2. Log in to the NethSecurity.
    3. Go to Security > Threat Shield DNS, select the lan zone (the green zone) and enable the service.
    4. Confirm the broken configuration state
      uci show adblock.global.adb_nftdevforce
      adblock.global.adb_nftdevforce='green'/'lan'
      
      nft list chain inet adblock pre-routing
      # iifname "green/lan" ... th dport 53 ... redirect to :53
      # iifname "green/lan" ... th dport 853 ... goto _reject
      
    5. Build the ns-threat_shield and ns-api packages and copy them to the machine and install the two packages with apk add command to simulate the packages update.
    6. Verify the selection was moved to ns_tsdns_zones and the devices were rebuilt:
      uci show adblock.global.ns_tsdns_zones     # expected: 'lan' or 'green'
      uci show adblock.global.adb_nftdevforce     # expected: 'eth0'
      
    7. Verify adblock was restarted and the rules are correct:
      nft list chain inet adblock pre-routing     # iifname "eth0"
      
    8. Repeat steps 7–9 of the first scenario (dig + counter check) to confirm interception.
    9. Idempotency: run the migration again and verify it changes nothing:
      /usr/libexec/ts-dns-migrate-devices
      uci show adblock.global.ns_tsdns_zones      # unchanged
      uci show adblock.global.adb_nftdevforce      # unchanged
      

    New interface in an enforced zone

    1. With Threat Shield DNS enabled on the lan zone, note the current devices:
      uci show adblock.global.adb_nftdevforce      # e.g. 'eth0'
      
    2. Add a second interface (e.g. eth2) to the lan/green zone from the UI (or via uci) and save/commit.
    3. Verify the device was added automatically:
      uci show adblock.global.adb_nftdevforce      # expected: 'eth0' 'eth2'
      nft list chain inet adblock pre-routing       # rules with iifname for both devices
      
    4. Executedig command from a client on the new interface and verify the counters rise.
    5. Remove the interface from the zone and verify the device is dropped from adb_nftdevforce.
  5. added
    testingPackages are available from testing repositories
    on Aug 27, 2026
  6. moved this from In Progress 🛠 to Testing in NethSecurityon Aug 27, 2026
  7. Tbaile commented on Sep 3, 2026

    @Tbaile
    Collaborator

    I've got a single KO from the upgrade path, probably related to adblock and our code.

    I've did an image upgrade, instead of the packages cause I didn't read properly, this made the adblock completely ineffective.
    NFT rules are good, but blocking doesn't happen, when we dive into adblock status we are missing versions of adblock.

    root@NethSecVM:~# /etc/init.d/adblock status
    ::: adblock runtime information
      + adblock_status  : enabled
      + frontend_ver    : -
      + backend_ver     : -
      + blocked_domains : 47 536
      + active_feeds    : piracy
    

    A restart of only adblock populates the versions and the blocking now works.
    However, rebooting the machine makes adblock lock itself again.
    I need further investigation on the matter.

  8. Tbaile commented on Sep 4, 2026

    @Tbaile
    Collaborator

    KO is not related to this issue, see: #1885

  9. moved this from Testing to Verified in NethSecurityon Sep 4, 2026
  10. added
    verifiedAll test cases were verified successfully
    and removed
    testingPackages are available from testing repositories
    on Sep 4, 2026
  11. moved this from Verified to Done ✅ in NethSecurityon Sep 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

verifiedAll test cases were verified successfully

Type

Projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions