Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
Next revisionBoth sides next revision
docs:guide-user:firewall:filtering_traffic_at_ip_addresses_by_dns [2022/05/01 20:16] pliniosenioredocs:guide-user:firewall:filtering_traffic_at_ip_addresses_by_dns [2024/01/13 12:53] – [Improvements] plinioseniore
Line 1: Line 1:
 ====== fw4 Filtering traffic with IP sets by DNS ====== ====== fw4 Filtering traffic with IP sets by DNS ======
-{{section>meta:infobox:howto_links#cli_skills&noheader&nofooter&noeditbutton}}+{{section>meta:infobox:howto_links#basic_skills&noheader&nofooter&noeditbutton}}
  
 ===== Introduction ===== ===== Introduction =====
Line 11: Line 11:
  
 ===== Prerequisites =====  ===== Prerequisites ===== 
-  - You need a firewall zone without forwarding to **wan**, so that no traffic to the internet is allowed by default+  - You need a firewall zone without forwarding to **wan**, so that no traffic to the internet is allowed by default. Below this firewall zone is referenced as //wildlan// 
   - Have **dig** and **grep** installed   - Have **dig** and **grep** installed
-  - 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 
   - Is assumed a standard fw4 configuration with //inet fw4// table   - Is assumed a standard fw4 configuration with //inet fw4// table
  
-===== Command-line instructions ===== +This wiki covers two cases, based on the //dnsmasq// running version. The //Case 1// applies only to //dnsmasq// 2.87 or greater.
  
-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**+===== [CASE 1] Command-line instructions =====  
 + 
 +Install //dnsmasq-full// as follows 
 + 
 +<code bash> 
 +opkg update; cd /tmp/ && opkg download dnsmasq-full; opkg install ipset libnettle8 libnetfilter-conntrack3; 
 +opkg remove dnsmasq; opkg install dnsmasq-full --cache /tmp/; rm -f /tmp/dnsmasq-full*.ipk; 
 +</code> 
 + 
 +Confirm the //dnsmasq// that is running with 
 + 
 +<code bash> 
 +opkg list-installed dns* 
 +</code> 
 + 
 +A valid result should looks like //dnsmasq-full - 2.88-1// 
 + 
 +In ///etc/hotplug.d/iface/20-firewall// 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** 
 + 
 +<code bash> 
 +# 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 \;} 
 +nft insert rule inet fw4 forward_wildlan ip daddr @blackhole accept 
 +</code> 
 + 
 +The //wildlan// zone has no access to internet unless the target IP address is listed in //blackhole//, with //dnsmasq 2.87// we can have that resolved IPs are automatically added to a set. 
 + 
 +Edit **/etc/dnsmasq.conf** with 
 + 
 +<code bash> 
 +# The IP address corresponding to allowed.url URLs will be saved in the nftset (/4# filters for ipv4) 
 +nftset=/first.allowed.urls/4#inet#fw4#blackhole 
 +nftset=/second.allowed.urls/4#inet#fw4#blackhole 
 +... 
 +</code> 
 + 
 +Looking to the case in which you want to ensure that only IP addresses resolved via your DNS are allowed, then use # wildcard. This make sense if you want avoid access via direct IP without a filter for specific URLs. 
 + 
 +<code bash> 
 +nftset=/#/4#inet#fw4#blackhole 
 +</code> 
 + 
 +The relevant IP address of the allowed URLs can be listed with the below command, the set will anyhow remain empty till any of the allowed URLs is resolved via //dnsmasq//
 + 
 +<code bash> 
 +nft list set inet fw4 blackhole 
 +</code> 
 + 
 +===== [CASE 2] Command-line instructions =====  
 + 
 +This applies only for //OpenWrt 22.03//, //OpenWrt 22.03.1// and //OpenWrt 22.03.2// that have an older release of //dnsmasq//. In this case we cannot use //dnsmasq// to automatically fill the IP addresses in the set, so this have to be done with a script. 
 + 
 +In ///etc/hotplug.d/iface/20-firewall// 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**
  
 <code bash> <code bash>
Line 27: Line 79:
 ## Add element to "blackhole" from file urls.txt ## Add element to "blackhole" from file urls.txt
 for address in $(dig a -f /etc/sets-ipdns/wildlan-urls.list +short | grep -v '\.$'); do for address in $(dig a -f /etc/sets-ipdns/wildlan-urls.list +short | grep -v '\.$'); do
- nft add element inet fw4 blackhole {$address}+ nft add element inet fw4 blackhole {$address timeout 24h}
 done done
  
-## Allow packes in "blackhole" (all others are denied by default) 
 nft insert rule inet fw4 forward_wildlan ip daddr @blackhole accept nft insert rule inet fw4 forward_wildlan ip daddr @blackhole accept
 </code> </code>
Line 47: Line 98:
 Based on this forward chain only the traffic with destination to the IP addresses included in @blackhole will 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:+The ///etc/hotplug.d/iface/20-firewall// is executed at any change of any interface (so mostly 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 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. 2. In case of DNS Load Balancing, the same DNS query will result in different IP addresses (all valid) based on time of request.
Line 56: Line 107:
 </code> </code>
  
-In the ///etc/sets-ipdns/update-sets.sh// include the update of sets code from ///etc/rc.local//+In the ///etc/sets-ipdns/update-sets.sh//
  
 <code bash> <code bash>
 ## Add element to "blackhole" from file urls.txt ## Add element to "blackhole" from file urls.txt
 for address in $(dig a -f /etc/sets-ipdns/wildlan-urls.list +short | grep -v '\.$'); do for address in $(dig a -f /etc/sets-ipdns/wildlan-urls.list +short | grep -v '\.$'); do
- nft add element inet fw4 blackhole {$address}+ nft add element inet fw4 blackhole {$address timeout 24h}
 done done
 </code> </code>
Line 77: Line 128:
 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). 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).
  
-===== Limitation ===== +===== Limitations =====
-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.+In //CASE 1// any URL and sub-URL that is listed will be allowed, rather in //CASE 2// only the exact listed URL will be allowed. This make //CASE 2// functionally working only for services that doesn't use multiple sub-URLs.
  
-===== Further improvement ===== +In //CASE 2// the script will periodically query the DNS with all domains included in ///etc/sets-ipdns/wildlan-urls.list// so that list should be reasonably small.
-If the goal is to enforce the [[:docs:guide-user:firewall:fw3_configurations:fw3_parent_controls#blocking_name_resolution_dns_by_adblockers | DNS based filtering ]] this configuration could be modified as follow: +
-  - List of the IP addresses served by the DNS into a //set// using a timeout on the entries +
-  Allow traffic only to the IP addresses in the //set//+
  
-This will require //dnsmasq 2.87// and //--nftset// included in OpenWrt.+===== Next Improvements =====
  
 +The command line instructions are included in ///etc/hotplug.d/iface/20-firewall// that trigger a rebuild of the firewall configuration at each change of any interface. Anyhow this is not trigged when a UCI/LUCI firewall change is applied. So at any change in the firewall configuration the rebuild will not involve the custom rules included in ///etc/hotplug.d/iface/20-firewall//, as result connectivity of devices that rely on this will be lost.
  
 +The rules will be reapplied at next change in status of any interface, that could also be trigged on purpose to rebuild the rules.
  
 +If in next released will be included a custom file for NFT commands that is trigged at any firewall rebuild, this problem will be solved.
  • Last modified: 2024/05/27 21:51
  • by systemcrash