[openwrt/openwrt] dnsmasq: Support nftables nftsets

LEDE Commits lede-commits at lists.infradead.org
Sun Nov 6 11:48:25 PST 2022


ldir pushed a commit to openwrt/openwrt.git, branch master:
https://git.openwrt.org/d7f378796f985c902ff7906767c275c40a15347f

commit d7f378796f985c902ff7906767c275c40a15347f
Author: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
AuthorDate: Mon Nov 29 17:16:39 2021 +0000

    dnsmasq: Support nftables nftsets
    
    Add build option for nftables sets. By default disable iptables ipset
    support.  By default enable nftable nftset support since this is what
    fw4 uses.
    
    Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
    
    dnsmasq: nftset: serve from ipset config
    
    Use existing ipset configs as source for nftsets to be compatible with
    existing configs. As the OS can either have iptables XOR nftables
    support, it's fine to provide both to dnsmasq. dnsmasq will silently
    fail for the present one. Depending on the dnsmasq compile time options,
    the ipsets or nftsets option will not be added to the dnsmasq config
    file.
    
    dnsmasq will try to add the IP addresses to all sets, regardless of the
    IP version defined for the set. Adding an IPv6 to an IPv4 set and vice
    versa will silently fail.
    
    Signed-off-by: Mathias Kresin <dev at kresin.me>
    
    dnsmasq: support populating nftsets in addition to ipsets
    
    Tell dnsmasq to populate nftsets instead of ipsets, if firewall4 is present in
    the system. Keep the same configuration syntax in /etc/config/dhcp, for
    compatibility purposes.
    
    Huge thanks to Jo-Philipp Wich for basically writing the function.
    
    Signed-off-by: Jo-Philipp Wich <jo at mein.io>
    Signed-off-by: Rui Salvaterra <rsalvaterra at gmail.com>
    
    dnsmasq: obtain nftset ip family from nft
    
    Unfortunately dnsmasq nft is noisy if an attempt to add a mismatched ip address
    family to an nft set is made.
    
    Heuristic to guess which ip family a nft set might belong by inferring
    from the set name.
    
    In order of preference:
    
    If setname ends with standalone '4' or '6' use that, else
    if setname has '4' or '6' delimited by '-' or '_' use that (eg
    foo-4-bar) else
    If setname begins with '4' or '6' standalone use that.
    
    By standalone I mean not as part of a larger number eg. 24
    
    If the above fails then use the existing nft set query mechanism and if
    that fails, well you're stuffed!
    
    With-thanks-to: Jo-Philipp Wich <jo at mein.io> who improved my regexp
    knowledge.
    
    Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
    
    dnsmasq: specify firewall table for nftset
    
    Permit ipsets to specify an nftables table for the set.  New config
    parameter is 'table'.  If not specified the default of 'fw4' is used.
    
    config ipset
            list name 'BK_4,BK_6'
            option table 'dscpclassify'
            option table_family 'ip'
            option family '4'
            list domain 'ms-acdc.office.com'
            list domain 'windowsupdate.com'
            list domain 'update.microsoft.com'
            list domain 'graph.microsoft.com'
            list domain '1drv.ms'
            list domain '1drv.com'
    
    The table family can also be specified, usually 'ip' or 'ip6' else the
    default 'inet' capable of both ipv4 & ipv6 is used.
    
    If the table family is not specified then finally a family option is
    available to specify either '4' or '6' for ipv4 or ipv6 respectively.
    
    This is all in addition to the existing heuristic that will look in the
    nftset name for an ip family clue, or in total desperation, query the
    value from the nftset itself.
    
    Signed-off-by: Kevin Darbyshire-Bryant <ldir at darbyshire-bryant.me.uk>
---
 package/network/services/dnsmasq/Makefile          | 12 +++++--
 .../network/services/dnsmasq/files/dnsmasq.init    | 42 +++++++++++++++++-----
 2 files changed, 43 insertions(+), 11 deletions(-)

diff --git a/package/network/services/dnsmasq/Makefile b/package/network/services/dnsmasq/Makefile
index e2902ed875..d4aa298450 100644
--- a/package/network/services/dnsmasq/Makefile
+++ b/package/network/services/dnsmasq/Makefile
@@ -30,6 +30,7 @@ PKG_CONFIG_DEPENDS:= CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dhcp \
 	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec \
 	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth \
 	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset \
+	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_nftset \
 	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack \
 	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid \
 	CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc \
@@ -61,10 +62,11 @@ endef
 
 define Package/dnsmasq-full
 $(call Package/dnsmasq/Default)
-  TITLE += (with DNSSEC, DHCPv6, Auth DNS, IPset, Conntrack, NO_ID enabled by default)
+  TITLE += (with DNSSEC, DHCPv6, Auth DNS, IPset, Nftset, Conntrack, NO_ID enabled by default)
   DEPENDS+=+PACKAGE_dnsmasq_full_dnssec:libnettle \
 	+PACKAGE_dnsmasq_full_ipset:kmod-ipt-ipset \
-	+PACKAGE_dnsmasq_full_conntrack:libnetfilter-conntrack
+	+PACKAGE_dnsmasq_full_conntrack:libnetfilter-conntrack \
+	+PACKAGE_dnsmasq_full_nftset:nftables-json
   VARIANT:=full
   PROVIDES:=dnsmasq
 endef
@@ -83,7 +85,7 @@ define Package/dnsmasq-full/description
 $(call Package/dnsmasq/description)
 
 This is a fully configurable variant with DHCPv4, DHCPv6, DNSSEC, Authoritative DNS
-and IPset, Conntrack support & NO_ID enabled by default.
+and nftset, Conntrack support & NO_ID enabled by default.
 endef
 
 define Package/dnsmasq/conffiles
@@ -109,6 +111,9 @@ define Package/dnsmasq-full/config
 		default y
 	config PACKAGE_dnsmasq_full_ipset
 		bool "Build with IPset support."
+		default n
+	config PACKAGE_dnsmasq_full_nftset
+		bool "Build with Nftset support."
 		default y
 	config PACKAGE_dnsmasq_full_conntrack
 		bool "Build with Conntrack support."
@@ -144,6 +149,7 @@ ifeq ($(BUILD_VARIANT),full)
 		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_dnssec),-DHAVE_DNSSEC) \
 		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_auth),,-DNO_AUTH) \
 		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_ipset),,-DNO_IPSET) \
+		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_nftset),-DHAVE_NFTSET,) \
 		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_conntrack),-DHAVE_CONNTRACK,) \
 		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_noid),-DNO_ID,) \
 		$(if $(CONFIG_PACKAGE_dnsmasq_$(BUILD_VARIANT)_broken_rtc),-DHAVE_BROKEN_RTC) \
diff --git a/package/network/services/dnsmasq/files/dnsmasq.init b/package/network/services/dnsmasq/files/dnsmasq.init
index c4ca3eb2db..386b47616e 100755
--- a/package/network/services/dnsmasq/files/dnsmasq.init
+++ b/package/network/services/dnsmasq/files/dnsmasq.init
@@ -33,6 +33,7 @@ dnsmasq_ignore_opt() {
 		[ "${dnsmasq_features#* DNSSEC }" = "$dnsmasq_features" ] || dnsmasq_has_dnssec=1
 		[ "${dnsmasq_features#* TFTP }" = "$dnsmasq_features" ] || dnsmasq_has_tftp=1
 		[ "${dnsmasq_features#* ipset }" = "$dnsmasq_features" ] || dnsmasq_has_ipset=1
+		[ "${dnsmasq_features#* nftset }" = "$dnsmasq_features" ] || dnsmasq_has_nftset=1
 	fi
 
 	case "$opt" in
@@ -55,6 +56,8 @@ dnsmasq_ignore_opt() {
 			[ -z "$dnsmasq_has_tftp" ] ;;
 		ipset)
 			[ -z "$dnsmasq_has_ipset" ] ;;
+		nftset)
+			[ -z "$dnsmasq_has_nftset" ] ;;
 		*)
 			return 1
 	esac
@@ -169,10 +172,6 @@ append_address() {
 	xappend "--address=$1"
 }
 
-append_ipset() {
-	xappend "--ipset=$1"
-}
-
 append_connmark_allowlist() {
 	xappend "--connmark-allowlist=$1"
 }
@@ -796,25 +795,54 @@ dhcp_relay_add() {
 
 dnsmasq_ipset_add() {
 	local cfg="$1"
-	local ipsets domains
+	local ipsets nftsets domains
 
 	add_ipset() {
 		ipsets="${ipsets:+$ipsets,}$1"
 	}
 
+	add_nftset() {
+		local IFS=,
+		for set in $1; do
+			local fam="$family"
+			[ -n "$fam" ] || fam=$(echo "$set" | sed -nre \
+				's#^.*[^0-9]([46])$|^.*[-_]([46])[-_].*$|^([46])[^0-9].*$#\1\2\3#p')
+			[ -n "$fam" ] || \
+				fam=$(nft -t list set "$table_family" "$table" "$set" 2>&1 | sed -nre \
+				's#^\t\ttype .*\bipv([46])_addr\b.*$#\1#p')
+
+			[ -n "$fam" ] || \
+				logger -t dnsmasq "Cannot infer address family from non-existent nftables set '$set'"
+
+			nftsets="${nftsets:+$nftsets,}${fam:+$fam#}$table_family#$table#$set"
+		done
+	}
+
 	add_domain() {
 		# leading '/' is expected
 		domains="$domains/$1"
 	}
 
+	config_get table "$cfg" table 'fw4'
+	config_get table_family "$cfg" table_family 'inet'
+	if [ "$table_family" = "ip" ] ; then
+		family="4"
+	elif [ "$table_family" = "ip6" ] ; then
+		family="6"
+	else
+		config_get family "$cfg" family
+	fi
+
 	config_list_foreach "$cfg" "name" add_ipset
+	config_list_foreach "$cfg" "name" add_nftset
 	config_list_foreach "$cfg" "domain" add_domain
 
-	if [ -z "$ipsets" ] || [ -z "$domains" ]; then
+	if [ -z "$ipsets" ] || [ -z "$nftsets" ] || [ -z "$domains" ]; then
 		return 0
 	fi
 
 	xappend "--ipset=$domains/$ipsets"
+	xappend "--nftset=$domains/$nftsets"
 }
 
 dnsmasq_start()
@@ -948,7 +976,6 @@ dnsmasq_start()
 	config_list_foreach "$cfg" "server" append_server
 	config_list_foreach "$cfg" "rev_server" append_rev_server
 	config_list_foreach "$cfg" "address" append_address
-	config_list_foreach "$cfg" "ipset" append_ipset
 
 	local connmark_allowlist_enable
 	config_get connmark_allowlist_enable "$cfg" connmark_allowlist_enable 0
@@ -1141,7 +1168,6 @@ dnsmasq_start()
 	config_foreach filter_dnsmasq ipset dnsmasq_ipset_add "$cfg"
 	echo >> $CONFIGFILE_TMP
 
-	echo >> $CONFIGFILE_TMP
 	mv -f $CONFIGFILE_TMP $CONFIGFILE
 	mv -f $HOSTFILE_TMP $HOSTFILE
 




More information about the lede-commits mailing list