Open ImranR98 opened 1 year ago
Not the developer, but don't think it does. Actually, it does the opposite. This should be possible with some routing magic, but I wouldn't know how to do that.
I don't use this script, because I prefer configuring things with nix instead. However, I just figured out how to get exit nodes working and this seems like a good place to share. (Disclaimer: I am not very knowledgeable about networking, so figuring this out was an extremely slow process of educated guesswork and trial and error.)
If you run ip rule list
on a system running both Mullvad and Tailscale, you should see something like this:
0: from all lookup local
5208: from all lookup main suppress_prefixlength 0
5209: not from all fwmark 0x6d6f6c65 lookup 1836018789
5210: from all fwmark 0x80000/0xff0000 lookup main
5230: from all fwmark 0x80000/0xff0000 lookup default
5250: from all fwmark 0x80000/0xff0000 unreachable
5270: from all lookup 52
32766: from all lookup main
32767: from all lookup default
These are your system's routing rules. The number on the left is a priority, the text on the right is a rule telling the system when to use a particular routing table. Rules 0, 32766, and 32767 exist on basically every Linux system from what I gather. Rules 5210, 5230, 5250, and 5270 are put there by Tailscale and always have the same priority numbers. Rules 5208 and 5209 are put there by Mullvad, which tries to ensure its rules always come before everything else.
We need the rule at 5209 to come after Tailscale's rules, which we can do by running:
ip rule del not from all fwmark 0x6d6f6c65 lookup 1836018789
ip rule add pref 6000 not from all fwmark 0x6d6f6c65 lookup 1836018789
Now if you run ip rule list
again, you should see:
0: from all lookup local
5208: from all lookup main suppress_prefixlength 0
5210: from all fwmark 0x80000/0xff0000 lookup main
5230: from all fwmark 0x80000/0xff0000 lookup default
5250: from all fwmark 0x80000/0xff0000 unreachable
5270: from all lookup 52
6000: not from all fwmark 0x6d6f6c65 lookup 1836018789
32766: from all lookup main
32767: from all lookup default
Success! Well, almost. Tailscale is probably broken at this point, and you need another firewall rule to unbreak it. Modify the excludeOutgoing chain to look something like this:
chain excludeOutgoing {
type route hook output priority -100; policy accept;
meta mark & 0x00ff0000 == 0x00080000 ct mark set 0x00000f41;
ip daddr 100.64.0.0/10 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
ip6 daddr fd7a:115c:a1e0::/48 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
}
I lowered the priority from 0 to -100 to make sure these apply before Mullvad's firewall rules, and also added the rule meta mark & 0x00ff0000 == 0x00080000 ct mark set 0x00000f41
. This allows some additional Tailscale traffic to avoid rejection by Mullvad's firewall rules.
One last hurdle is that any time you disconnect and reconnect to Mullvad, it will undo the routing table reordering that we did. I plan on writing a cron job that periodically checks for this and corrects it, but I haven't actually gotten around to that yet.
Also, make sure you use Mullvad's privacy check page before using an exit node configured like this. On some browsers (e.g. Firefox for Android) your Tailscale address is leaked through WebRTC, creating a unique fingerprint that could be used to identify your VPN traffic.
Thanks @ajgrf. When I run ip rule list
, the output does match yours, and I've added the firewall rule but it seems there's still something wrong with my setup. The exit node does show up as connected on Tailscale but I can't access the internet on it. Will continue to troubleshoot and post an update if it works.
Does your exit node function without Mullvad running? Do you have any extra firewall rules hanging around? (Check with nft list table inet mullvad-ts
.)
It's also possible that the NixOS firewall is helping me out too. When I enabled tailscale, I set the NixOS option networking.firewall.checkReversePath = "loose"
, which runs ip46tables -t mangle -A nixos-fw-rpfilter -m rpfilter --validmark "--loose" -j RETURN
at boot. I don't know what that does exactly (I just copied it from somewhere else), and the table name at the very least is NixOS-specific, but it seems like it may be important.
I think these are the nftables rules that relate to the ip46tables
command in my last post:
table ip mangle {
chain nixos-fw-rpfilter {
fib saddr . mark oif != 0 counter packets 6123199 bytes 8391132930 return
udp sport 67 udp dport 68 counter packets 5 bytes 1690 return
ip saddr 0.0.0.0 ip daddr 255.255.255.255 udp sport 68 udp dport 67 counter packets 0 bytes 0 return
counter packets 61 bytes 18614 drop
}
chain PREROUTING {
type filter hook prerouting priority mangle; policy accept;
counter packets 6123265 bytes 8391153234 jump nixos-fw-rpfilter
}
}
table ip6 mangle {
chain nixos-fw-rpfilter {
fib saddr . mark oif != 0 counter packets 22367 bytes 2401898 return
counter packets 52 bytes 23627 drop
}
chain PREROUTING {
type filter hook prerouting priority mangle; policy accept;
counter packets 22419 bytes 2425525 jump nixos-fw-rpfilter
}
}
Again, I don't know how to interpret this. My notes say it's important for exit nodes and subnet routing, though. Hopefully it's helpful to you trying to get your own exit node working.
Here's my two cents. Thanks to @ajgrf's suggestion, I was able to set up exit nodes. My setup is the following:
Debian testing x64 (Trixie);
I've set dnsmasq+openresolv in order to avoid resolv.conf overwriting.\
Moreover, I forced dnsmasq to use 100.64.0.27 (one of mullvad public dns, more can be found here), whenever I use wg-mullvad and 100.100.100.100 whenever tailscale0 is used, something like this on /etc/dnsmasq.conf
:
server=100.64.0.27@wg-mullvad
server=<custom public dns>@wlp3s0
server=100.100.100.100@tailscale0
I instructed openresolv to use the DNS server on localhost (id est, the dnsmasq server itself).
Unfortunately, while good, the mnf script is not good enough for me since:
What I did was simply edit the file mullvad.rules
this way:
[...]
chain excludeOutgoing {
type route hook output priority -100; policy accept;
meta mark & 0x00ff0000 == 0x00080000 ct mark set 0x00000f41;
ip daddr $EXCLUDED_IPS ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
# Comment the following line if you do not want IPv6 support.
#ip6 daddr $EXCLUDED_IPV6 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
}
[...]
as suggested by @ajgrf and then, made a script like the following one. Please note that there's no error checking, it's just to show the basics of it.
#!/bin/bash
if [ "$1" = "up" ]
then
sudo tailscale set --advertise-exit-node
sudo tailscale up
# These are used to adapt tailscale rules to my custom iptables rules
sudo iptables -D INPUT -j ts-input
sudo iptables -I INPUT 6 -j ts-input
sudo iptables -D FORWARD -j ts-forward
sudo iptables -I FORWARD 3 -j ts-forward
sudo iptables -t nat -D POSTROUTING -j ts-postrouting
sudo iptables -t nat -A POSTROUTING -j ts-postrouting
# This is set so that exit nodes can be used, this is also thanks to ajgrf
sudo ip rule del not from all fwmark 0x6d6f6c65 lookup 1836018789
sudo ip rule add pref 6000 not from all fwmark 0x6d6f6c65 lookup 1836018789
# Use the modified `mullvad.rules` provided by this project
sudo nft -f ./mullvad.rules
elif [ "$1" = "down" ]
then
sudo tailscale down
sudo nft delete table inet mullvad-ts
fi
I was able to use Tailscale on Android to surf the web as if I was connected to Mullvad with this configuration. This is great since there's no way to setup multiple VPNs on Android.
If the Mullvad check page says that you have DNS leaks, try setting, on the host used as exit node, a custom DNS address and set the one of the Mullvad DNSes (in my case, 100.64.0.27, for I set it on dnsmasq).
This works both with and without Mullvad being enabled. Of course, if not, only Tailscale is in use, meaning that when browsing, it will use the actual public IP of the exit node.
Hi, I saw your comment on https://github.com/tailscale/tailscale/issues/2880. Does this script support using the node as an exit node (routing all traffic from the Tailscale network through Mullvad)?