fw4 Filtering traffic with IP sets by DNS

This guide create a set of IP address for traffic filtering, is an equivalent of dns_ipset based on nftables/fw4 that is the default starting from OpenWrt 22.03.

Avoid bypass of DNS based filtering with direct connection to the IP address of the website or with DoH. The general use case is a traffic restriction to be applied for SmartTV, IoT and other devices for which you may want to force a limited internet access.

To reach this goal a set of IP addresses is created from a list of allowed or denied domains, a firewall rule to allow or deny traffic to those IP address is then created. The below example refer to the allow case for a specific interface called wildlan.

  1. You need a firewall zone without forwarding to wan, so that no traffic to the internet is allowed by default
  2. Have dig and grep installed
  3. Create a new interface (called wildlan in the below example) for which no forward is set in the firewall settings, so that only IP addresses in the set will be allowed
  4. Is assumed a standard fw4 configuration with inet fw4 table

In /etc/rc.local add the below code to create the nft set in which we will save the IP addresses, the proposed code is ipv4 only but can be extended to cover ipv6

# Filter wildlan by IP addresses
## Create a set for "inet fw4" table with name "blackhole" that can include "ipv4_addr"
nft add set inet fw4 blackhole { type ipv4_addr \;}
 
## Add element to "blackhole" from file urls.txt
for address in $(dig a -f /etc/sets-ipdns/wildlan-urls.list +short | grep -v '\.$'); do
	nft add element inet fw4 blackhole {$address}
done
 
## Allow packes in "blackhole" (all others are denied by default)
nft insert rule inet fw4 forward_wildlan ip daddr @blackhole accept

The list of domains to which traffic will be allowed shall be included in a the custom file /etc/sets-ipdns/wildlan-urls.list, to create the file

cd /etc
mkdir sets-ipdns
cd sets-ipdns
vim wildlan-urls.list

List inside vim the domain names that shall be allowed.

Based on this forward chain only the traffic with destination to the IP addresses included in @blackhole will be allowed.

The rc.local is executed at boot time, so that @blackhole will be filled with IP addresses only at that stage. That set shall be periodically updated for two reasons: 1. The IP addresses may change 2. In case of DNS Load Balancing, the same DNS query will result in different IP addresses (all valid) based on time of request.

In the Scheduled Task in Luci or in /etc/crontabs/root we execute every 15 minutes a script to update the sets

15 * * * * /etc/sets-ipdns/update-sets.sh

In the /etc/sets-ipdns/update-sets.sh include the update of sets code from /etc/rc.local

## Add element to "blackhole" from file urls.txt
for address in $(dig a -f /etc/sets-ipdns/wildlan-urls.list +short | grep -v '\.$'); do
	nft add element inet fw4 blackhole {$address}
done

Enable the script and reboot

chmod +x /etc/sets-ipdns/update-sets.sh
reboot

After the reboot, verify the content of the @blackhole and the result should be a list of ipv4 addresses.

nft list set inet fw4 blackhole

The final crosscheck is to verify that addresses listed in /etc/sets-ipdns/wildlan-urls.list can be accessed, no other domains should be accessible unless the same IP address is shared between multiple domains (that happen with CDNs).

This approach will query periodically the DNS with all domains included in /etc/sets-ipdns/wildlan-urls.list so that list should be reasonably small.

With this type of approach the DNS query executed by a device that want to connect and the one executed by this script happens in different time and the DNS may reply with a different IP address, so it may happen that a device try to connect to an IP address that is not included in the list.

If the goal is to enforce the DNS based filtering this configuration could be modified as follow:

  1. List of the IP addresses served by the DNS into a set using a timeout on the entries
  2. Allow traffic only to the IP addresses in the set

This will require dnsmasq 2.87 and –nftset included in OpenWrt.

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: 2022/05/01 16:18
  • by plinioseniore