0

How do I redirect only DNS traffic to use a tunnel interface when active?

Any other type of traffic should use the kernel's routing table instead. Whenever the tunnel interface is not active, DNS traffic is to use the kernel's routing table instead. Is this possible with iptables?

Note: I am using Strongswan 5.9.1, so if there is a way to configure this functionality from Strongswan, I would like to do that. However, I am using the system as a route based policy. Also, I am currently marking packets with strongswan, not sure if that would be related.

Interfaces:

# ip -br a lo UNKNOWN 127.0.0.1/8 ::1/128 ens3 UP 192.168.0.15/24 fe80::e74:fcff:fe28:cb00/64 ens4 UP 2.2.1.2/30 fe80::e74:fcff:fe28:cb01/64 virbr0 DOWN 192.168.122.1/24 virbr0-nic DOWN ip_vti0@NONE DOWN vti01@NONE UNKNOWN 172.21.0.3/32 fe80::200:5efe:202:102/64 

Routes:

# route -n Kernel IP routing table Destination Gateway Genmask Flags Metric Ref Use Iface 0.0.0.0 192.168.0.1 0.0.0.0 UG 0 0 0 ens3 2.2.0.1 0.0.0.0 255.255.255.255 UH 101 0 0 ens4 2.2.1.0 0.0.0.0 255.255.255.252 U 101 0 0 ens4 3.3.0.0 2.2.0.1 255.255.255.252 UG 101 0 0 ens4 3.3.1.0 2.2.1.1 255.255.255.252 UG 101 0 0 ens4 10.212.134.0 192.168.0.1 255.255.255.0 UG 100 0 0 ens3 172.21.0.0 0.0.0.0 255.255.255.248 U 0 0 0 vti01 192.168.0.0 0.0.0.0 255.255.255.0 U 100 0 0 ens3 192.168.122.0 0.0.0.0 255.255.255.0 U 0 0 0 virbr0 

I tried using the following rule:

# iptables -t mangle -A OUTPUT -p udp --dport 53 --out-interface vti01 

I can see the rule, but when I watch it, no packets are going into the rule when I do a dig request on the same host.

# watch -n1 iptables -t mangle -nvL Chain OUTPUT (policy ACCEPT 0 packets, 0 bytes) pkts bytes target prot opt in out source destination 0 0 udp -- * vti01 0.0.0.0/0 0.0.0.0/0 udp dpt:53 

What am I missing?

2

1 Answer 1

1

Thanks to @A.B The commands I used were the following (Note I made the table's id the same as DNS protocol number [53]):

ip route add table 53 0.0.0.0/0 dev vti01 ip rule add iif lo ipproto udp dport 53 lookup 53 sysctl -w net.ipv4.conf.vti01.rp_filter=2 

I ran the following to check on status:

ip route list table 53 ip rule list | grep 53 

I was able to implement this in my custom _updown script so Strongswan would build and remove these entries every time the tunnel goes up or down, and it works

#!/bin/bash set -o nounset set -o errexit VTI_IF="vti01" PORT="53" TABLE="53" case "${PLUTO_VERB}" in up-client) ip tunnel add $VTI_IF local 2.2.1.2 remote 3.3.0.2 mode vti key 41 ip link set $VTI_IF up ip addr add 172.21.0.3 dev $VTI_IF ip route add 172.21.0.0/29 dev $VTI_IF ip route add table $TABLE 0.0.0.0/0 dev $VTI_IF ip rule add iif lo ipproto udp dport $PORT lookup $TABLE sysctl -w "net.ipv4.conf.$VTI_IF.rp_filter=2" sysctl -w "net.ipv4.conf.$VTI_IF.disable_policy=1" sysctl -w "net.ipv4.conf.$VTI_IF.rp_filter=0" sysctl -w "net.ipv4.conf.$VTI_IF.forwarding=1" ;; down-client) ip rule del iif lo ipproto udp dport $PORT lookup $TABLE ip route del table $TABLE 0.0.0.0/0 dev $VTI_IF ip tunnel del $VTI_IF ;; esac 

I then call my script in my swanctl.conf file, here is what a connection looks like. The section under the child "updown=" is how to call the script.

connections { remote-sa { version = 2 local { id = 2.2.1.2 } local_addrs = 2.2.1.2 remote_addrs = 3.3.0.2 proposals = aes256-sha256-ecp384 local { auth = psk } remote { auth = psk } children { remote-sa-child { local_ts = 172.21.0.0/29 remote_ts = 0.0.0.0/0 mark_in = 41 mark_out = 41 esp_proposals = aes256-sha256-ecp384 updown = /opt/_updown_vti01 iptables start_action = start close_action = start } } } } 
1
  • Glad it's (almost) working. Don't forget DNS also requires TCP port 53, not just UDP. Commented Oct 27, 2021 at 21:50

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.