This is an old revision of the document!
DNS-based firewall with IP sets
Introduction
- This how-to describes the method for setting up DNS-based firewall with IP sets on OpenWrt.
- Follow DNS hijacking to intercept DNS queries from your LAN clients.
Goals
- Filter LAN client traffic based on DNS with IP sets.
Instructions
Install the packages and configure IP sets for domains to filter. Set up firewall rules to filter LAN client traffic which destination matches the IP sets. Configure the domains which addresses should be stored in the IP sets.
# Install packages opkg update opkg install dnsmasq ipset ipset-dns # Configure IP sets uci -q delete firewall.filter uci set firewall.filter="ipset" uci set firewall.filter.name="filter" uci set firewall.filter.family="ipv4" uci set firewall.filter.storage="hash" uci set firewall.filter.match="ip" uci -q delete firewall.filter6 uci set firewall.filter6="ipset" uci set firewall.filter6.name="filter6" uci set firewall.filter6.family="ipv6" uci set firewall.filter6.storage="hash" uci set firewall.filter6.match="ip" # Filter LAN client traffic with IP sets uci -q delete firewall.filter_fwd uci set firewall.filter_fwd="rule" uci set firewall.filter_fwd.name="Filter-IPset-DNS-Forward" uci set firewall.filter_fwd.src="lan" uci set firewall.filter_fwd.dest="wan" uci set firewall.filter_fwd.ipset="filter dest" uci set firewall.filter_fwd.family="ipv4" uci set firewall.filter_fwd.proto="all" uci set firewall.filter_fwd.target="REJECT" uci -q delete firewall.filter6_fwd uci set firewall.filter6_fwd="rule" uci set firewall.filter6_fwd.name="Filter-IPset-DNS-Forward" uci set firewall.filter6_fwd.src="lan" uci set firewall.filter6_fwd.dest="wan" uci set firewall.filter6_fwd.ipset="filter6 dest" uci set firewall.filter6_fwd.family="ipv6" uci set firewall.filter6_fwd.proto="all" uci set firewall.filter6_fwd.target="REJECT" uci commit firewall /etc/init.d/firewall restart # Configure ipset-dns uci set ipset-dns.@ipset-dns[0].ipset="filter" uci set ipset-dns.@ipset-dns[0].ipset6="filter6" uci commit ipset-dns /etc/init.d/ipset-dns restart # Resolve race conditions for ipset-dns cat << "EOF" > /etc/firewall.ipsetdns /etc/init.d/ipset-dns restart EOF cat << "EOF" >> /etc/sysupgrade.conf /etc/firewall.ipsetdns EOF uci -q delete firewall.ipsetdns uci set firewall.ipsetdns="include" uci set firewall.ipsetdns.path="/etc/firewall.ipsetdns" uci set firewall.ipsetdns.reload="1" uci commit firewall /etc/init.d/firewall restart # Configure domains to filter uci add_list dhcp.@dnsmasq[0].server="/example.com/127.0.0.1#53001" uci add_list dhcp.@dnsmasq[0].server="/example.net/127.0.0.1#53001" uci commit dhcp /etc/init.d/dnsmasq restart
Testing
Flush DNS cache on the clients and restart the client browser. Verify your client traffic is properly filtered on the router.
Troubleshooting
Collect and analyze the following information.
# Restart services /etc/init.d/log restart; /etc/init.d/firewall restart /etc/init.d/ipset-dns restart; /etc/init.d/dnsmasq restart # Log and status logread -e dnsmasq; netstat -l -n -p | grep -e dnsmasq logread -e ipset-dns; netstat -l -n -p | grep -e ipset-dns # Runtime configuration pgrep -f -a dnsmasq; pgrep -f -a ipset-dns iptables-save; ip6tables-save; ipset list # Persistent configuration uci show firewall; uci show dhcp; uci show ipset-dns
Extras
Web interface
If you want to manage the settings using web interface.
Preresolve domains
Preresolve domains at startup.
# Preresolve domains cat << "EOF" > /etc/firewall.dnsmasq /etc/init.d/dnsmasq restart uci get dhcp.@dnsmasq[0].server \ | sed -e "s/\s/\n/g" \ | sed -n -e "s/^\///;s/\/.*$//p" \ | while read -r IPSET_DOMAIN do nslookup "${IPSET_DOMAIN}" localhost done EOF cat << "EOF" >> /etc/sysupgrade.conf /etc/firewall.dnsmasq EOF uci -q delete firewall.dnsmasq uci set firewall.dnsmasq="include" uci set firewall.dnsmasq.path="/etc/firewall.dnsmasq" uci set firewall.dnsmasq.reload="1" uci commit firewall /etc/init.d/firewall restart
Persistent IP sets
Disable domain preresolving. Use persistent IP sets. Save IP sets daily at midnight.
# Disable domain preresolving uci set firewall.dnsmasq.enabled="0" # Use persistent IP sets cat << "EOF" > /etc/firewall.ipset-save ipset save > /etc/ipset.save EOF cat << "EOF" > /etc/firewall.ipset-restore ipset -! restore < /etc/ipset.save EOF cat << "EOF" >> /etc/sysupgrade.conf /etc/firewall.ipset-save /etc/firewall.ipset-restore /etc/ipset.save EOF uci -q delete firewall.ipset uci set firewall.ipset="include" uci set firewall.ipset.path="/etc/firewall.ipset-restore" uci set firewall.ipset.reload="1" uci commit firewall /etc/init.d/firewall restart # Save IP sets daily cat << "EOF" >> /etc/crontabs/root 0 0 * * * sh /etc/firewall.ipset-save EOF /etc/init.d/cron restart # Populate and save IP sets sh /etc/firewall.dnsmasq sh /etc/firewall.ipset-save
Source restriction
Limit the restriction scope to a specific source MAC address.
# Apply source restriction for FW_RULE in filter_fwd filter6_fwd do uci add_list firewall.${FW_RULE}.src_mac="11:22:33:44:55:66" uci add_list firewall.${FW_RULE}.src_mac="aa:bb:cc:dd:ee:ff" done uci commit firewall /etc/init.d/firewall restart
Time restriction
Reorder firewall rules and enable time restriction to keep the rules active.
# Apply time restriction for FW_RULE in filter_fwd filter6_fwd do uci set firewall.${FW_RULE}.start_time="21:00:00" uci set firewall.${FW_RULE}.stop_time="09:00:00" uci set firewall.${FW_RULE}.weekdays="Mon Tue Wed Thu Fri" done uci commit firewall /etc/init.d/firewall restart
Established connections
Reorder firewall rules to properly apply time restrictions.
# Reorder firewall rules cat << "EOF" > /etc/firewall.estab for IPT in iptables ip6tables do ${IPT}-save -c -t filter \ | sed -e "/FORWARD.*ESTABLISHED.*ACCEPT/d; /FORWARD.*reject/i $(${IPT}-save -c -t filter \ | sed -n -e "/FORWARD.*ESTABLISHED.*ACCEPT/p")" \ | ${IPT}-restore -c -T filter done EOF cat << "EOF" >> /etc/sysupgrade.conf /etc/firewall.estab EOF uci -q delete firewall.estab uci set firewall.estab="include" uci set firewall.estab.path="/etc/firewall.estab" uci set firewall.estab.reload="1" uci commit firewall /etc/init.d/firewall restart