peacey / split-vpn

A split tunnel VPN script for Unifi OS routers (UDM, UXG, UDR) with policy based routing.
GNU General Public License v3.0
802 stars 56 forks source link

How to force UDP's DNS requests to VPN #169

Open ddkedr opened 1 year ago

ddkedr commented 1 year ago

Hi!

I think I'm stupid or smth, but I can't beat this.

Problem. I have some region-specific restrictions from websites, that decided to resolve all the dns requests from my coutry to 127.0.0.1. And this is done by all major DNS-server like Cloudflare, Google etc.

I got Pi-hole running in host mode and everything is kinda fine. I added 1.1.1.1 to the FORCED_DESTINATIONS_IPV4 and it works for all the client devices just fine. But it looks like all the DNS requests that pihole makes are done from the UDM itself and are not being routed through the VPN.

So what I need is to make Cloudflare think that my DNS-requests are coming from my VPN's IP-address and not from my real IP-address.

I couldn't find any suitable parameter in split-vpn configs

Is it possible to force not only client' traffic but also the UDM's aswell?

peacey commented 1 year ago

Hi @ddkedr,

It is possible to force local UDM traffic through the VPN with FORCED_LOCAL_INTERFACE option. But this option forces all local traffic from the UDM, not just a particular one like port 53.

However it is possible to force only port 53 outgoing local traffic by adding your own custom iptables rules with the up hook. Just add this snippet to your vpn.conf if you want to force all local port 53 traffic out the VPN:

hooks_up() {
    for proto in udp tcp; do
        iptables -t mangle -A ${PREFIX}OUTPUT -p $proto --dport 53 -j MARK --set-xmark ${MARK}
        ip6tables -t mangle -A ${PREFIX}OUTPUT -p $proto --dport 53 -j MARK --set-xmark ${MARK}
    done
}

You can also add -d 1.1.1.1 before the -p flag or whatever other IP if you prefer to limit these forcing rules by IP instead of all port 53 outgoing local traffic.

ddkedr commented 1 year ago

Wow! Thanks, @peacey ! It works! 🥳

Just a couple more questions to double check my understanding of how this works.

  1. Am I correct that it is actually doesn't matter which DNS-server is used in my clients' network configs? I'm no expert in iptables but it looks like all DNS requests from clients are somehow routed to pihole and the actual dns-requests are made from the UDM itself? If the answer is "yes" then it not clear why is it important to run the pihole in host mode.

  2. I'm seeing that No1 client in pihole is pihole itself with the host IP-address from VLAN5. There are another clients, but pihole still has far more requests. Is this normal? If "yes", then what IP-address my pihole uses to "receive" those requests from itself?

  3. Is it even possible to have some clients use DNS servers of their choice regardless of all these split-vpn and pihole existence on my UDM? I understand that those clients probably won't contribute to ipset lists updates, but still.

Thank you again for you work and help! Cheers!

peacey commented 1 year ago

If you use the DNS_IPV4_IP option, then a DNAT rule is added to re-route all port 53 traffic to that IP (your pihole in your case). So it doesn't matter what DNS is used in your clients network settings, as long as the router sees the traffic to port 53 from your client, it will redirect it. The one exception is if you have the DNS on the client set to an IP on the same subnet as the client (but not the router itself) then the router will not see that traffic (since it travels on layer 2) and will not be able to re-route it to your desired IP.

Now pihole is running in host mode and can access your Wn interface directly, so when it makes a request to the Internet, it uses the UDM's WAN IP directly without needing any routing from its internal pihole IP.

ddkedr commented 1 year ago

You already answered my first question while I was adding two more to the previous comment :)

So, following you last comment, am I correct that with the pihole setup it is actually not important what destination are we going to have in DNS_IPV4_IP option, since it won't use neither VPN's DNS-server nor any other specified IP-address, but rather re-route all port 53 traffic to the pihole?

peacey commented 1 year ago

So, following you last comment, am I correct that with the pihole setup it is actually not important what destination are we going to have in DNS_IPV4_IP option, since it won't use neither VPN's DNS-server nor any other specified IP-address, but rather re-route all port 53 traffic to the pihole?

Sorry, I don't understand. If you want to force clients to use your pihole, you have to set the pihole IP in DNS_IPV4_IP. Isn't that what you did? If you don't set it there, you can still give your clients the pihole IP manually using DHCP or manual DNS, but then your client won't be forced to the pihole if they try to use another DNS (like some rogue app that doesn't respect system DNS settings).

I'm seeing that No1 client in pihole is pihole itself with the host IP-address from VLAN5. There are another clients, but pihole still has far more requests. Is this normal? If "yes", then what IP-address my pihole uses to "receive" those requests from itself?

This doesn't seem normal. Why would the pihole be requesting DNS info from itself? What did you set up as the DNS server in pihole's DNS settings? And also, you didn't set up anything under conditional forwarding in pihole settings? Also, what did you set up as the UDM's WAN DNS (is it just auto)?

Is it even possible to have some clients use DNS servers of their choice regardless of all these split-vpn and pihole existence on my UDM? I understand that those clients probably won't contribute to ipset lists updates, but still.

If you are using DNS_IPV4_IP to re-route DNS requests to pihole, there is a way to exempt some clients from this DNS forcing rule by adding another custom rule (see this reply to another thread asking about this). If you don't want to force DNS requests to pihole, you can always opt not to use DNS_IPV4_IP, and instead just give the pihole DNS manually through DHCP or manually setting it on the client you want to use pihole and set another DNS for those that don't.

ddkedr commented 1 year ago

Hi! Sorry or the delay

Sorry, I don't understand. If you want to force clients to use your pihole, you have to set the pihole IP in DNS_IPV4_IP. Isn't that what you did? If you don't set it there, you can still give your clients the pihole IP manually using DHCP or manual DNS, but then your client won't be forced to the pihole if they try to use another DNS (like some rogue app that doesn't respect system DNS settings).

Right now DNS_IPV4_IP is set to DHCP, which according to your manuals should use my VPN's DNS-server, which is not correct if I want DNS-requests forwarded to my pihole. BTW, I don't exaclty understand what DNS_IPV4_INTERFACE does but it is empty in my config.

But it seems that DNS-requests are still going to pihole (which is configured to use 1.1.1.1), even though they souldn't. So, if I understood you correctly, I should've used my Pihole IP-address in DNS_IPV4_IP instead of DHCP.

My WAN DNS is just auto. But my LAN DNS is set to my UDM local IP-address, not the pihole address. Is that correct?

Here is my pihole stats, that shows that it's getting a lot of requests.

image

And here is the https://1.1.1.1/help data that shows my DNS-requests are delivered to CF through the VPN.

image

I'm seeing that No1 client in pihole is pihole itself with the host IP-address from VLAN5. There are another clients, but pihole still has far more requests. Is this normal? If "yes", then what IP-address my pihole uses to "receive" those requests from itself?

This doesn't seem normal. Why would the pihole be requesting DNS info from itself? What did you set up as the DNS server in pihole's DNS settings? And also, you didn't set up anything under conditional forwarding in pihole settings? Also, what did you set up as the UDM's WAN DNS (is it just auto)?

It's not the No1 client anymore, but it still there for DS-requests, which is probably Okay since I have DNSSEC turned on in my pihole.

To answer your question, I only have Cloudflare servers and nothing else:

image

Here is the screenshot of my conditional forwarding.

image
ddkedr commented 1 year ago

UPDATE: I tried to dig deeper in why my DNS requests are still routed to my pihole and I've found these rules in my iptables:

-A PREROUTING ! -s 192.168.15.10/32 ! -d 192.168.15.10/32 -i br0 -p udp -m udp --dport 53 -j DNAT --to-destination 192.168.15.10
-A PREROUTING ! -s 192.168.15.10/32 ! -d 192.168.15.10/32 -i br0 -p tcp -m tcp --dport 53 -j DNAT --to-destination 192.168.15.10

Note: 192.168.15.10 is my PiHole IP-address. My main network is 192.168.10.0/24

Then I found these iptables rules, that were probably created because DNS_IPV4_IP is set to DHCP.

-A VPN_PREROUTING ! -s 8.8.8.8/32 ! -d 8.8.8.8/32 -p udp -m mark --mark 0x169 -m udp --dport 53 -j DNAT --to-destination 8.8.8.8:53
-A VPN_PREROUTING ! -s 8.8.8.8/32 ! -d 8.8.8.8/32 -p tcp -m mark --mark 0x169 -m tcp --dport 53 -j DNAT --to-destination 8.8.8.8:53

But I could still see that my Pihole I working (ads are being blocked)

Then I have found this peace of code in 10-dns-host.sh

# Force DNS traffic to pihole
for intfc in ${FORCED_INTFC}; do
    if [ -d "/sys/class/net/${intfc}" ]; then
        for proto in udp tcp; do
            prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV4} ! -d ${IPV4} --dport 53 -j DNAT --to ${IPV4}"
            iptables -t nat -C ${prerouting_rule} || iptables -t nat -A ${prerouting_rule}
            if [ -n "${IPV6}" ]; then
                prerouting_rule="PREROUTING -i ${intfc} -p ${proto} ! -s ${IPV6} ! -d ${IPV6} --dport 53 -j DNAT --to [${IPV6}]"
                ip6tables -t nat -C ${prerouting_rule} || ip6tables -t nat -A ${prerouting_rule}
            fi
        done
    fi
done

So it seems to me, that this is the real reason why DNS-requests are routed to pihole IP-address, which makes me want to ask again: Does it really matter what we have set in DNS_IPV4_IP parameter? :) Or am I still reading all this incorrectly?