[SOLVED] Tailscale subnet router limited to only some devices?

So that last piece is the kicker then.

Now that I have an exit node setup at my house, I need to have one of their NAS’s Tailscale instances connect to my exit node.

Once that’s done, how are machines in their subnet able to go through the Tailscale network?

I need to set the gateway on those devices to their NAS, but then what? How do I get that NAS to become a gateway; sending traffic over Tailscale?

What kind of network access does Tailscale have on their nas? Are you running a VM with a network bridged to LAN … or something else? How are you running Tailscale there?

Can you configure IP addresses manually on those devices, and set the gateway to the Tailscale LAN IP?

The gateway is the router IP address on that subnet. You can create a policy based route on the router that equates to “if packet is from specific address, set default route to tailscale subnet router, else leave default route as ISP router/uplink.”

That custom routing rule makes sense; although, Tailscale’s router isn’t on their subnet, it’s in the cloud and not publically accessible. Only machines with the Tailscale client can connect to the Tailscale router even when using subnet routing.

Tailscale subnet routing doesn’t change any IPs. All it does is let Tailscale clients access machines on another network. It does not let those machines access Tailscale clients (from my understanding).

If I do this:

set default route to tailscale subnet router

Then those machines will go nowhere as they don’t know where that network is located. It resides on a virtual interface on the NAS itself.

I could tell the router “hey, the gateway for these devices should be the NAS”. “The NAS” being a machine on their network that’s sending all traffic through to my network over Tailscale.

As soon as I do that, the NAS will receive packets saying “here’s my Internet traffic”. Then it will drop all those packets because it has no clue what to do with them. Unless I configure some sort of route table which says “all Internet/Gateway traffic on LAN needs to go to the Tailscale interface”, I can’t see a way for it to know what to do with those packets.

And I wouldn’t know how to set it up so any local SMB traffic would still work and only gateway traffic would go to Tailscale.

TrueNAS is the NAS provider. Tailscale is installed via a Docker container on Kubernetes. There’s no Tailscale NAS.

For this setup, there is a tailscale0 interface on the host even though Tailscale is in a Docker container. But this is a virtual interface. There’s no physical interface for machines to point to.

The tailscale0 network is not bridged with the LAN network. This sounds like a decent solution, but wouldn’t that mean both networks are merged together, and they will have DHCP server conflicts? Also, I don’t think Tailscale gives out IP addresses willy-nilly. Those hosts have to be authenticated.

So in this case, I’d need the NAS in their network to act as a NAT router for non-Tailscale devices.


From what @2FA says, UniFi will let me change their gateway to the NAS’s IP. I haven’t yet tested this because I still don’t have a way to route inbound packages to the virtual Tailscale interface.

Tonight, I tried OpenWRT w/ Tailscale on a spare Raspberry Pi and even set up a pfSense server on a spare SuperMicro server board, but I’ve run into multiple issues in both cases.

Adding the interface

If I add the tailscale0 interface to OpenWRT, then it completely kills the Tailscale connection:

I’ve tried both “Unmanaged” and “DHCPv6 Client”.

Narrowing it down, it seems like clicking “Configure” on the Devices screen is the cause:

I haven’t got it configured right now, but clicking “Configure” happens when you create an OpenWRT interface. I think OpenWRT tries to claim the interface and the Tailscale app loses access.

Surprisingly, the same thing happens in pfSense:

When adding the interface, Tailscale loses access.

Route mappings

While it didn’t add these mappings automatically as it should’ve, I can setup Tailscale mappings for outbound traffic in pfSense:

OpenWRT won’t let me because it only lets you route between OpenWRT interfaces, not physical interfaces.

Connecting to an exit node

I tried doing --exit-node=REMOTE_EXIT_NODE_NAME in pfSense, and it took it, but nothing appears to work. When trying to grab my IP in the CLI, it’s the local public IP, not the exit node’s public IP.

pfSense seems to expect you only want to use the router as an exit node; not that you want to connect your entire network to another one for outbound traffic.

When running the same --exit-node=REMOTE_EXIT_NODE_NAME command in OpenWRT, it actually shows the exit node’s public IP! But since I can’t route any traffic, this is pretty much useless.

At this point, it makes me wanna go back to Raspbian and try to mess with iptables manually (yuck). I’m not skilled enough to do any of that though.


I haven’t configured any routing from LAN to Tailscale just yet, but I really need to figure out the --exit-node situation in pfSense before I do that.

If I could get routing in OpenWRT to use the virtual interface rather than the OpenWRT interface, I’d be set!

I was unable to ping the pfSense box from any machine on the Tailscale network.

This firewall rule fixed that:

I’m locking this down, but it was a firewall rule causing the issue.

Tailscale isn’t a first-class interface in pfSense, but it does work well as a second-class interface unlike OpenWRT.

After messing with a bunch of NAT and other settings and failing to see any change, I thought maybe I need to create a custom Gateway.

pfSense does not let Tailscale be the gateway:

This may or may not matter. This is what I mean about Tailscale being a second-class interface in pfSense. It’s not usable everywhere.

I need to say “any LAN traffic is sent to Tailscale”. Then behind the scenes, Tailscale is sending NATing that traffic on WAN (which could technically be the same interface as LAN).

There’s no routing in the cloud, tailscaled is a router and your big virtual conceptual router is just a bunch of tailscaled being coordinated in a way that might make things look like you have this magical thing.

IIRC, by default it does allow such access, unless you setup ACLs in your tailscale config (ACLs are distributed to each Tailscale client which will then enforce them on either side).

For example,

… let’s say you have a Plex server that also just happens to run Tailscale and thus you have a plex server on 100.100.30.40 …

…if your parents network is 192.168.17.0/24 … and you have a Raspberry pi on 192.168.17.17 running tailscaled as a subnet router advertising 192.168.17.0/24…

… and then you have your parents TV on 192.168.17.38 running with a 192.168.17.17 as a gateway

Your parents TV on 192.168.17.38 will send all packets not for any of the other hosts on the local lan to 192.168.17.17 (the pi) and it will take them off of eth0 and send them into tailscale0, and tailscaled will grab them, encrypt them and send them over to where they’re supposed to go ie. to your Plex server without any kind of nat…
… this all assumes there’s not OS level firewalls on the TV and on the pi and assumes that “forwarding” is enabled on the raspberry pi which is what makes it not drop packets it receives destined for other networks it’s connected to.

tailscaled will create the tailscale0 tun interface and will setup the routing rules to make it possible to send stuff over.

On Plex host that just so happens to also be running tailscaled, tailscaled will install a route to 192.168.17.0/24 via tailscale0 which will let IP packets flow back to your parents TV.

If your parents TV sends a packet destined for 8.8.8.8 to pi on 192.168.17.17 … the routing rules on 192.168.17.17 will not send it through tailscale0, but will instead go to the home router your parents have running on 192.168.17.1 example, and once 8.8.8.8 replies, those replies with a src address 8.8.8.8 will go to your parents TV probably without passing through the pi (or they might pass through the pi, this all depends on how the ARP tables on the home router get updated, this part of ipv4 is a bit arbitrary), replies should get back to the TV either way.


Things get a lot more interesting once you add tailscale exit nodes … and you add VM bridges and firewalls and kubernetes in TrueNAS and docker networking and OpenWRT and pfSense which all have firewalls and try to manage routing rules and IP addresses and so on… you end up with way too many things.

… you kind of need to be patient and debug all the things one by one.

1 Like

Thanks! I read your scenario and actually tried it last night, but Internet packets were dropped, not routed to Tailscale or my router.

I’m avoiding the NAS to make this simpler. I tried this in OpenWRT, connecting to Tailscale and then having my PC pointed at its Gateway. Just like this:

Your parents TV on 192.168.17.38 will send all packets not for any of the other hosts on the local lan to 192.168.17.17 (the pi)

That didn’t work even though packets in OpenWRT were being sent to Tailscale.


Today, I’m gonna try using Raspbian instead. It won’t have a separate firewall to deal with.

From what I’ve been reading, for incoming packets to redirect from one interface to another, you need to configure iptables. If eth0 gets packets it doesn’t know about, it will drop them by default.

And you’re saying Tailscale does that for me?

This is what’s in iptables just after connecting to Tailscale.

$ sudo iptables --list
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ts-input   all  --  anywhere             anywhere

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
ts-forward  all  --  anywhere             anywhere

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain ts-forward (1 references)
target     prot opt source               destination
MARK       all  --  anywhere             anywhere             MARK xset 0x40000/0xff0000
ACCEPT     all  --  anywhere             anywhere             mark match 0x40000/0xff0000
DROP       all  --  100.65.0.0/10        anywhere
ACCEPT     all  --  anywhere             anywhere

Chain ts-input (1 references)
target     prot opt source               destination
ACCEPT     all  --  router.my-subnet.ts.net  anywhere
RETURN     all  --  100.116.92.0/23      anywhere
DROP       all  --  100.65.0.0/10        anywhere

Changing my PC’s gateway to this Raspberry Pi on Raspbian, all Internet traffic is dropped.

It’s not automatically routed even without connecting to an exit node.

If I do connect to an exit node, none of these iptables entries changes. What am I missing? Something should’ve changed, or there’d be no way for all my local packets to go through Tailscale.

I got it working finally on Raspbian. I had to run this iptables command:

sudo iptables -t nat -A POSTROUTING -o tailscale0 -j MASQUERADE

This creates a NAT routing of anything going to tailscale0.

A few things, I don’t know how to save this. There’s iptables-persistent, but I’m not sure if there’s a proper way to save custom iptables changes and make sure they get loaded at boot.

I was wrong about IP tables. When you “list”, that doesn’t list everything. Here’s the nat table after changing it:

  $ iptables -t nat -L
  Chain PREROUTING (policy ACCEPT)
  target     prot opt source               destination

  Chain INPUT (policy ACCEPT)
  target     prot opt source               destination

  Chain OUTPUT (policy ACCEPT)
  target     prot opt source               destination

  Chain POSTROUTING (policy ACCEPT)
  target     prot opt source               destination
  ts-postrouting  all  --  anywhere             anywhere
+ MASQUERADE  all  --  anywhere             anywhere

  Chain ts-postrouting (1 references)
  target     prot opt source               destination
  MASQUERADE  all  --  anywhere             anywhere             mark match 0x40000/0xff0000

I still need to try this on a device at their place, but on my computer to the Raspberry Pi running Raspbian, it works great!

From what @risk is saying, I may not need iptables at all because it’s possible Tailscale subnet routing is already doing this for me. But because of Docker 'n such, we’re not sure what’s actually going on there.

Next Steps

I wanna try this on the NAS to see if I don’t need to add yet another machine to their network.

I still need to figure out a few more things:

  1. I don’t want my NAS to forward any packets through Tailscale, only other clients using it as a gateway.
  2. I want packets going to my NAS, rather than the Internet to not go through Tailscale.

Not sure if this NAT routing can be configured to exclude the NAS itself.

I had my parents test it on their Roku. Took forever to figure out OpenWRT, but here’s what I did.

I have Tailscale configured with public DNS**. That’s important if you want to do this yourself the way I did.

Step 1 - Reconfigure Gateway on their Network

Their router is currently OpenWRT, not yet UniFi, so this is what I did.

Update /etc/config/dhcp:

config host
        option name 'nas'
        option ip '192.168.20.144'
        option mac 'D0:50:99:C2:B7:0E'

config host
        option name 'RokuUltra'
        option ip '192.168.20.142'
        option mac 'AC:AE:19:FC:21:A4'
        option dns '1'
        option tag 'gateway_to_my_network'

config tag 'gateway_to_my_network'
        list dhcp_option '3,192.168.20.144' # Gateway address
        list dhcp_option '6,100.100.100.100' # Tailscale's DNS server

After changing that config, run these commands:

uci commit dhcp
/etc/init.d/dnsmasq restart

After I did that, they had to unplug and plugin Ethernet on the Roku, so it could pull the correct IP information.

At this point, all traffic is routed through the NAS which as IP forwarding enabled:

Step 2 - Setup Exit Node on NAS in their network

I needed to both connect to the exit node in the Docker container, and I needed to route all incoming traffic to Tailscale as well.

This box does not need to be a subnet router. I wasn’t able to test that situation.

Access the Tailscale Docker container’s shell and run:

tailscale set --exit-node=MY_NETWORK_NODE_NAME --exit-node-allow-lan-access

Change MY_NETWORK_NODE_NAME to the name of the exit node.

Then go to TrueNAS’s shell and run this:

sudo iptables -t nat -A POSTROUTING -o tailscale0 -j MASQUERADE

This sets all incoming traffic to pass traffic through to tailscale0 using NAT, so all IPs appear as though they’re they NAS’s Tailscale IP.

Done!

And that’s it! Once those steps are done, you can circumvent Netflix’s one-house policy :stuck_out_tongue:.

This was a fun project.

2 Likes

Not sure if it helps after the fact, but there is an additional tool to view applied iptables rukes

sudo iptables-save

Which prints the current rules to screen.

Then

sudo iptables-save >> Sawsiptables.file

You can edit the file line by line if you wanted to change routing for some ip’ or sources or such. (Singe arrow clears and saves new, double adds onto any existing, or new) Then

sudo iptables-restore Sawsiptables.file

But you got it working regardless

1 Like

I did see ipstables-save, and I tried doing iptables-restore on it right after, but it errored :frowning:.


This was a “get it working and document it” kinda thing. Now that I’m done, I reverted all my changes since this was a proof-of-concept that isn’t currently needed.

Can’t believe I got this working on the NAS, also can’t believe it all came down to 1 line of iptables. Literally 1 line that took 3 days to figure out because I was scared of iptables.

I built a pfSense box, setup a Raspberry Pi with 2 OSs, and spent hours looking at videos and reading articles until I finally found a single answer on a Linux StackExchange question asking about the exact same issue for OpenVPN’s tun0. Wow…


TrueNAS makes a bad router. If I wanted a permanent solution I’d use the Raspberry Pi.

Another issue with using the NAS is all traffic coming in from LAN, including SMB and Tailscale exit node traffic, gets routed as well. So ideally, I’d have a separate router (the Raspberry Pi) specifically designated to this one task.

2 Likes

UPDATE

I got the iptables-restore thing working :+1:. Worked great with the correct 1-line command.

I finally set this up at my parent’s house full-time; more than my NAS demo, but multiple things changed:

  1. I got a new router and gave them my old UniFi USG.
  2. UniFi’s system is, by far, the worst router software I’ve used when you wanna do something interesting. I wasn’t able to accomplish this task in UniFi even though EdgeOS supports it. I even tried running VLANs with all UniFi managed switches, and it wasn’t able to assign devices to VLANs over DHCP. As far as I understand it, that’s called 802.1Q.
  3. I turned off DHCP in UniFi on their network and configured the old OpenWRT router as a DHCP-server. I setup DHCP options 3 (gateway) and 6 (DNS) as the UniFi router.
  4. Then, like before, I changed the DHCP entries on only a few machines to run through a Raspberry Pi 3B acting as a Tailscale VPN router.

Full Configuration

OpenWRT LAN interface

OpenWRT Devices

UniFi Network

Why UniFi sucks for this

When I was doing it with VLANs in UniFi, the Raspberry Pi needed 2 Ethernet adapters. One for the main network and another for the VLAN network.

UniFi lets you set the gateway address, but that means everything on that VLAN, including the Raspberry Pi, points to the Raspberry Pi as a gateway. Unless I statically assigned its gateway as the UniFi router, there was no way for it to access the Internet from inside the VLAN.

My solution was 2 Ethernet adapters, but that took 2 switch ports and was completely unnecessary. And like I said, this only worked on switch ports. I’d have to create a separate WiFi SSID to VLAN 2 other wireless-only devices.

I also tried creating firewall rules to and from the VPN VLAN, but was unable to communicate with devices on that other subnet. It shouldn’t be this hard to figure out.

In the end, I think using OpenWRT as a DHCP server was the simplest route since I already got it working, and they already had it on their own router.

VPNing only specific domains

One thing I’d like to do is route only certain domains through Tailscale, but I’m not versed enough in iptables to figure that out.

No IPv6

I have absolutely no clue how to figure out IPv6 outside of UniFi. I can set it up in OpenWRT, but there’s no UniFi WAN interface to grab IPs with that prefix. I ended up just turning it off in UniFi and OpenWRT.

1 Like

If the solution is ugly, but it works, it’s a “Bodge” in our parlance. or a Jerry Rigged solution. or Janky.
I love such.

Obviously there Should be a way to do it with the proper gear, but if it’s a hot mess of fail, then simply getting it working the way you did, is a win!

2 Likes

Thanks! Yeah, it’s super jank, but the functionality is solid. I can easily add new devices to the VPN now. I’m specifically documenting everything on this forum, so I don’t forget what I was thinking when I try to change something in the future.

The final solution is surprisingly less-jank than using UniFi + VLANs or UniFi + JSON :man_shrugging:.

I’m just glad OpenWRT is behind NAT now. One less thing I have to worry about. Although, Tailscale subnets make it easy to target, and I can even install Tailscale on the device itself provided I add more storage.

1 Like

Hey man, I’m trying to implement a solution similar to what you did but I need some help.

What I have so far:

  1. Raspberrypi acting as an exit node at my friend’s house.
  2. Raspberrypi that my Roku ultra connects to, that is connected to my router (Roku <-----> RPi <-----> router)

To get this to work do I just need to have raspberrypi #2 use raspberrypi #1 as an exit node and run the command “sudo iptables -t nat -A POSTROUTING -o tailscale0 -j MASQUERADE” on raspberrypi #2?

Were you able to get this working?

I’m not certain what steps you took, so it’s a bit difficult to understand exactly how you have it setup.

There are other ways to set this up in the Raspberry Pi, but I’m not an expert at IP tables or much of Linux networking.

The way my config worked, the DHCP server in the router told the Roku to use the Raspberry Pi as a Gateway, and the Raspberry Pi is setup to send all packets that come in through the VPN.