v23/DSA setup with DNS-filter on an external device

The goal is to set up OpenWRT router with AdGuardHome on a separate device (as AdGuardHome requires more resources than the decent router can afford, also for the purposes of statistics).

I couldn't find a comprehensive manual, and would be happy to write one as soon as I make it work. I followed this wiki (slightly altered and fixed a pair of issues in https://openwrt.org/docs/guide-user/network/wifi/guestwifi/configuration_command_line_interface) to set up networks and firewall for IoT network isolation (it should have the DNS-filtered access to the internet, but not to the other local networks, the other local networks should have access to the devices on this network).

Then I followed this post to set up OpenWRT to work with AdGuardHome [How-To-Updated 2021] Installing AdGuardHome on OpenWrt [Manual and opkg method], but changed it as if my DNS is upstream (pointed DHCP option 6 to the static ip of RaspberryPi).

I tried directions for the upstream DNS from this recommended comment Correct Way to Set DNS Server - #24 by willowen100.

My problem is: there is no way I could make DNS work in IoT network.

I had to run dnsmasq with noresolv='1', but ideally I would like it to work either as a failover or at least for the local discover. Because AdGuardHome being a single DNS for all purposes seems like a central point of failure. It's set up on RaspberryPi 3B+ which is powerful enough, but SD card is not designed for this kind of usage. AdGuardHome is set up to listen on a static 192.168.2.3 port 53

Following the guest-wlan wiki I created a network which is built on a software bridge, which doesn't have a device underneath. This is the difference from the LAN network, which is built on br-lan that bridges lan1 and lan2 physical ports. I tried to mess with devices but it brings even more unpredictable variables. Sometimes I get locked out for no reason I understand, sometimes the connection is silently list I have to deduct to restart the wan or any other interface which I never touched, or the full router. The most annoying thing is that if I include IoT network in the LAN firewall zone, it will get DNS and work effortlessly, but that's not the goal. It's a pointer that the problem might be in firewall, but I couldn't find where exactly. Please help me good sirs.

# ubus call system board
{
	"kernel": "5.15.137",
	"hostname": "OpenWrt",
	"system": "ARMv7 Processor rev 5 (v7l)",
	"model": "GL.iNet GL-B1300",
	"board_name": "glinet,gl-b1300",
	"rootfs_type": "squashfs",
	"release": {
		"distribution": "OpenWrt",
		"version": "23.05.2",
		"revision": "r23630-842932a63d",
		"target": "ipq40xx/generic",
		"description": "OpenWrt 23.05.2 r23630-842932a63d"
# cat /etc/config/dhcp

config dnsmasq
	option domainneeded '1'
	option localise_queries '1'
	option rebind_protection '0'
	option local '/lan/'
	option domain 'lan'
	option expandhosts '1'
	option cachesize '1000'
	option authoritative '1'
	option readethers '1'
	option leasefile '/tmp/dhcp.leases'
	option localservice '1'
	option ednspacket_max '1232'
	option port '54'
	list server '192.168.2.3'
	option noresolv '1'

config dhcp 'lan'
	option interface 'lan'
	option start '100'
	option limit '150'
	option leasetime '24h'
	option dhcpv4 'server'
	option dhcpv6 'server'
	option ra 'server'
	list ra_flags 'managed-config'
	list ra_flags 'other-config'
	list dhcp_option '6,192.168.2.3'
	list dns '::ffff:192.168.2.3'

config dhcp 'wan'
	option interface 'wan'
	option ignore '1'
	option start '100'
	option limit '150'
	option leasetime '12h'

config odhcpd 'odhcpd'
	option maindhcp '0'
	option leasefile '/tmp/hosts/odhcpd'
	option leasetrigger '/usr/sbin/odhcpd-update'
	option loglevel '4'

config dhcp 'IoT'
	option interface 'IoT'
	option start '100'
	option limit '150'
	option leasetime '12h'
	list dhcp_option '6,192.168.2.3'

config host
	option name 'raspberrypi'
	option mac 'B8:27:EB:61:55:76'
	option ip '192.168.2.3'
	option leasetime 'infinite'
	option duid '000100012be4692cb827eb615576'
	list match_tag 'known'
	option instance '0'
	option dns '1'
# cat /etc/config/network

config interface 'loopback'
	option device 'lo'
	option proto 'static'
	option ipaddr '127.0.0.1'
	option netmask '255.0.0.0'

config globals 'globals'
	option ula_prefix 'fde1:4999:41ef::/48'

config device
	option name 'br-lan'
	option type 'bridge'
	list ports 'lan1'
	list ports 'lan2'
	option acceptlocal '1'
	option igmp_snooping '1'

config interface 'lan'
	option device 'br-lan'
	option proto 'static'
	option ipaddr '192.168.2.1'
	option netmask '255.255.255.0'
	option ip6assign '60'

config interface 'wan'
	option device 'wan'
	option proto 'static'
	option ipaddr '192.168.1.2'
	option netmask '255.255.255.0'
	option gateway '192.168.1.1'
	option peerdns '0'
	list dns '1.1.1.1'
	list dns '1.0.0.1'

config device 'IoT_dev'
	option type 'bridge'
	option name 'br-IoT'
	option igmp_snooping '1'
	option acceptlocal '1'

config interface 'IoT'
	option proto 'static'
	option device 'br-IoT'
	list ipaddr '192.168.13.1/24'
	option gateway '192.168.2.1'
# cat /etc/config/firewall

config defaults
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option synflood_protect '1'

config zone
	option name 'lan'
	option input 'ACCEPT'
	option output 'ACCEPT'
	option forward 'ACCEPT'
	list network 'lan'

config zone
	option name 'wan'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	option masq '1'
	option mtu_fix '1'
	list network 'wan'

config forwarding
	option src 'lan'
	option dest 'wan'

config rule
	option name 'Allow-DHCP-Renew'
	option src 'wan'
	option proto 'udp'
	option dest_port '68'
	option target 'ACCEPT'
	option family 'ipv4'

config rule
	option name 'Allow-Ping'
	option src 'wan'
	option proto 'icmp'
	option icmp_type 'echo-request'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-IGMP'
	option src 'wan'
	option proto 'igmp'
	option family 'ipv4'
	option target 'ACCEPT'

config rule
	option name 'Allow-DHCPv6'
	option src 'wan'
	option proto 'udp'
	option dest_port '546'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-MLD'
	option src 'wan'
	option proto 'icmp'
	option src_ip 'fe80::/10'
	list icmp_type '130/0'
	list icmp_type '131/0'
	list icmp_type '132/0'
	list icmp_type '143/0'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Input'
	option src 'wan'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	list icmp_type 'router-solicitation'
	list icmp_type 'neighbour-solicitation'
	list icmp_type 'router-advertisement'
	list icmp_type 'neighbour-advertisement'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-ICMPv6-Forward'
	option src 'wan'
	option dest '*'
	option proto 'icmp'
	list icmp_type 'echo-request'
	list icmp_type 'echo-reply'
	list icmp_type 'destination-unreachable'
	list icmp_type 'packet-too-big'
	list icmp_type 'time-exceeded'
	list icmp_type 'bad-header'
	list icmp_type 'unknown-header-type'
	option limit '1000/sec'
	option family 'ipv6'
	option target 'ACCEPT'

config rule
	option name 'Allow-IPSec-ESP'
	option src 'wan'
	option dest 'lan'
	option proto 'esp'
	option target 'ACCEPT'

config rule
	option name 'Allow-ISAKMP'
	option src 'wan'
	option dest 'lan'
	option dest_port '500'
	option proto 'udp'
	option target 'ACCEPT'

config zone 'iot'
	option name 'iot'
	option input 'REJECT'
	option output 'ACCEPT'
	option forward 'REJECT'
	list network 'iot'
	list network 'IoT'

config forwarding 'iot_wan'
	option src 'iot'
	option dest 'wan'

config forwarding 'lan_iot'
	option src 'lan'
	option dest 'iot'

config rule 'iot_dns'
	option name 'Allow-DNS-iot'
	option src 'iot'
	option dest_port '53'
	list proto 'tcp'
	list proto 'udp'
	option target 'ACCEPT'
	list dest_ip '192.168.2.3'

config rule 'iot_dhcp'
	option name 'Allow-DHCP-iot'
	option src 'iot'
	option dest_port '67'
	option proto 'udp'
	option family 'ipv4'
	option target 'ACCEPT'
$ cat /opt/AdGuardHome.yaml
http:
  pprof:
    port: 6060
    enabled: false
  address: 192.168.2.3:80
  session_ttl: 720h
users:
  - name: [xxx]
    password: [xxx]
auth_attempts: 5
block_auth_min: 15
http_proxy: ""
language: en
theme: auto
dns:
  bind_hosts:
    - 127.0.0.1
    - 192.168.2.3
    - ::1
    - ::ffff:192.168.2.3
  port: 53
  anonymize_client_ip: false
  ratelimit: 20
  ratelimit_subnet_len_ipv4: 24
  ratelimit_subnet_len_ipv6: 56
  ratelimit_whitelist: []
  refuse_any: true
  upstream_dns:
    - https://dns.cloudflare.com/dns-query
    - https://dns10.quad9.net/dns-query
    - https://unfiltered.adguard-dns.com/dns-query
    - h3://unfiltered.adguard-dns.com/dns-query
    - '[/pool.ntp.org/]1.1.1.1'
    - '[/pool.ntp.org/]1.0.0.1'
    - '[/lan/]127.0.0.1'
    - '[//]127.0.0.1'
  upstream_dns_file: ""
  bootstrap_dns:
    - 9.9.9.10
    - 149.112.112.10
    - 2620:fe::10
    - 2620:fe::fe:10
    - 1.1.1.1
    - 1.0.0.1
  fallback_dns:
    - 1.1.1.1
    - 1.0.0.1
    - 9.9.9.9
  all_servers: false
  fastest_addr: false
  fastest_timeout: 1s
  allowed_clients: []
  disallowed_clients: []
  blocked_hosts:
    - version.bind
    - id.server
    - hostname.bind
  trusted_proxies:
    - 127.0.0.0/8
    - ::1/128
  cache_size: 4194304
  cache_ttl_min: 0
  cache_ttl_max: 0
  cache_optimistic: true
  bogus_nxdomain: []
  aaaa_disabled: false
  enable_dnssec: false
  edns_client_subnet:
    custom_ip: ""
    enabled: false
    use_custom: false
  max_goroutines: 300
  handle_ddr: true
  ipset: []
  ipset_file: ""
  bootstrap_prefer_ipv6: false
  upstream_timeout: 10s
  private_networks: []
  use_private_ptr_resolvers: true
  local_ptr_upstreams:
    - 192.168.2.3:53
    - 127.0.0.1
  use_dns64: false
  dns64_prefixes: []
  serve_http3: false
  use_http3_upstreams: false
  serve_plain_dns: true
tls:
  enabled: false
  [xxx]
querylog:
  ignored: []
  interval: 2160h
  size_memory: 1000
  enabled: true
  file_enabled: true
statistics:
  ignored: []
  interval: 24h
  enabled: true
filters:
  - [xxx]
whitelist_filters: []
user_rules:
  - [xxx]
dhcp:
  enabled: false
  [xxx]
filtering:
  blocking_ipv4: ""
  blocking_ipv6: ""
  blocked_services:
	[xxx]
  protection_disabled_until: null
  safe_search:
    enabled: false
    [xxx]
  blocking_mode: default
  parental_block_host: family-block.dns.adguard.com
  safebrowsing_block_host: standard-block.dns.adguard.com
  rewrites: []
  safebrowsing_cache_size: 1048576
  safesearch_cache_size: 1048576
  parental_cache_size: 1048576
  cache_time: 30
  filters_update_interval: 24
  blocked_response_ttl: 10
  filtering_enabled: true
  parental_enabled: false
  safebrowsing_enabled: false
  protection_enabled: true
clients:
  runtime_sources:
    whois: true
    arp: true
    rdns: true
    dhcp: true
    hosts: true
  persistent: []
log:
  file: ""
  max_backups: 0
  max_size: 100
  max_age: 3
  compress: false
  local_time: false
  verbose: false
os:
  group: ""
  user: ""
  rlimit_nofile: 0
schema_version: 27

You omitted to specify the destination (lan) zone.
Thus, the rule is erroneously created in the input_iot instead of the forward_iot chain.

2 Likes

You are correct indeed good Sir! You saved me another day!

I didn't even care to check those rules logic as they came from a supposedly well-established wiki article: https://openwrt.org/docs/guide-user/network/wifi/guestwifi/configuration_command_line_interface. Though, as I mentioned, while applying it I had to correct that script in a couple places.

I'd like to edit that wiki, but need wiki admin attendance: manually registering me.
Otherwise, the offending lines were:

  • This part does random things if there are already some custom networks. Also FW_WAN resolved into lan with a default configuration.

    # Configuration parameters
    NET_ID="guest"
    WIFI_DEV="$(uci -q get wireless.@wifi-iface[0].device)"
     
    # Fetch upstream zone
    . /lib/functions/network.sh
    network_flush_cache
    network_find_wan NET_IF
    FW_WAN="$(fw4 -q network ${NET_IF})"
    
  • add set firewall.${NET_ID}_dns.dest=lan here:

    delete firewall.${NET_ID}_dns
    set firewall.${NET_ID}_dns=rule
    set firewall.${NET_ID}_dns.name=Allow-DNS-${NET_ID}
    set firewall.${NET_ID}_dns.src=${NET_ID}
    set firewall.${NET_ID}_dns.dest_port=53
    add_list firewall.${NET_ID}_dns.proto=tcp
    add_list firewall.${NET_ID}_dns.proto=udp
    set firewall.${NET_ID}_dns.target=ACCEPT
    

Your case is specific because you are using an external DNS server that is located in the lan zone.

The commands on the linked page automatically create a guest network for you, but the router itself is used as a DNS server.

2 Likes

you're right. But it won't hurt to create another wiki article or a post describing this not-so-specific use-case, in the light of AGH no longer fits storage or RAM of many routers nowadays.

1 Like

This topic was automatically closed 10 days after the last reply. New replies are no longer allowed.