14 comments

[ 0.20 ms ] story [ 41.3 ms ] thread
It is surprising to see this here, but I see how it could be interesting. When we were experimenting very early on with Tailscale I went Googling around for IP ranges just to understand the space better and that was when I first discovered CGNAT.

It took a bit of digging through RFC6598 to realize that, if it's only being used properly (and I had never seen it used directly), then it would be generally available for an overlay network.

Since then we've run into a couple of other edge cases where people are using CGNAT. More reason for us to get our IPv6 support sorted out.

I'm currently using ZeroTier for a similar purpose to what Tailscale seems to be targeted at.

The problem I ran into with ipv6 is that the OS (either macOS or Android, I don't recall which unfortunately) won't query for AAAA records when it does DNS lookups unless there is a DNS resolver configured that is reachable over ipv6.

ZeroTier doesn't provide its own DNS, so I'd manually entered A and AAAA records into Google Cloud DNS on a domain I own, but because of that quirk I wasn't able to use ipv6 since my Internet links at home and work were both ipv4 only.

It's MacOS, or at least I know MacOS does that.

One solution would be to run a local DNS service like Cloudflare DNS-over-HTTPS proxy and then enter ::1 (IPv6 loopback) as your DNS. I bet that would work, but I haven't tried it. It also improves privacy and security on untrusted networks. Not sure how it handles the captive portal problem though. Maybe Cloudflare's service has a shim for that.

MacOS used to do the simple thing, but at some point in a recent release they started being "smart" and added this annoying restriction.

So how does Tailscale handle the situation when it assigns 100.64.x.y to a device that happens to be behind a CPE device with the same IP?
The standard deployment of CGNAT means the customer router gets a 100.64 address on the side facing the ISP, then NATs it with something like 192.168. So the cgnat range is not visible to the end user machine and there is no conflict if we use it again.

We have unfortunately discovered phone carriers who hang out cgnat addresses directly to phones, so we will need to do something else there.

Which is perfectly valid usage. CGNAT addresses are supposed to be used on ISP-customer link. Whether there is customer router or just customer end computer on that link is customer decision.

The phone carrier situation is similar - CGNAT address is assigned to customer device on radio interface, whether that device is phone or LTE-based router is customer decision.

(comment deleted)
I don't think Tailscale's use of 100.x.x.x address space conforms with the RFC, but I don't think that there are any better alternatives out there. Do note though, once people start abusing the 100.x.x.x space, it will become "just another private IP space" and lost its significance:

RFC6598 requires that, when used as a routable address, the device must be able to do address translation across router interfaces when the addresses are identical on two different interfaces.

[1]: https://tools.ietf.org/html/rfc6598#section-4

CGNAT block is popular in private k8s as overlay network address space because often the enterprise network already claims rfc1918 blocks. I'm not sure how close to the line that kind of usage is but I suspect it is SHOULD NOT. Speaking of, I probably should not even post this comment as it will now be indexed and served in search results, further contributing to the corruption. Alas, it works.
(comment deleted)
> We are considering using other unused address ranges, including the otherwise wasted 0.x.x.x

0.x.x.x is currently incompatible with WordPress: https://github.com/WordPress/WordPress/blob/641c632b0c9fde4e...

To put it another way, 0.x.x.x and 100.x.x.x don't have equivalent properties in WordPress. 0.x.x.x is blocked in some cases to prevent SSRF attacks. 100.x.x.x is considered a "normal" IP address.

There is a http_request_host_is_external hook you can use to get past that via add_filter().
But this would be trivial to fix, no?
IPv4 address space is too small, exhibit #34138408340314.