Re: Linux NATting does not support NAT hole punching?

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Le 11/07/2018 à 21:12, Christian Worm Mortensen a écrit :
> Hi Greg,
> 
>>> I have run two Chrome browsers each behind their own Linux NAT. I have
>>> then tried to instruct them to establish a P2P connection with each
>>> other using WebRTC. WebRTC is a standard framework that allows P2P
>>> communication between browsers and which is available from JavaScript.
>>>
>>> It turned out that the two browsers were not able to establish a P2P
>>> connection.

I Made a real test between two real systems:
- both at the same ISP (free.fr)
- one Ubuntu 14.04 system behind free.fr's "Revolution" box known to be
  running Linux (https://floss.freebox.fr/freebox_server/3.2.0/index.html, so
  apparently at least running Linux 4.2), in router/NAT mode.
- one Debian 9.5 system behind a Debian 9.5 router/NAT system running kernel
  4.16.x itself also behind a freebox, but in switch mode (so completely
  transparent).
- the Ubuntu system runs chromium-browser (65.0.3325.181-0ubuntu0.14.04.1)
- the Debian system runs chromium (67.0.3396.87-1~deb9u1)
- both systems have a RFC1918 type IP behind their router.
- both routers are doing standard MASQUERADE without any WebRTC related DNAT.
- both systems "rendez-vous" using WebRTC by using this demo site:
https://appr.tc/
  and choosing the same join number.

It just worked. both systems exchange UDP packets directly and display remote
peer's camera video. The UDP packets don't flow through appr.tc but between
the two router's public IPs (which de-SNAT them accordingly to their
internal system). appr.tc is mostly here as broker to synchronize the
direct establishment of the flows between the peers.

So it seems your testing didn't work because of an unknown factor, but not
because of Linux and you shouldn't conclude Linux NAT does not support NAT
hole punching.

What is very important: the router/NAT system should *drop* unknown outside
incoming packets (thus not generate TCP RST or ICMP unreachable errors). If it
doesn't drop packets before conntrack allow reverse-SNATing them because of the
internal outgoing flow, then the internal system will give up early and
attemps will fail.

It's easy to test UDP or TCP hole punching outside of any complex
application: by running socat on both sides and choosing the adequate source
and destination ports. Here's a full easily reproducible example using
network namespaces, to be run as root, using 5 network namespaces: one for each system, one for each router + one for "internet".

######################################

for i in s1 r1 in r2 s2; do ip netns del "$i" 2>/dev/null || : ; done

ip netns add s1
ip netns add r1
ip netns add in
ip netns add r2
ip netns add s2

ip -n s1 link add eth0 type veth peer name lan0 netns r1
ip -n r1 link add wan0 type veth peer name left0 netns in
ip -n in link add right0 type veth peer name wan0 netns r2
ip -n r2 link add lan0 type veth peer name eth0 netns s2

ip netns exec r1 iptables -P INPUT DROP
ip netns exec r1 iptables -P FORWARD DROP
ip netns exec r1 iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
ip netns exec r1 iptables -A FORWARD -i lan0 -j ACCEPT
ip netns exec r1 iptables -t nat -A POSTROUTING -o wan0 -j MASQUERADE

ip netns exec r2 iptables -P INPUT DROP
ip netns exec r2 iptables -P FORWARD DROP
ip netns exec r2 iptables -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
ip netns exec r2 iptables -A FORWARD -i lan0 -j ACCEPT
ip netns exec r2 iptables -t nat -A POSTROUTING -o wan0 -j MASQUERADE

ip -n s1 address add 192.0.2.2/24 dev eth0
ip -n r1 address add 192.0.2.1/24 dev lan0
ip -n r1 address add 198.51.100.11/24 dev wan0
ip -n in address add 198.51.100.1/24 dev left0
ip -n in address add 203.0.113.1/24 dev right0
ip -n r2 address add 203.0.113.12/24 dev wan0
ip -n r2 address add 192.0.2.1/24 dev lan0
ip -n s2 address add 192.0.2.2/24 dev eth0

ip -n in route add unreachable 192.0.2.0/24 # enforce routers' NAT

for i in s1 r1 in r2 s2; do ip -n "$i" link set lo up; done
ip -n s1 link set eth0 up
ip -n s1 route add default via 192.0.2.1
ip -n r1 link set lan0 up
ip -n r1 link set wan0 up
ip -n r1 route add default via 198.51.100.1
ip -n in link set left0 up
ip -n in link set right0 up
ip -n r2 link set wan0 up
ip -n r2 route add default via 203.0.113.1
ip -n r2 link set lan0 up
ip -n s2 link set eth0 up
ip -n s2 route add default via 192.0.2.1

######################################

The most important part in the setup above is probably '-P INPUT DROP'

To test (requires simultaneous use of two terminals, as root):

UDP:
######################################

#term1:
ip netns exec s1 socat udp4:203.0.113.12:2222,reuseaddr,sourceport=1111 -

#term2:
ip netns exec s2 socat udp4:198.51.100.11:1111,reuseaddr,sourceport=2222 -

######################################
Send a line on both side. After the first line will be lost, both system
will have established the same udp flow.


TCP:
Works exactly the same with tcp (by using a dual SYN/SYN initial handshake,
as per rfc793 3.4 figure 8: https://tools.ietf.org/html/rfc793#section-3.4
+ rfc1122 4.2.2.10 https://tools.ietf.org/html/rfc1122#page-87 )
######################################

#term1:
ip netns exec s1 socat tcp4:203.0.113.12:2222,reuseaddr,sourceport=1111 -

#term2:
ip netns exec s2 socat tcp4:198.51.100.11:1111,reuseaddr,sourceport=2222 -

######################################
(use ctrl-D not ctrl-C or a FIN_WAIT might appear).

You can observe what's happening on both sides of "internet" with:

#term3:
ip netns exec in tcpdump -n -s0 -p -i any ip

> Best,
> 
> Christian
> --

Regards,
Adel
--
To unsubscribe from this list: send the line "unsubscribe netfilter" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Linux Netfilter Development]     [Linux Kernel Networking Development]     [Netem]     [Berkeley Packet Filter]     [Linux Kernel Development]     [Advanced Routing & Traffice Control]     [Bugtraq]

  Powered by Linux