What's new

Using ipset to selectively route domains to a VPN client?

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

Ted Danson

Regular Contributor
I've been looking in to this recently and get the idea of adding server= and ipset= entries to dnsmasq.conf.add and have also created the ipset(s) at the terminal via SSH.

However I am stuck at the next stage, which I assume is to create an iptables entry to direct entries in the ipset(s) I've created to a connected VPN client? For example, when client 1 is connected I see an interface, tun11, in the route table, which I assume is where I want these ipset entries to go out over?

Thanks a lot for any help you can give me. This forum has been so helpful to me in the past.

Also thank you again Merlin for all your extremely hard work. :)
 
I've been looking in to this recently and get the idea of adding server= and ipset= entries to dnsmasq.conf.add and have also created the ipset(s) at the terminal via SSH.

However I am stuck at the next stage, which I assume is to create an iptables entry to direct entries in the ipset(s) I've created to a connected VPN client? For example, when client 1 is connected I see an interface, tun11, in the route table, which I assume is where I want these ipset entries to go out over?

You will need one iptables rule and one RPDB rule referencing the correct VPN Client instance (1-5 if available in the firmware)
Code:
ip rule add from 0/0 fwmark 0x1000 table ovpnc1 prio 9991
iptables -t mangle -A PREROUTING -i br0 -p tcp -m set --match-set 'Your_IPSET' src,dst -j MARK --set-mark 0x1000/0x1000

NOTE: When using the commands in say nat-start you need to precede the commands with appropriate delete commands to avoid creating unnecessary duplicate rules.

Code:
ip rule del prio 9991 2> /dev/null > /dev/null
ip rule add from 0/0 fwmark 0x1000 table ovpnc1 prio 9991

iptables -t mangle -D PREROUTING -i br0 -p tcp -m set --match-set 'Your_IPSET' src,dst -j MARK --set-mark 0x1000/0x1000 2> /dev/null > /dev/null
iptables -t mangle -A PREROUTING -i br0 -p tcp -m set --match-set 'Your_IPSET' src,dst -j MARK --set-mark 0x1000/0x1000

EDIT: Typo fixed (diligently) spotted by @Xentrk
P.S. It would be sooo much easier if these rules were added by vpnrouting.sh :rolleyes:
 
Last edited:
That looks like exactly what I need, thank you! I'm assuming I just create a nat-start file in the /jffs/scripts folder? Do I need to set any permissions etc on that or will it just work out the box?

This is what I've come up with, am I on the right track?

Code:
#!/bin/sh
#USA VPN IPSET RULE
ip rule del prio 9991
ip rule add from 0/0 fwmark 0x1000 table ovpnc1 prio 9991

iptables -t mangle -D PREROUTING -i br0 -p tcp -m set --match-set 'ukvpn' src,dst -j MARK --set-mark $0x1000/0x1000
iptables -t mangle -A PREROUTING -i br0 -p tcp -m set --match-set 'ukvpn' src,dst -j MARK --set-mark $0x1000/0x1000
#UK VPN IPSET RULE
ip rule del prio 9991
ip rule add from 0/0 fwmark 0x2000 table ovpnc2 prio 9991

iptables -t mangle -D PREROUTING -i br0 -p tcp -m set --match-set 'usavpn' src,dst -j MARK --set-mark $0x2000/0x2000
iptables -t mangle -A PREROUTING -i br0 -p tcp -m set --match-set 'usavpn' src,dst -j MARK --set-mark $0x2000/0x2000

I also set the scripts folder to executable with:

Code:
chmod a+rx /jffs/scripts/*

As an aside, the two ipsets I've created so far I did as follows:

Code:
ipset create usavpn hash:ip
ipset create ukvpn hash:ip

Bringing up ipset --list gives:

Code:
Name: ukvpn
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 60
References: 0
Number of entries: 0
Members:

Name: usavpn
Type: hash:ip
Revision: 4
Header: family inet hashsize 1024 maxelem 65536
Size in memory: 100
References: 0
Number of entries: 1
Members:
IP ADDRESS OF A DOMAIN I ADDED IN DNSMASQ.CONF.ADD
 
Last edited:
That looks like exactly what I need, thank you! I'm assuming I just create a nat-start file in the /jffs/scripts folder? Do I need to set any permissions etc on that or will it just work out the box?

This is what I've come up with, am I on the right track?

You do not need the quotes around the ipset name in the PREROUTING Chain rule - it's my way of attempting to highlight a USER defined text string :oops:

and for the 'UK VPN IPSET RULE' there is a typo - you should be using 'prio 9992'

Code:
#!/bin/sh
#USA VPN IPSET RULE
ip rule del prio 9991 2> /dev/null > /dev/null
ip rule add from 0/0 fwmark 0x1000 table ovpnc1 prio 9991

iptables -t mangle -D PREROUTING -i br0 -p tcp -m set --match-set ukvpn src,dst -j MARK --set-mark $0x1000/0x1000 2> /dev/null > /dev/null
iptables -t mangle -A PREROUTING -i br0 -p tcp -m set --match-set ukvpn src,dst -j MARK --set-mark $0x1000/0x1000
#UK VPN IPSET RULE
ip rule del prio 9992 2> /dev/null > /dev/null
ip rule add from 0/0 fwmark 0x2000 table ovpnc2 prio 9992

iptables -t mangle -D PREROUTING -i br0 -p tcp -m set --match-set usavpn src,dst -j MARK --set-mark $0x2000/0x2000 2> /dev/null > /dev/null
iptables -t mangle -A PREROUTING -i br0 -p tcp -m set --match-set usavpn src,dst -j MARK --set-mark $0x2000/0x2000
 
Last edited:
That looks like exactly what I need, thank you! I'm assuming I just create a nat-start file in the /jffs/scripts folder? Do I need to set any permissions etc on that or will it just work out the box?

This is what I've come up with, am I on the right track?

Code:
#!/bin/sh
#USA VPN IPSET RULE
ip rule del prio 9991
ip rule add from 0/0 fwmark 0x1000 table ovpnc1 prio 9991

iptables -t mangle -D PREROUTING -i br0 -p tcp -m set --match-set 'ukvpn' src,dst -j MARK --set-mark $0x1000/0x1000
iptables -t mangle -A PREROUTING -i br0 -p tcp -m set --match-set 'ukvpn' src,dst -j MARK --set-mark $0x1000/0x1000
#UK VPN IPSET RULE
ip rule del prio 9991
ip rule add from 0/0 fwmark 0x2000 table ovpnc2 prio 9991

iptables -t mangle -D PREROUTING -i br0 -p tcp -m set --match-set 'usavpn' src,dst -j MARK --set-mark $0x2000/0x2000
iptables -t mangle -A PREROUTING -i br0 -p tcp -m set --match-set 'usavpn' src,dst -j MARK --set-mark $0x2000/0x2000
You have a conflict with the prio 9991 for both ovpnc1 and ovpnc2. Change ovpnc2 to prio 9992.

I have not seen the $ symbol used in front of the fwmark before. Not sure if it is a typo.
 
Thanks all, fixed that (including the $ on the set mark entries, I spotted that too hehe!)

Now when I run the script I get this:

Code:
./nat-start.sh
iptables: No chain/target/match by that name.
iptables: No chain/target/match by that name.
RTNETLINK answers: No such file or directory
iptables: No chain/target/match by that name.
iptables: No chain/target/match by that name.

So I thought if I try iptables --list I'd see a PREROUTING table, but it's not there. So I did iptables --new PREROUTING, tried a list again, it's now there. Ran the script. Same output as above.

EDIT: Also, yep I meant to remove the quote marks off of the ipset names. Haha! :)
 
Thanks all, fixed that (including the $ on the set mark entries, I spotted that too hehe!)

Now when I run the script I get this:

Code:
./nat-start.sh
iptables: No chain/target/match by that name.
iptables: No chain/target/match by that name.
RTNETLINK answers: No such file or directory
iptables: No chain/target/match by that name.
iptables: No chain/target/match by that name.

So I thought if I try iptables --list I'd see a PREROUTING table, but it's not there. So I did iptables --new PREROUTING, tried a list again, it's now there. Ran the script. Same output as above.

EDIT: Also, yep I meant to remove the quote marks off of the ipset names. Haha! :)

What does the command
Code:
iptables -nvL --line -t mangle
show?
 
What does the command
Code:
iptables -nvL --line -t mangle
show?

Code:
RT-AC5300-05B0:/jffs/scripts# iptables -nvL --line -t mangle
Chain PREROUTING (policy ACCEPT 39939 packets, 11M bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        1    60 MARK       all  --  tun11  *       0.0.0.0/0            0.0.0.0/0            MARK xset 0x1/0x7
2        1    60 MARK       all  --  tun12  *       0.0.0.0/0            0.0.0.0/0            MARK xset 0x1/0x7
3     163K  131M BWDPI_FILTER  udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0

Chain INPUT (policy ACCEPT 12959 packets, 1517K bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 26952 packets, 9300K bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 MARK       all  --  *      br0     192.168.1.0/24       192.168.1.0/24       MARK xset 0x1/0x7

Chain OUTPUT (policy ACCEPT 11532 packets, 3192K bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 38776 packets, 13M bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain BWDPI_FILTER (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp spt:68 dpt:67
2        1   323 DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp spt:67 dpt:68
 
Code:
RT-AC5300-05B0:/jffs/scripts# iptables -nvL --line -t mangle
Chain PREROUTING (policy ACCEPT 39939 packets, 11M bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        1    60 MARK       all  --  tun11  *       0.0.0.0/0            0.0.0.0/0            MARK xset 0x1/0x7
2        1    60 MARK       all  --  tun12  *       0.0.0.0/0            0.0.0.0/0            MARK xset 0x1/0x7
3     163K  131M BWDPI_FILTER  udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0

Chain INPUT (policy ACCEPT 12959 packets, 1517K bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain FORWARD (policy ACCEPT 26952 packets, 9300K bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 MARK       all  --  *      br0     192.168.1.0/24       192.168.1.0/24       MARK xset 0x1/0x7

Chain OUTPUT (policy ACCEPT 11532 packets, 3192K bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain POSTROUTING (policy ACCEPT 38776 packets, 13M bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain BWDPI_FILTER (1 references)
num   pkts bytes target     prot opt in     out     source               destination
1        0     0 DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp spt:68 dpt:67
2        1   323 DROP       udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0            udp spt:67 dpt:68

Apparently there are previous reports of RT-AC68U owners suffering the same frustrating issues, but I have just tried the commands on three separate RMerlin firmware loaded RT-AC68U units and none exhibit the same error messages about 'No chain/target/match by that name'; either by copy'n'paste or manually typing the command, so I doubt it is RT-AC5300 specific.:(

Strange, so you stated that the '-t mangle PREROUTING' Chain didn't exist o_O until

'..I did iptables --new PREROUTING' ?

yet the PREROUTING Chain is seemingly definitely populated? :eek:

NOTE: To eliminate the RTNETLINK message, add
Code:
2> /dev/null > /dev/null
to the end of the 'delete' rules.

Not sure what else I can suggest at the moment. :oops:
 
Thanks for the 2> /dev/null > /dev/null tip, that fixed that at least. It's really weird, not sure where to go now either. Ah well, if it doesn't work I'll restore previous backups to the router and try another day.

The ipsets seem to be working though. I try domains I've entered for each set and the sets are populating with ip addresses. So that's a start! :)

EDIT:

Regarding the PREROUTING chain. Indeed, it absolutely did not exist when I started out doing this. I had to create the chain manually as it wasn't there when I listed the tables first time round.
 
Regarding the PREROUTING chain. Indeed, it absolutely did not exist when I started out doing this. I had to create the chain manually as it wasn't there when I listed the tables first time round.

So I wonder at which point these entries were added (unless you also inserted them? :p)
Code:
Chain PREROUTING (policy ACCEPT 39939 packets, 11M bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        1    60 MARK       all  --  tun11  *       0.0.0.0/0            0.0.0.0/0            MARK xset 0x1/0x7
2        1    60 MARK       all  --  tun12  *       0.0.0.0/0            0.0.0.0/0            MARK xset 0x1/0x7
3     163K  131M BWDPI_FILTER  udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0

I suppose there could be a timing issue with the nat-start commands, but if you can clearly list the PREROUTING Chain, then you should be able to add the iptables fwmark rules manually o_O
 
Absolutely no idea. The only things I create manually were the ipsets, the nat-start.sh with the rules provided and the PREROUTING chain (as it didn't exist).

tun11 and tun12 are the two vpn clients I've switched on on my router right now.
 
Absolutely no idea. The only things I create manually were the ipsets, the nat-start.sh with the rules provided and the PREROUTING chain (as it didn't exist).

tun11 and tun12 are the two vpn clients I've switched on on my router right now.

Can you try the following
Code:
iptables -nvL PREROUTING --line -t mangle

All I can think is that there may be an unprintable character in the actual name of the 'PREROUTING' Chain - unlikely but worth a shot to at least rule it out :(
 
Here you go:

Code:
Chain PREROUTING (policy ACCEPT 17843 packets, 5955K bytes)
num   pkts bytes target     prot opt in     out     source               destination
1        1    60 MARK       all  --  tun11  *       0.0.0.0/0            0.0.0.0/0            MARK xset 0x1/0x7
2        1    60 MARK       all  --  tun12  *       0.0.0.0/0            0.0.0.0/0            MARK xset 0x1/0x7
3     172K  133M BWDPI_FILTER  udp  --  eth0   *       0.0.0.0/0            0.0.0.0/0
 
Just a little update. This is really odd. It 'seems' to be working. Some stuff I absolutely know 100% requires a VPN to work, is working. Not across all platforms though. My web browser doesn't seem to work with the site(s) but tablets, STB's, mobile etc work.

Really bizarre. I feel like I'm almost there but not 100% sure how to be, well, 100% sure all is well. :)
 
Just a little update. This is really odd. It 'seems' to be working. Some stuff I absolutely know 100% requires a VPN to work, is working. Not across all platforms though. My web browser doesn't seem to work with the site(s) but tablets, STB's, mobile etc work.

Really bizarre. I feel like I'm almost there but not 100% sure how to be, well, 100% sure all is well. :)

Well the RPDB rules should be the definitive rules that you should check
Code:
ip rule

as the iptables PREROUTING fwmark rule simply tags the ipset (or destination port) ready for the processing by the RPDB rules.

However, if the routing in the actual target VPN Client route table 11x (or route table main) is incorrect then things may not work as intended.

Perhaps you could simply try with the shortest iptables command to see if they work as you add extra parameters
e.g.
Code:
iptables -t mangle -A PREROUTING -m set --match-set ukvpn dst

iptables -t mangle -A PREROUTING -p tcp -m set --match-set ukvpn dst

etc.
 
Last edited:
Gave that a try but it's still not working unfortunately.

So what does this display?
Code:
iptables --verbose -t mangle -A PREROUTING -j ACCEPT
 

Similar threads

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top