tailscale
tailscale copied to clipboard
Support adding Mullvad servers as Exit Nodes?
We have a number of users who try to use multiple VPN products at the same time and then get sad when they inevitably break, trying to hook into the OS networking stacks at the same places and conflicting:
https://github.com/tailscale/tailscale/issues?q=is%3Aissue+label%3Avpn-interop+
But of all the other VPN services, Mullvad (https://mullvad.net/) seems like the best/easiest one for us to support interop with.
Mullvad already supports Wireguard, so we could probably pretty trivially support letting you add Mullvad Servers to your network such that they show up as Tailscale Exit Node options.
Possible options:
- CLI tool to just do the API calls to Tailscale to pretend to be a Tailscale node, but actually set the endpoints/etc of a Mullvad server.
- Let you define Mullvad servers in your tailnet's ACL/Policy JSON. Then the control plane server would blend them in to your netmap so they'd be Exit Node options.
- Add your Mullvad account number to your Tailnet policy, then we do some API calls or something to query all Mullvad servers and and add them all?
- web GUI options for one/some of the above.
For now I was playing with just doing (1) as a proof of concept.
I see reference to a Mullvad API but I've yet to find it. The Mullvad client is open source, though, so I assume that configuring Wireguard within their app ultimately does some API calls to Mullvad.
3 sounds fun. A bit of googling found this:
curl https://api.mullvad.net/wg/ -d account=YOURMULLVADACCOUNTNUMBER --data-urlencode pubkey=YOURPUBLICKEY
One difficulty is that it's unlike any other exit node we have, in that only 1 device in your network gets to use it. Mullvad gives you a few WireGuard tunnels, but effectively each device using an exit node consumes one of a few slots, and once you're out, that exit node... what, stops existing? Will require propagating significantly different data to clients, because they're now going to have to "check out" and "return" VPN slots to when they turn an exit node on/off. And if I turn on the exit node then throw my laptop in a wood chipper, is that slot blocked for ever? How do we recover?
Some thoughts on how our concepts and privacy VPN concepts don't overlap cleanly.
@danderson, yeah, I was just thinking about that. One option is we do it per-user, not per-tailnet, more like sharing.
API stuff, from their curl-to-bash script https://mullvad.net/media/files/mullvad-wg.sh ....
$ curl -LsS https://api.mullvad.net/public/relays/wireguard/v1/ | jq .
{
"countries": [
{
"name": "Australia",
"code": "au",
"cities": [
{
"name": "Melbourne",
"code": "mel",
"latitude": -37.815018,
"longitude": 144.946014,
"relays": [
{
"hostname": "au3-wireguard",
"ipv4_addr_in": "103.231.88.2",
"ipv6_addr_in": "2407:a080:3000:12::a03f",
"public_key": "kXXykjh6KqiE/pvtmTV8kCB+jhhkl9kT0Dg+yyDz8hg=",
"multihop_port": 3100
},
{
"hostname": "au4-wireguard",
"ipv4_addr_in": "103.231.88.18",
"ipv6_addr_in": "2407:a080:3000:11::a04f",
"public_key": "D2ltFd7TbpYNq9PejAeGwlaJ2bEFLqOSYywdY9N5xCY=",
"multihop_port": 3102
}
]
},
{
"name": "Sydney",
"code": "syd",
"latitude": -33.861481,
"longitude": 151.205475,
"relays": [
...
And then it also has the bit that @crawshaw found above.
Or purely a per-device setting that the control plane never sees. That is, we let you interop with mullvad, but don't give you any centralized control. Less "magical", but lets us skip building a whole new concept in our control plane. (unless that concept is applicable more widely, in which case, worth it?)
Would love to see a feature like this. I'm planning to setup a Raspberry Pi and connect it to Mullvad and Tailscale as an exit node. Just waiting on the ability to allow LAN access on Android when an exit node is in use. However, the ability to use Mullvad as an exit node directly would be next-level.
So, it depends what are people's needs. For me, it was like this: a) Have Tailscale running so I can access the server b) Have Mullvad running so I can change my geolocation while browsing This would alleviate from constantly turning Mullvad on/off when I need to jump in my server. Solution - As long as you use Windows and Firefox for browsing this is possible (thanks to Mullvad support for helping out).
Steps:
- You need to use the default Wireguard client and the Mullvad Firefox app.
- Get a Wireguard config from Mullvad and edit "allowed IPs" line as follows: AllowedIPs = 0.0.0.0/5, 8.0.0.0/7, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/2, 128.0.0.0/3, 160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4, 8.8.8.8/32, 10.64.0.0/10 N.B. All the IPs need to be in one line to work.
- Connect to both Tailscale and Mullvad. When using Firefox, you can change the Socks5 proxy that goes through Wireguard to change the geolocation. The Firefox addon also works as a killswitch so nothing will go out it the Wireguard goes down.
- Any other browser or app should work as usual and should be able to connect to the server running Tailscale.
The last entry in the allowed IPs list in item 2 is "10.64.0.0/10"; should that be "100.64.0.0/10" ?
This should exclude 100.64.0.0/10 and IPv6 from the VPN. At least that I think is the logic.
I currently use exactly this combination, Tailscale and Mullvad, and only the Tailscale client.
To be able to "set it and forget" (especially on my iPhone) and still have both access to my Tailscale network and Mullvad VPN servers I have configured my ASUS router with (kernel level) WireGuard to selectively push only traffic coming from a Tailscale exit node on that lan into the outgoing tunnel to the Mullvad (multihop) servers, while other traffic goes outside the WireGuard tunnel.
Then I can use the Tailscale client alone and mostly keep "Use Exit Node" on. But that switch is also the choice between obfuscating outgoing traffic or not everywhere, while always staying in the Tailscale network. This is especially handy on the iPhone which can only have one vpn connection at a time.
(Also see issues https://github.com/tailscale/tailscale/issues/1534 and https://github.com/tailscale/tailscale/issues/2504 for further low-hanging "set it and forget" features with regard to not taking advantage of the on-demand feature on iOS/Mac clients who only support one vpn connection at a time).
Tailscale integrated support for Mullvad exit nodes would look and work the same from the outside, but would of course alleviate both my lan exit node and router of traffic and encryption work (especially if Mullvad was supported on a device level, but also regardless), and would also make it a bit faster by going through less (unoptimized) hops in one particular lan. I guess there would be a benefit to using the same WireGuard implementation for both and considering Mullvad a "peer" too?
I suppose (as an amateur!) a benefit of having the feature on a network level, as opposed to device level, is that one could use the same Mullvad "slot"/key for all of that exit node's traffic from the owner's network (as I do), and keep only the existing Tailscale encryption "hop" and keep-alive on devices. Especially important on battery powered mobile devices.
(It may be a hot selling point too and bring a marketing partner...)
@bohtho , what asus router are you using? I'd very much be interested in a more in-depth guide of how you set up the router to work like this. Also, would you say that this has decreased your speed significantly? With mullvad on my PC I can get 600 up/down but using VPN Fusion on my asus router the speed drops tenfold.
@Koliera I have an ASUS AX XT8 mesh at that location.
Well, there's not much more to explain, the "Multiple VPN" tab (or "VPN Fusion"?) set up for a Mullvad Wireguard configuration, allowing all IPs including the ones used by lan exit node (It's also the default connection actually while other outgoing clients are selectively "freed" from the VPN tunnel (in the "Internet connection" item)). I have an extra static route in the router to safely bring any Tailscale IPs back to the lan exit node, but I'm not sure that's necessary given that the lan exit node is also a subnet router and accepting routes.
It's fast reacting but the speed falls quickly. But I give it a chance on account of not optimizing the multihop Mullvad servers yet, and also because those router features (incl WG server) are only available in the latest Asuswrt betas (now at RC3-3). What's still missing is a Tailscale subnet router and exit node implementation 😊
I would much rather have "native" Mullvad exit nodes in Tailscale though. I guess any interop with pure WireGuard is relevant to this GitHub issue too.
(I highly recommend discussing ASUS routers, Asuswrt and beta features in the forum at http://www.snbforums.com/forums/asuswrt-official.51/)
Maybe not exactly the same issue as this, but I was able to access my machine while connected to Mullvad (using their daemon and CLI, from https://github.com/mullvad/mullvadvpn-app) over Tailscale by adding the following rule to my nftables:
table inet excludeTraffic {
chain excludeOutgoing {
type route hook output priority -100; policy accept;
ip daddr 100.64.0.0/10 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
}
chain excludeIncoming {
type filter hook input priority -100; policy accept;
ip saddr 100.64.0.0/10 ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
}
}
which I pieced together from their help page: https://mullvad.net/en/help/split-tunneling-with-linux-advanced/
Aha! Of course this was already on your radar :)
My current setup is that I have WireGuard.app connected to a Mullvad node near me with AllowedIPs 10.64.0.0/10, and then I use FoxyProxy in Firefox to select SOCKS5 servers (all of which are reachable from any Mullvad WireGuard connection).
The ways Tailscale integration would help are
- not having to run WireGuard.app in parallel to have access to Mullvad SOCKS5 nodes in 10.64.0.0/10
- being able to select Mullvad nodes as exit nodes without clashing with Tailscale.app
Note that for (1) the Tailscale client would have to select the Mullvad "entry point" (the WireGuard node to connect to and route 10.64.0.0/10 through) somehow, ideally automatically based on latency.
For (2) there needs to be a way to select the exit node from the very long list of nodes, so the current UI might not work.
FWIW, I would happily pay for Mullvad at a steep markup through my Tailscale account, just like Mozilla VPN is Mullvad within a Mozilla branded client at a markup. They are friendly folks, so consider reaching out!
Any chance of hearing if Tailscale might think about working on a custom VPN exit node? Would be great if there would be an easy way to somehow upload/use a wireguard config file and set it as the exit node.
I promise that we will update the bug when work begins in earnest.
Thanks for the services some question :
- Does this feature will come (when working properly) as an official feature ?
- 2 Will our exit node be the "entry" node of the VPN ?
Thanks for these answer
This is a tracking bug for a feature request. No work has been done on it. You can best signal support by clicking on the reaction buttons in the top post, which feeds into prioritization choices. We will not have answers to what the feature might look like until work actually begins.
This is a tracking bug for a feature request. No work has been done on it. You can best signal support by clicking on the reaction buttons in the top post, which feeds into prioritization choices. We will not have answers to what the feature might look like until work actually begins.
Ok thanks for the answer (so i add my :+1: ) since i'm interested in such feature.
https://github.com/tailscale/tailscale/issues/925#issuecomment-1164218447
I've made a script to set up a Mullvad VPN from Wireguard config files, with support for Tailscale (by updating the routing table after the tunnel goes up): https://gist.github.com/1player/e9cadfef833d5eb5a23c30223f560147
Excellent, happy to see that this is still on the radar. One of the great features that would differentiate Tailscale from other options. Nice!
I wasn't able to get the routing table approach to work, but I did manage to get Mullvad and Tailscale to play nice by using the following nftables rules:
table inet mullvad-ts {
chain exclude-outgoing {
type route hook output priority 0; policy accept;
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;
}
chain allow-incoming {
type filter hook input priority -100; policy accept;
iifname "tailscale0" ct mark set 0x00000f41 meta mark set 0x6d6f6c65;
}
}
By marking the incoming and outgoing Tailscale traffic like this, Mullvad lets it through the rest of the routing table without blocking it or directing it to their servers (see Mullvad's split tunneling docs).
I created this script as a workaround that is perfectly working for me in Linux: https://github.com/r3nor/mullvad-tailscale
@r3nor does this script allow you to run the tailscale node as an exit node too? Thanks in advance!
I have multiple machines using Mullvad and when using tailscale it simply doesn't work. The only way I found to SSH to another machine, say machine 2, from machine 1 is to disconnect from Mullvad on machine 2 and add split-tunneling rules on machine 1 without the need to disconnect from Mullvad on that machine. But if all the machines are connected to Mullvad I didn't find any way to make this work even if I add split-tunneling rules on all of them. I tried ZeroTier and it worked out of the box for me. I like Tailscale's features more but for now I'll be just using ZeroTier until this issue is resolved I guess.
I have multiple machines using Mullvad and when using tailscale it simply doesn't work. The only way I found to SSH to another machine, say machine 2, from machine 1 is to disconnect from Mullvad on machine 2 and add split-tunneling rules on machine 1 without the need to disconnect from Mullvad on that machine. But if all the machines are connected to Mullvad I didn't find any way to make this work even if I add split-tunneling rules on all of them.
I tried ZeroTier and it worked out of the box for me. I like Tailscale's features more but for now I'll be just using ZeroTier until this issue is resolved I guess.
Just chiming in to say I went the other way, Tailscale all the way, by dropping Mullvad and setting up a couple of Tailscale exit nodes in different regions on Oracle Cloud's free tier. The latency is awfully low too on the same WireGuard all the way.
Just chiming in to say I went the other way, Tailscale all the way, by dropping Mullvad and setting up a couple of Tailscale exit nodes in different regions on Oracle Cloud's free tier. The latency is awfully low too on the same WireGuard all the way.
I've just tried implementing this and it works well. Thanks for the very good idea I really liked it.
Just chiming in to say I went the other way, Tailscale all the way, by dropping Mullvad and setting up a couple of Tailscale exit nodes in different regions on Oracle Cloud's free tier. The latency is awfully low too on the same WireGuard all the way.
I've just tried implementing this and it works well. Thanks for the very good idea I really liked it.
The problem with that it's you loose the "hide in the noise" from VPN, now people can just do (these ip = you). And if you protect yourself from your ISP you just move the "Trust" to the server hosting privider (where mullvad do audit to prove their claim).
My knowledge of routing tables is limited, so I couldn't make Mullvad and Tailscale work together by modifying routing tables in macOS. I'm not even sure if that would be possible. However, I found another way to route all traffic except local traffic and Tailscale's traffic through Mullvad's tunnel.
While the suggested solution is only tested on macOS, I believe it would work on Linux and Windows as well.
Requirements:
- The official WireGuard client
- WireGuard configuration files downloaded from Mullvad or some other provider
- List of IPs to be included in Mullvad's tunnel, e.g.,
0.0.0.0/0
for all IPv4 traffic - List of IPs to be excluded from Mullvad's tunnel
Steps:
- Subtract the IPs to be excluded from the tunnel from the IPs to be included in the tunnel and update the
AllowedIPs
field in your WireGuard configuration with the result - Go to Tailscale Preferences and uncheck Use Tailscale DNS Settings
- Connect to Mullvad
- Connect to Tailscale
Here is a Python script that helps with the subtraction. In this example, I have subtracted Tailscale's IPv4 range from the list of all public IPv4s. I believe the netaddr
package supports IPv6 too. You just need to add the appropriate IPv6 ranges to the list.
from netaddr import *
public_ips = IPSet(["1.0.0.0/8", "2.0.0.0/8", "3.0.0.0/8", "4.0.0.0/6", "8.0.0.0/7", "11.0.0.0/8", "12.0.0.0/6", "16.0.0.0/4", "32.0.0.0/3", "64.0.0.0/2", "128.0.0.0/3", "160.0.0.0/5", "168.0.0.0/6", "172.0.0.0/12", "172.32.0.0/11", "172.64.0.0/10", "172.128.0.0/9", "173.0.0.0/8", "174.0.0.0/7", "176.0.0.0/4", "192.0.0.0/9", "192.128.0.0/11", "192.160.0.0/13", "192.169.0.0/16", "192.170.0.0/15", "192.172.0.0/14", "192.176.0.0/12", "192.192.0.0/10", "193.0.0.0/8", "194.0.0.0/7", "196.0.0.0/6", "200.0.0.0/5", "208.0.0.0/4", "10.64.0.1/32"])
socks_ips = IPSet(["10.64.0.0/10"])
tailscale_ips = IPSet(["100.64.0.0/10"])
endpoint_ip = IPSet(["198.54.134.98/32"])
filtered_ips = (public_ips | socks_ips) - tailscale_ips - endpoint_ip
print(filtered_ips)
The AllowedIPs
would therefore look like this:
AllowedIPs = 1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6, 8.0.0.0/7, 10.64.0.1/32, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/3, 96.0.0.0/6, 100.0.0.0/10, 100.128.0.0/9, 101.0.0.0/8, 102.0.0.0/7, 104.0.0.0/5, 112.0.0.0/4, 128.0.0.0/3, 160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4
If you use Mullvad's SOCKS5 proxies, the AllowedIPs
would look like this:
AllowedIPs = 1.0.0.0/8, 2.0.0.0/7, 4.0.0.0/6, 8.0.0.0/7, 10.64.0.0/10, 11.0.0.0/8, 12.0.0.0/6, 16.0.0.0/4, 32.0.0.0/3, 64.0.0.0/3, 96.0.0.0/6, 100.0.0.0/10, 100.128.0.0/9, 101.0.0.0/8, 102.0.0.0/7, 104.0.0.0/5, 112.0.0.0/4, 128.0.0.0/3, 160.0.0.0/5, 168.0.0.0/6, 172.0.0.0/12, 172.32.0.0/11, 172.64.0.0/10, 172.128.0.0/9, 173.0.0.0/8, 174.0.0.0/7, 176.0.0.0/4, 192.0.0.0/9, 192.128.0.0/11, 192.160.0.0/13, 192.169.0.0/16, 192.170.0.0/15, 192.172.0.0/14, 192.176.0.0/12, 192.192.0.0/10, 193.0.0.0/8, 194.0.0.0/7, 196.0.0.0/6, 200.0.0.0/5, 208.0.0.0/4
~Shortcomings:~
- You can no longer use Tailscale's MagicDNS to access other machines in your network. Therefore, you have to run something like
/Applications/Tailscale.app/Contents/MacOS/Tailscale ping my_server
to get the IP address of my_server
.
Update on MagicDNS:
You can use Tailscale's DNS by enabling MagicDNS in the settings and changing the DNS in WireGuard's interface to 100.100.100.100
, i.e.,
DNS = 100.100.100.100
You can then change your Global nameservers to Mullvad's 193.138.218.74
or Quad9 and enable "Override local DNS".
Please let me know if you have any solutions to address this shortcoming.
References:
https://github.com/tailscale/tailscale/issues/2880#issuecomment-970325618 https://stackoverflow.com/questions/37283929/find-subtract-ipset
FWIW, you can have a tailscale peer connected to Mullvad, and use this peer as an exit node.
You just have to make sure the tailscaled service starts after the mullvad wireguard wg-quick and it'll work
Create an override for tailscaled:
sudo systemctl edit tailscaled.service
[Unit]
[email protected]
where xxY is the server code you chose for your wg-quick service
Oh and, the tailscale service needs to be up with --accept-dns=false
if you do not want DNS leak