> Many home routers try to preserve the source port in external mappings. This is a property called “equal delta mapping” – it won’t work on all routers but for our algorithm we’re sacrificing coverage for simplicity.
It is precisely this point that has flummoxed me when connecting my p2p wireguard config[1] with a friend that uses a pfsense router, no matter what we tried, pfsense always chooses a random source port.
But in the simple case this blog outlines, if both ends use the same source port, this method punches through 2 firewalls effortlessly:
There are plenty of free public STUN servers and ways to share the information they return.
The real problem is the port randomization if any client is behind a symmetric NAT. The search space for randomly trying port numbers is too large.
There are some ways to reduce the search space, like port prediction. But ultimately, a large dose of port scanning is the only way I know of to make the connection reliably. And there’s only so much of that you can do before triggering IPS or overwhelming the NAT.
In this era where AI is eating away at how deterministic computers are, I really appreciate reading about an elegant solution to a real problem using deterministic logic.
Needing to punch holes in NAT is one of the most idiotic own-goals in the entire field of networking.
NAT is effectively your router doing DHCP with a 17-bit suffix (16-bit port + 1 bit for UDP vs TCP) to each of your applications and then not telling you the address it gave you or how long it is good for (which is what a regular DHCP lease does). This is in addition to it, most likely, already doing regular DHCP and allocating you a IP address that it does tell you about, but which is basically worthless since routing to just that prefix without the hidden suffix goes into a black hole.
If you could just ask your router for a lease on a chunk of IP+NAT addresses that you could allocate to your applications and rotate them as they expire, you would not need this horrifying mess.
The router would just need to maintain the last-leg routing table (what a concept, a router doing routing with routing tables) just like it already does DHCP.
The applications would have short-term stable addresses that they could just tell their peers and just directly tell the router/firewall to block anybody except the desired peer short-term address.
Does TCP hole punching actually work with common CPEs and CG-NATs?
I don’t think I’ve ever seen it done successfully and have often wondered if it’s for a lack of use cases or due to its bad success rate and complexity compared to UDP hole punching.
That said, I really wish there was a standardized way to do it. Some sort of explicit (or at least implicit but unambiguous) indicator to all firewalls that a connection from a given host/port pair is desired for the next few seconds. Basically a lightweight, in-band port mapping protocol.
It could have well been an official recommendation to facilitate TCP hole punching, but I guess it’s too late now, as firewall behaviors have had decades to evolve into different directions.
Meh. "It is assumed another process will coordinate the running of this tool." Coordination is the crux of the problem for fast convergence. Otherwise you're stuck with an infinity cubed, hypercubed, or worse problem.
The timestamp bucket idea for generating shared port candidates is clever.
Do you find this works reliably outside routers that preserve source ports? My understanding was that TCP punching tends to depend heavily on NAT behavior.
I don’t think the bucket-choosing algorithm works? The two hosts can be just on opposite sides of a bucket edge. For example if one host sees t=61 and another sees t=62, they will get different buckets despite being less than 20 seconds apart. You’ve got to check adjacent buckets within your error tolerance, not expand the bucket windows in size based on it.
Can't both sides just keep trying different ports until they get lucky? There's not that many of them, and even if it takes several minutes to get a match, that's better than nothing at all.
My internet provider didn't even maintain the ip-address. They have a pool of egress routes and seems to route round-robin. Basically every new connection can be from any address in the pool.
I had to call them to make it stop since it tripped the VPN solution at work, that interpreted it as a MIM attack. They disabled it no questions asked as soon as I called, so I guess it mostly works for most people, but not all.
But on that note, isn't it basically time now for IPv6 so we can stop shit like this and go to directly addressable devices like everyone did in the early 90s.
One thing about this get I just realized is that if the defect exists on some home networking equipment, then the defect can be leveraged in corporate network environments to disable this functionality. If the user of the algorithm (or, person using an app using it for userspace) isn't aware of the limitations, that would be super frustrating!
This perfectly eliminates the last centralized bottleneck for P2P agent networks.
We are dropping this deterministic punch directly into the grubcrawler.dev edge binaries. Instead of relying on STUN/TURN servers to coordinate a swarm, millions of nodes trapped behind residential NATs will use the unix timestamp to mathematically predict a collision course, aggressively punch through their firewalls, and instantly hand the raw TCP socket over to rust-lightning (LDK).
No DNS. No signaling servers. No legacy IP registries. Just a self-assembling Lightning mesh of autonomous agents spinning up encrypted channels and executing paid RPC calls entirely in the dark.
23 comments
[ 3.7 ms ] story [ 56.2 ms ] threadIt is precisely this point that has flummoxed me when connecting my p2p wireguard config[1] with a friend that uses a pfsense router, no matter what we tried, pfsense always chooses a random source port.
But in the simple case this blog outlines, if both ends use the same source port, this method punches through 2 firewalls effortlessly:
[1] https://blog.rymcg.tech/blog/linux/wireguard_p2p/
- can't decide on a port in the same message
- don't suffer from NAT port randomization
I'm not saying it will never happen, but the Venn diagram of this being the minimum complexity solution just doesn't seem very large?
The real problem is the port randomization if any client is behind a symmetric NAT. The search space for randomly trying port numbers is too large.
There are some ways to reduce the search space, like port prediction. But ultimately, a large dose of port scanning is the only way I know of to make the connection reliably. And there’s only so much of that you can do before triggering IPS or overwhelming the NAT.
IPv6 makes this way easier, of course!
In this era where AI is eating away at how deterministic computers are, I really appreciate reading about an elegant solution to a real problem using deterministic logic.
NAT is effectively your router doing DHCP with a 17-bit suffix (16-bit port + 1 bit for UDP vs TCP) to each of your applications and then not telling you the address it gave you or how long it is good for (which is what a regular DHCP lease does). This is in addition to it, most likely, already doing regular DHCP and allocating you a IP address that it does tell you about, but which is basically worthless since routing to just that prefix without the hidden suffix goes into a black hole.
If you could just ask your router for a lease on a chunk of IP+NAT addresses that you could allocate to your applications and rotate them as they expire, you would not need this horrifying mess.
The router would just need to maintain the last-leg routing table (what a concept, a router doing routing with routing tables) just like it already does DHCP.
The applications would have short-term stable addresses that they could just tell their peers and just directly tell the router/firewall to block anybody except the desired peer short-term address.
I don’t think I’ve ever seen it done successfully and have often wondered if it’s for a lack of use cases or due to its bad success rate and complexity compared to UDP hole punching.
That said, I really wish there was a standardized way to do it. Some sort of explicit (or at least implicit but unambiguous) indicator to all firewalls that a connection from a given host/port pair is desired for the next few seconds. Basically a lightweight, in-band port mapping protocol.
It could have well been an official recommendation to facilitate TCP hole punching, but I guess it’s too late now, as firewall behaviors have had decades to evolve into different directions.
Do you find this works reliably outside routers that preserve source ports? My understanding was that TCP punching tends to depend heavily on NAT behavior.
Hardly the case in even half of typical deployment cases.
I had to call them to make it stop since it tripped the VPN solution at work, that interpreted it as a MIM attack. They disabled it no questions asked as soon as I called, so I guess it mostly works for most people, but not all.
But on that note, isn't it basically time now for IPv6 so we can stop shit like this and go to directly addressable devices like everyone did in the early 90s.
We are dropping this deterministic punch directly into the grubcrawler.dev edge binaries. Instead of relying on STUN/TURN servers to coordinate a swarm, millions of nodes trapped behind residential NATs will use the unix timestamp to mathematically predict a collision course, aggressively punch through their firewalls, and instantly hand the raw TCP socket over to rust-lightning (LDK).
No DNS. No signaling servers. No legacy IP registries. Just a self-assembling Lightning mesh of autonomous agents spinning up encrypted channels and executing paid RPC calls entirely in the dark.