How to use nftset with dnsmasq?

hello,

dnsmasq.conf

ipset=/accountkit.com/socialmedia
ipset=/acebook.com/socialmedia
ipset=/faacebook.com/socialmedia
ipset=/facebbook.com/socialmedia

i was able to limit bandwidth for those for exanple by creating

ipset create socialmedia hash:ip

and

redirect the the set with iptables to class
iptables -A FORWARD -t mangle -m set --match-set socialmedia src -j MARK --set-mark 0x2

and the class

tc qdisc add dev pppoe-wan root htb default 3
tc class add dev pppoe-wan parent 1: classid 1:2 rate 2mbit
tc filter add dev pppoe-wan parent 1: .....  handle 2 fw classid 1:2

i want to capture dnsmasq ip facebbook.com and put them to nftset instead of ipset as i want to use nftables

and do the same as above example but with nftables

First thing to note is that you'll need to be running a snapshot version of OpenWrt as the dnsmasq build in 22.03.x has ipset support and not nftset.

22.03.5-box$ dnsmasq -v
Dnsmasq version 2.86  Copyright (c) 2000-2021 Simon Kelley
Compile time options: blah ... conntrack ipset auth ...
snapshot-box$ dnsmasq -v
Dnsmasq version 2.89  Copyright (c) 2000-2022 Simon Kelley
Compile time options: blah ... conntrack no-ipset nftset auth ...

Once that's done, you'll have to manually create the sets and populate them, as the LuCI firewall code doesn't yet fully support nftsets, but it looks like you've already got a good handle on that (just translate your iptables rules to nft).

1 Like

root@OpenWrt:~# dnsmasq -v

Dnsmasq version 2.89  Copyright (c) 2000-2022 Simon Kelley
Compile time options: IPv6 GNU-getopt no-RTC no-DBus UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset nftset auth cryptohash DNSSEC no-ID loop-detect inotify dumpfile

This software comes with ABSOLUTELY NO WARRANTY.
Dnsmasq is free software, and you are welcome to redistribute it
under the terms of the GNU General Public License, version 2 or 3.
1 Like

there is no match for set in nftables i tried iptables-translate didn't convert the rule

iptables-translate  -m set --match-set socialmedia1  src -A FORWARD
nft # -m set --match-set socialmedia1 src -A FORWARD

You would use an expression like:

ip saddr @socialmedia1

to match an IPv4 source address from the set.

1 Like
root@OpenWrt:~# nft list sets
table inet fw4 {
        set socialmedia1 {
                type ipv4_addr
        }
        set streaming {
                type ipv4_addr
        }
        set test {
                type ipv4_addr
        }
}
table inet nft-qos-monitor {
}
table inet nft-qos-static {
}

/etc/config/dhcp

 config ipset
         list name 'streaming'
         list domain 'youtube.com'

 config ipset
         list name 'test_uci_set'
         list domain 'youtube.com'
         list domain 'googlevideo.com'

 config ipset
         list name 'test'
         list domain 'google.com'
         list domain 'googlevideo.com'
         list domain 'youtube.com'

/etc/config/firewall

 config ipset
        option name 'test'
        option enabled '1'
        option match 'ip'

why it doesn't put the resolve ip into set ??

Interesting that you have compiled dnsmasq with both ipset and nftset options.

What’s in dnsmasq.conf?

grep -E "ipset|nftset" /var/etc/dnsmasq.conf.*
root@OpenWrt:~# grep -E "ipset|nftset" /var/etc/dnsmasq.conf.*
ipset=/google.com/googlevideo.com/youtube.com/test
nftset=/google.com/googlevideo.com/youtube.com/4#ip#fw4#test
root@OpenWrt:~#
nslookup google.com 127.0.0.1
nslookup youtube.com 127.0.0.1
nft list set inet fw4 test
1 Like
root@OpenWrt:~# nslookup google.com 127.0.0.1
Server:         127.0.0.1
Address:        127.0.0.1:53

Non-authoritative answer:
Name:   google.com
Address: 142.251.37.238

Non-authoritative answer:
Name:   google.com
Address: 2a00:1450:4006:813::200e

root@OpenWrt:~# nslookup youtube.com 127.0.0.1
Server:         127.0.0.1
Address:        127.0.0.1:53

Non-authoritative answer:
Name:   youtube.com
Address: 2a00:1450:4006:812::200e

Non-authoritative answer:
Name:   youtube.com
Address: 142.251.37.206

root@OpenWrt:~# nft list set inet fw4 test
table inet fw4 {
        set test {
                type ipv4_addr
                elements = { 10.0.0.113, 74.125.133.188,
                             142.250.27.192, 142.250.200.206,
                             142.250.200.238, 142.250.201.14,
                             142.250.201.36, 142.250.201.46,
                             142.250.203.237, 142.250.203.238,
                             142.251.37.34, 142.251.37.46,
                             142.251.37.164, 142.251.37.174,
                             142.251.37.194, 142.251.37.206,
                             142.251.37.238, 156.200.33.204,
                             156.200.33.207, 156.200.33.208,
                             172.217.18.46, 172.217.18.238,
                             172.217.19.46, 172.217.19.142,
                             172.217.21.14, 172.217.171.206,
                             216.58.198.78, 216.58.205.206,
                             216.58.211.206, 216.58.212.110 }
        }
}
root@OpenWrt:~#
1 Like

when i rebooted the router it stopped capture ip from dnsmasq // can u help figure this out

Are your LAN clients all using the router IP as their DNS server?

yes they are using dhcp with router ip address as dns

OK, then just verify all the individual components are in place.

uci show firewall | grep ipset
uci show dhcp | grep ipset
grep nftset /var/etc/dnsmasq.conf.*
nft list sets
ipset list

If they are, wait for clients to query the router's dnsmasq for the target domains and populate the sets. Clients might be caching previous query results, so it might not appear to be working instantly.

Keep in mind that one very significant limitation of the nftset setting in dnsmasq is that dnsmasq does not actually add the IP address for the specified domain until and unless the domain name is encountered by dnsmasq in a DNS request.

2 Likes

That looks suspect to me, I'd expect the ip for family (between 4 and fw4) to be inet, as the set lives in a dual-stack table.

1 Like

Good point. If table_family is specified in the dhcp config file, it should be removed.

When I add a test set, it uses the proper table family in the dnsmasq config. This is with snapshot r22755-326eb6e482 on an x86 bare metal install, dnsmasq-full 2.89-4 and firewall4 2023-03-23-04a06bd7-1.

$ tail -7 /etc/config/firewall
config ipset
        option name 'fred'
        option comment 'A test of things'
        option family 'ipv4'
        option counters '1'
        list match 'dest_ip'

$ tail -4 /etc/config/dhcp
config ipset
        list name 'fred'
        list domain 'google.com'

... uci commit, restart fw4 and dnsmasq ...

$ nft list set inet fw4 fred
table inet fw4 {
        set fred {
                type ipv4_addr
                comment "A test of things"
        }
}

$ grep nftset /var/etc/dnsmasq.conf.cfg01411c
nftset=/google.com/4#inet#fw4#fred

$ nslookup google.com
...

$ nft list set inet fw4 fred
table inet fw4 {
        set fred {
                type ipv4_addr
                comment "A test of things"
                elements = { 142.250.176.14 }
        }
}

There does seem to be a minor bug: the counters option is ignored when creating the set (although I think this might be a deliberate omission, as I recall seeing a bug fix on nftables committed just recently).

Oops, it's about verdict maps, not named sets:
https://git.netfilter.org/nftables/commit/?id=686ab8b6996e154592a5fc16bd1e15e661201b2a

You might not have to use the whole snapshot, from 23.03.5, I just took 3 files from snapshot which seemed to be dependencies

dnsmasq is the DNS/DHCP server that comes standard in OpenWRT.
The package shipped with OpenWrt, dnsmasq is a minimal compile omitting certain features
ipset support allows dnsmasq to dynamically add the results of dns lookups to netfilter ipsets, which can later be used in firewall rules to permit or deny traffic.
Replace the minimal version with the full version

opkg update
opkg remove dnsmasq
mv /etc/config/dhcp /etc/config/dhcp.bak
opkg install dnsmasq-full

As of openWRT 23.0.5 Jul 17, 2023 could not get dnsmasq-full working in a container, only works in a virtual machine. Probably something small
As of openWRT 23.0.5 Jul 17, 2023 the version of dnsmasq-full that comes with the distribution is 2.86. This version while it supports ipsets does not support nfsets

root@OpenWrt:~# dnsmasq -v
Dnsmasq version 2.86  Copyright (c) 2000-2021 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack ipset auth cryptohash DNSSEC no-ID loop-detect inotify dumpfile

OpenWrt has shifted focus from iptsbles to nftables so we prefer to use nfset support as opposed to ipset support
Download a newer version of dnsmasq-full from the openWRT snapshots repository and 2 of it's dependencies
The fact that it's in snapshot, means that releases after 23.0.x will not need to do this bit.
Also the filenames might change but the base path will probably stay the same

wget https://downloads.openwrt.org/snapshots/packages/x86_64/base/libubox20230523_2023-05-23-75a3b870-1_x86_64.ipk
wget https://downloads.openwrt.org/snapshots/packages/x86_64/base/libubus20220615_2022-06-15-9913aa61-1_x86_64.ipk
wget https://downloads.openwrt.org/snapshots/packages/x86_64/base/dnsmasq-full_2.89-4_x86_64.ipk

Install the packages

opkg install libubox20230523_2023-05-23-75a3b870-1_x86_64.ipk
opkg install libubus20220615_2022-06-15-9913aa61-1_x86_64.ipk
opkg install dnsmasq-full_2.89-4_x86_64.ipk

Now we have dnsmasq-full 2.89 which supports nfsets

root@OpenWrt:~# dnsmasq -v
Dnsmasq version 2.89  Copyright (c) 2000-2022 Simon Kelley
Compile time options: IPv6 GNU-getopt no-DBus UBus no-i18n no-IDN DHCP DHCPv6 no-Lua TFTP conntrack no-ipset nftset auth cryptohash DNSSEC no-ID loop-detect inotify dumpfile