#3290·headscale

[Bug] Exit node drops traffic to destinations in its directly connected external subnet

Author: pvaCreated May 29, 2026Updated Sep 14, 2026
Labelsbugquestionstale

Is this a support request?

  • This is not a support request

Is there an existing issue for this?

  • I have searched the existing issues

Current Behavior

There are two nodes in a Headscale/Tailscale network:

  1. exitnode — node that advertises itself as an exit node. It is connected directly to the internet:
  • Internal IP: 10.1.0.2/24
  • External IP: 88.88.88.2/24
  • External subnet: 88.88.88.0/24
  1. clientnode — client that uses exitnode as exit node:
  • Internal IP: 10.2.0.2/24

In such a configuration, clientnode accesses the Internet using exitnode's external IP address, 88.88.88.2, as the source address, and general Internet access works as expected. For example, access to external addresses such as 8.8.8.8 works.

However, clientnode cannot access other addresses from the same external subnet, 88.88.88.0/24, that is directly connected to exitnode.

Before enabling exitnode as an exit node, ICMP ping from clientnode works to both publicly routable Internet addresses, 88.88.88.3 and 8.8.8.8:

bash
clientnode$ ping -c1 88.88.88.3
# OK

clientnode$ ping -c1 8.8.8.8
# OK

But after we enable exitnode as the exit node:

clientnode$ tailscale up --exit-node=exitnode --accept-routes --login-server=https://vpn.example.com

pinging 88.88.88.3 is not working anymore:

bash
clientnode$ ping -c1 88.88.88.3
# FAIL

clientnode$ ping -c1 8.8.8.8
# Still OK

The problem appears only for destinations that belong to the external subnet directly connected to the exit node itself, in this example: 88.88.88.0/24.

Expected Behavior

When clientnode uses exitnode as an exit node, it should be able to reach any publicly routable Internet address through that exit node, including addresses from the external subnet directly connected to exitnode.

In this example, ping from clientnode to both 8.8.8.8 and 88.88.88.3 should work.

Note: we do not want exitnode to announce 88.88.88.0/24 as a subnet route to all clients. Clients that do not use exitnode as an exit node should continue reaching 88.88.88.3 through their normal Internet route, with their own public source IP address visible on the Internet.

Steps To Reproduce

  1. Connect to two nodes to a Headscale/Tailscale network:

    • exitnode

      • advertises itself as an exit node (and is allowed to be used as exitnode in ACL)
      • has an external interface with IP 88.88.88.2/24
      • the directly connected external subnet is 88.88.88.0/24
    • clientnode

      • uses exitnode as its exit node
  2. From clientnode, verify that both public IP addresses are reachable before enabling the exit node:

bash
   ping -c1 88.88.88.3
   ping -c1 8.8.8.8

Both pings should succeed.

  1. Enable exitnode as the exit node on clientnode:
bash
   tailscale up \
     --exit-node=exitnode \
     --accept-routes \
     --login-server=https://vpn.example.com
  1. From clientnode, ping a normal Internet address:
bash
   ping -c1 8.8.8.8

This still works.

  1. From clientnode, ping another public IP address from the external subnet directly connected to exitnode:
bash
   ping -c1 88.88.88.3

Observe that the ping to 88.88.88.3 fails, even though general Internet access through the exit node still works.

Environment

markdown
- OS: Gentoo Linux
- Headscale version: headscale version v0.27.2-rc.1+dirty
  commit: c6d399a66ca9ec94bb84e78e8edf9a31981f554c
- Tailscale version: 1.96.5

Runtime environment

  • Headscale is behind a (reverse) proxy
  • Headscale runs in a container

Debug information

We found a workaround: advertise 88.88.88.0/24 on exitnode, but do not approve this route in Headscale. This prevents the route from being distributed to clients, but it makes the local tailscaled on exitnode allow traffic from clientnode to destinations inside 88.88.88.0/24.

Still, this feels more like a workaround than a proper fix.

The current logic seems intended to exclude LAN/private networks from automatic exit-node access. But in this case the excluded subnet is a publicly routable Internet subnet directly connected to the exit node, not a private LAN.

Maybe publicly routable directly connected networks should not be treated the same way as LAN/private networks when shrinking the default route for an exit node.

https://github.com/juanfont/headscale/issues/1637#issuecomment-4439510460