How is ICMP NAT traversal supposed to work if the NAT device in question rewrites outbound ICMP packets?
=========================================================================================
| CLIENT | <---> | NAT-C | <---> { internet } <---> | NAT-S | <---> | SERVER |
=========================================================================================
19.19.19.19 (external addresses) 72.72.72.72
192.168.0.2 192.168.0.1 (internal addresses) 172.16.0.1 172.16.0.2
A quick overview of ICMP holepunching as described in pwnat
:
SERVER
sends ICMP Echo Request packets (pings) to some other host (e.g. 3.3.3.3
) to open up a hole in NAT-S
. When CLIENT
wants to connect, it sends an ICMP Time Exceeded packet to NAT-S
, which is supposed to get routed to SERVER
. For said routing to work, CLIENT
constructs the ICMP Time Exceeded packet by embedding within it the same packet (ICMP Echo to 3.3.3.3
) it expects SERVER
to be sending in the first place.
If CLIENT
needs to embed the same (ICMP Echo Request) packet as it left NAT-S
in its ICMP Time Exceeded reply, it must know the packet's query ID. But how does it know this query ID?
According to RFC 3022 Section 2.2, when NAT-S
encounters the outbound ICMP Echo Request, it rewrites the packet's query ID field to a unique external query ID so that it can route future ICMP Echo Replies with the same query ID to SERVER
.
Given the problem above, it would seem that the premise behind pwnat
and ICMP holepunching is invalid and it's never supposed to work. Am I missing something here?
Thanks in advance :)
You're correct about the query ID.
pwnat
rarely works nowdays. I happened to know this icmp punching thing years ago, and interested in this idea. I had read the source code of pwnat and re-implemented it in Go by myself. Only basic NAT devices (rfc 1631 describes) which does simple address translation may work with it, any NAPT device which has robust NAPT implementation won't do.
Besides the identifier problem, (by the way, the source code of pwnat use 0 as the identifier of original request) pwnat didn't give the right checksum of original ip header which may lead to the NAT-S dropping the TTL exceeded message(if the packet can reach there).
More serious, according to rfc 5508,
when the NAT device receives the ICMP Error packet from the Private Realm, the NAT device uses the packet embedded within the ICMP Error message (i.e., the IP packet from the client to the server) to look up the NAT Session to which the embedded packet belongs. If the NAT device does not have an active mapping for the embedded packet, the NAT SHOULD silently drop the ICMP Error packet.
It means the ICMP Time Exceeded packet from the client wouldn't pass through the NAT-C. This paper does mention this scenario and recommends other solutions.