DNS-based firewall with IP sets

  • This how-to describes the method for setting up DNS-based firewall with IP sets on OpenWrt.
  • It relies on Dnsmasq, ipset-dns and firewall with IP sets to resolve and filter domains.
  • Follow DNS hijacking to intercept DNS queries from your LAN clients.
  • Filter LAN client traffic based on DNS with IP sets.

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.proto="all"
uci set firewall.filter_fwd.family="ipv4"
uci set firewall.filter_fwd.ipset="filter dest"
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.proto="all"
uci set firewall.filter6_fwd.family="ipv6"
uci set firewall.filter6_fwd.ipset="filter6 dest"
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
cat << "EOF" > /etc/firewall.ipsetdns
/etc/init.d/ipset-dns restart
/etc/init.d/dnsmasq restart
cat << "EOF" >> /etc/sysupgrade.conf
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/"
uci add_list dhcp.@dnsmasq[0].server="/example.net/"
uci commit dhcp
/etc/init.d/dnsmasq restart

Flush DNS cache on the clients and restart the client browser. Verify your client traffic is properly filtered on the router.

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

If you want to manage the settings using web interface.

  • Navigate to LuCI → Network → Firewall → Traffic Rules → Filter-IPset-DNS-Forward to manage firewall rules.
  • Navigate to LuCI → Network → DHCP and DNS → General Settings → DNS forwardings to manage domains.

Set up Hotplug extras to preresolve domains and populate IP sets at startup. Use persistent IP sets.

# Install packages
opkg update
opkg install resolveip
# Populate IP sets
mkdir -p /etc/hotplug.d/online
cat << "EOF" > /etc/hotplug.d/online/70-ipset-filter
if [ ! -e /var/lock/ipset-filter ] \
&& lock -n /var/lock/ipset-filter
uci -q delete firewall.filter.entry
uci -q delete firewall.filter6.entry
uci get dhcp.@dnsmasq[0].server \
| sed -e "s/\s/\n/g" \
| sed -n -e "s/^\///;s/\/.*$//p" \
| while read -r IPSET_DOMAIN
resolveip -4 "${IPSET_DOMAIN}" \
| while read -r IPSET_ADDR
uci del_list firewall.filter.entry="${IPSET_ADDR}"
uci add_list firewall.filter.entry="${IPSET_ADDR}"
resolveip -6 "${IPSET_DOMAIN}" \
| while read -r IPSET_ADDR
uci del_list firewall.filter6.entry="${IPSET_ADDR}"
uci add_list firewall.filter6.entry="${IPSET_ADDR}"
uci commit firewall
/etc/init.d/firewall restart
lock -u /var/lock/ipset-filter
cat << "EOF" >> /etc/sysupgrade.conf
. /etc/hotplug.d/online/70-ipset-filter

Limit the restriction scope to a specific source MAC address.

# Apply source restriction
for FW_RULE in filter_fwd filter6_fwd
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"
uci commit firewall
/etc/init.d/firewall restart

Reorder firewall rules and enable time restriction to keep the rules active. Reload kernel timezone to properly apply DST.

# Apply time restriction
for FW_RULE in filter_fwd filter6_fwd
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"
uci commit firewall
/etc/init.d/firewall restart

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 \
/FORWARD.*reject/i $(${IPT}-save -c -t filter \
| sed -n -e "/FORWARD.*ESTABLISHED.*ACCEPT/p")" \
| ${IPT}-restore -c -T filter
cat << "EOF" >> /etc/sysupgrade.conf
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
This website uses cookies. By using the website, you agree with storing cookies on your computer. Also you acknowledge that you have read and understand our Privacy Policy. If you do not agree leave the website.More information about cookies
  • Last modified: 2021/03/24 05:23
  • by vgaetera