tailscale / tailscale

The easiest, most secure way to use WireGuard and 2FA.
https://tailscale.com
BSD 3-Clause "New" or "Revised" License
19.58k stars 1.54k forks source link

NAT PMP issue with RouterOS #13785

Open artxtech opened 1 month ago

artxtech commented 1 month ago

What is the issue?

Tailscale can't create NAT via NAT PMP on routerOS.

I can use 3rd tool to create NAT via NAT PMP w/o problem, but tailscale can't.

What I can read from RouterOS log:

unable to allocate port for mapping *:0 -> localip-machineIP:62519, timeout 7200s

It seems tailscale requests a remote port 0 via NAT PMP, which leads to failure.

when I do tailscale debug portmap, it shows the same error like above in routerOS.

tailscale debug portmap:

monitor: monitor: gateway and self IP changed: gw=192.168.8.1 self=192.168.8.196 gw=192.168.8.1; self=192.168.8.196 portmapper: [v1] Got PMP response; IP: WAN IP, epoch: 15133 Probe: {PCP:false PMP:true UPnP:false} no mapping serveDebugPortmap: context done: context deadline exceeded

*I have randomize port sets true in ACL, so the port is not regular 41613.

Steps to reproduce

No response

Are there any recent changes that introduced the issue?

No response

OS

No response

OS version

No response

Tailscale version

No response

Other software

No response

Bug report

BUG-59ecaf859575b783e638ee0919cd1db1f30ae5deaf18e5a870053c72723456a1-20241011125954Z-187694008b84c3e9

artxtech commented 1 month ago

i spend sometime researching and realize it is tailscale request external port as 0, a way to indicate it does care what external port NAT PMP assigns.

I do this with my asus router, it just assign the same private / local port as external.

I tested this with py-natpmp - https://github.com/jaraco/nat-pmp

python3 natpmp_client.py -u -l 1800 0 60010 PortMapResponse: version 0, opcode 129 (129), result 0, ssec 172158, private_port 60010, public port 60010, lifetime 1800

ASUS just goes ahead and assign it.

while RouterOS takes the "0" as is, ofc port 0 isnt going to work.

I don't know who should resolve this, it seems "request external port as 0, a way to indicate it does care what external port NAT PMP assigns." a wide use practice...

artxtech commented 1 month ago

i've checked this requesting ext. port 0 behavior has nth to do with random port setting in acl.

raggi commented 1 month ago

It seems this should be reported to routerOS.

https://datatracker.ietf.org/doc/html/rfc6886#section-3.3

If the client would prefer to have a high-numbered "anonymous" external port assigned, then it should set the Suggested External Port to zero, which indicates to the gateway that it should allocate a high-numbered port of its choosing. If the client would prefer instead to have the mapped external port be the same as its local internal port if possible (e.g., a web server listening on port 80 that would ideally like to have external port 80), then it should set the Suggested External Port to the desired value. However, the gateway is not obliged to assign the port suggested, and may choose not to, either for policy reasons (e.g., port 80 is reserved and clients may not request it) or because that port has already been assigned to some other client. Because of this, some product developers have questioned the value of having the Suggested External Port field at all. The reason is for failure recovery. Most low- cost home NAT gateways do not record temporary port mappings in persistent storage, so if the gateway crashes or is rebooted, all the mappings are lost. A renewal packet is formatted identically to an initial mapping request packet, except that for renewals the client sets the Suggested External Port field to the port the gateway actually assigned, rather than the port the client originally wanted.

artxtech commented 1 month ago

It seems this should be reported to routerOS.

https://datatracker.ietf.org/doc/html/rfc6886#section-3.3

If the client would prefer to have a high-numbered "anonymous" external port assigned, then it should set the Suggested External Port to zero, which indicates to the gateway that it should allocate a high-numbered port of its choosing. If the client would prefer instead to have the mapped external port be the same as its local internal port if possible (e.g., a web server listening on port 80 that would ideally like to have external port 80), then it should set the Suggested External Port to the desired value. However, the gateway is not obliged to assign the port suggested, and may choose not to, either for policy reasons (e.g., port 80 is reserved and clients may not request it) or because that port has already been assigned to some other client. Because of this, some product developers have questioned the value of having the Suggested External Port field at all. The reason is for failure recovery. Most low- cost home NAT gateways do not record temporary port mappings in persistent storage, so if the gateway crashes or is rebooted, all the mappings are lost. A renewal packet is formatted identically to an initial mapping request packet, except that for renewals the client sets the Suggested External Port field to the port the gateway actually assigned, rather than the port the client originally wanted.

I read this earlier, reported this to RouterOS.