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?

Dave
  • 601
  • 11
  • 23
  • 1
    https://unix.stackexchange.com/questions/581419/routing-port-traffic-over-specific-interface . Then you have the routing table 220 and its routing rule to think about. No iptables needed. – A.B Oct 27 '21 at 16:28
  • Thanks! I just found this post too https://unix.stackexchange.com/questions/453509/route-traffic-on-certain-port-through-certain-interface . Still researching. – Dave Oct 27 '21 at 16:34

1 Answers1

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
            }
        }
    }   
}
Dave
  • 601
  • 11
  • 23
  • Glad it's (almost) working. Don't forget DNS also requires TCP port 53, not just UDP. – A.B Oct 27 '21 at 21:50