Closed SkyperTHC closed 1 year ago
I ran into this as well. The problem is that Wiretap uses gvisor's DNAT rules to intercept TCP connections. When two SYNs come in from the same source address and port it creates a conflict in the NAT table.
Aside from reimplementing NAT or a different transparent proxy solution, I think the proper way to do this is implementing Implicit Source Port Mapping (https://www.netfilter.org/documentation/HOWTO/NAT-HOWTO-6.html) in netstack. I raised an issue upstream: https://github.com/google/gvisor/issues/9030.
nmap is sending a second SYN with a new source port so no NAT conflict applies. Unfortunately if you try to scan more ports nmap will suffer the same problem.
Potential workarounds while a proper solution is developed:
It doesnt happen often - you made me fall off my chair. Well spotted. It's crazy that gvisor's DNAT has such an obvious bug.
The specs state that the same SRC-IP:SRC-PORT can be used to open different and multiple tcp connection. A TCP connection is identified by "SRC-IP + SRC-PORT + DST-IP + DST-PORT" and not just by SRC-IP and SRC-PORT.
It can be easily tested:
nc -p 4444 45.148.244.66 31337
nc -p 4444 45.148.244.66 31338
ss -antp
ESTAB 0 0 172.16.0.2:4444 45.148.244.66:31338 users:(("nc",pid=181,fd=3))
ESTAB 0 0 172.16.0.2:4444 45.148.244.66:31337 users:(("nc",pid=86,fd=3))
Et voila, two fully established TCP connection with SRC-IP, SRC-PORT and DST-IP identical...just DST-Port differs.
More here:
I hear Jon Postel laughing all the way from his grave...
The dnat-to-forwarder
branch fixes this problem by no longer relying on DNAT.
This problem does never show up if I'm using WG on both sides. It shows up when I'm using WT on the EXIT-NODE The bug is re-produceable (i tested 20x the same scenario and it showed up reliably).
I'm testing the current github from branch tcp-fix. I'm scanning for 2 ports on a single target only. Both ports are open on the target. Only the first one is found.
On the origin server (running wireguard)
Packets on origin server (wireguard):
Observe that the TCP SYN-ACK from port 22 is never send to the origin server. We only the the outgoing SYN.
Packet on Exit-Node to target (running wiretap):
The socket information on the exit node shows that the data is in the recv-q (44 bytes, "OpenSSH_..."):
The data stays in the RECV-Q for 5 seconds before the socket is closed.
The expected behaviour is for WT to:
My gut feeling is that WT misses that the TCP connection has been established successfully and then kills it after 5 seconds.
It is odd because it works when I'm using nmap instead of masscan:
The only difference that I can see is that nmap uses the Linux kernel (rather than raw TCP) and thus the SYN is re-send 2 times:
My gut says that WT somehow needs this 2nd SYN?