build-trust / ockam

Orchestrate end-to-end encryption, cryptographic identities, mutual authentication, and authorization policies between distributed applications – at massive scale.
https://ockam.io
Apache License 2.0
4.46k stars 560 forks source link

UDP NAT Puncturing #3507

Open mrinalwadhwa opened 2 years ago

mrinalwadhwa commented 2 years ago

Background

https://www.youtube.com/watch?v=01ajHxPLxAw https://en.wikipedia.org/wiki/UDP_hole_punching

A naive implementation of UDP NAT puncturing looks like this

sequenceDiagram
    participant A
    participant S as Rendezvous Service (S)
    participant B

    autonumber
    A ->> S: send a udp message
    B ->> S: send a udp message
    S ->> A: internet visible udp address of B
    S ->> B: internet visible udp address of A
    B ->> A: B can send messages to A
    A ->> B: A can send messages to B

Wikipedia has a good description of this flow:

Let A and B be the two hosts, each in its own private network; NA and NB are the two NAT devices with globally reachable IP addresses EIPA and EIPB respectively; S is a public server with a well-known, globally reachable IP address.

- A and B each begin a UDP conversation with S; the NAT devices NA and NB create UDP translation states and assign temporary external port numbers EPA and EPB.
- S examines the UDP packets to get the source port used by NA and NB (the external NAT ports EPA and EPB).
- S passes EIPA:EPA to B and EIPB:EPB to A.
- A sends a packet to EIPB:EPB.
- NA examines A's packet and creates the following in its translation table: (Source-IP-A, EPA, EIPB, EPB).
- B sends a packet to EIPA:EPA.
- NB examines B's packet and creates the following tuple in its translation table: (Source-IP-B, EPB, EIPA, EPA).
- Depending on the state of NA's translation table when B's first packet arrives (i.e. whether the tuple (Source-IP-A, EPA, EIPB, EPB) has been created by the time of arrival of B's first packet), B's first packet is dropped (no entry in translation table) or passed (entry in translation table has been made).
- Depending on the state of NB's translation table when A's first packet arrives (i.e. whether the tuple (Source-IP-B, EPB, EIPA, EPA) has been created by the time of arrival of A's first packet), A's first packet is dropped (no entry in translation table) or passed (entry in translation table has been made).
- At worst, the second packet from A reaches B; at worst the second packet from B reaches A. Holes have been "punched" in the NAT and both hosts can directly communicate.

Let's start with a prototype of this basic protocol.

Integrating with Ockam

This basic prototype will help us explore how this should integrate with Ockam.

The UX of using UDP puncturing would be similar to using Forwarders today. We likely would also failover from NAT puncturing to forwarders if NAT puncturing doesn't succeed in establishing communication.

Forwarders (click to expand) ```bash # Forwarders enable an ockam node to register a forwarding address on another node. # Any message that arrives at this forwarding address is immediately dispatched # to the node that registered the forwarding address. # Create two nodes blue and green $ ockam node create blue $ ockam node create green # Create a forwarder to node n2 at node n1 $ ockam forwarder create blue --at /node/green --to /node/blue /service/forward_to_blue # Send a message to the uppercase service on blue via its forwarder on green $ ockam message send hello --to /node/green/service/forward_to_blue/service/uppercase # This can be very useful in establishing communication between applications # that cannot otherwise reach each other over the network. # For instance, we can use forwarders to create an end-to-end secure channel between # two nodes that are behind private NATs # Create another node called yellow $ ockam node create yellow # Create an end-to-end secure channel between yellow and blue. # This secure channel is created trough blue's forwarder at green and we can # send end-to-end encrypted messages through it. $ ockam secure-channel create --from /node/yellow --to /node/green/service/forward_to_blue/service/api \ | ockam message send hello --from /node/yellow --to -/service/uppercase # In this topology green acts an an encrypted relay between yellow and blue. Yellow and # blue can be running in completely separate private networks. Green needs to be reachable # from both yellow and blue and only sees encrypted traffic. ```

We love helping new contributors! If you have questions or need help as you work on your first Ockam contribution, please leave a comment on this discussion. If you're looking for other issues to contribute to, checkout this discussion and labels - https://github.com/build-trust/ockam/labels/good%20first%20issue or https://github.com/build-trust/ockam/labels/help%20wanted

Retamogordo commented 2 years ago

It would nice to explore this issue. I think there are a couple of corner cases as for this kind of protocol implementation. And I would to ask, for example: Do you think that the destination peer must be aware that it is reached by relayed tunneling ? And does it mean that any ockam peer implements the rendevouz relay or it must be a mesh of dedicated peers ? And just out of curiosity: how ockam could be related to libp2p protocol set ? They have network of p2p nodes that feature bootstrapping, peer and content routing over encryped channels, identification on top many transports. They use Kademlia-like DHT as cornerstone of their network topology. Ipfs is built on top of libp2p. So it looks like ockam is something similar as for functionality. What is the story of ockam in this rush after new Internet ?

mrinalwadhwa commented 2 years ago

It would nice to explore this issue. I think there are a couple of corner cases as for this kind of protocol implementation.

Thank you for spending time on this!

Do you think that the destination peer must be aware that it is reached by relayed tunneling?

Can't think of any reason why it must

And does it mean that any ockam peer implements the rendevouz relay or it must be a mesh of dedicated peers ?

For our use cases, we're okay with central well known nodes offering relay, forwarding, rendezvous like services - as long as the data integrity and confidentiality guarantees are end-to-end.

how ockam could be related to libp2p

While there seem to be some similarities in the lowest level protocols. The use cases we're building for are vastly different.

mrinalwadhwa commented 2 years ago

The UX of using UDP puncturing would be similar to using Forwarders today. We likely would also failover from NAT puncturing to forwarders if NAT puncturing doesn't succeed in establishing communication.

# Forwarders enable an ockam node to register a forwarding address on another node.
# Any message that arrives at this forwarding address is immediately dispatched
# to the node that registered the forwarding address.

# Create two nodes blue and green
$ ockam node create blue
$ ockam node create green

# Create a forwarder to node blue at node green
$ ockam forwarder create blue --at /node/green --to /node/blue
/service/forward_to_blue

# Send a message to the uppercase service on blue via its forwarder on green
$ ockam message send hello --to /node/green/service/forward_to_blue/service/uppercase

# This can be very useful in establishing communication between applications
# that cannot otherwise reach each other over the network.

# For instance, we can use forwarders to create an end-to-end secure channel between
# two nodes that are behind private NATs

# Create another node called yellow
$ ockam node create yellow

# Create an end-to-end secure channel between yellow and blue.
# This secure channel is created trough blue's forwarder at green and we can
# send end-to-end encrypted messages through it.
$ ockam secure-channel create --from /node/yellow --to /node/green/service/forward_to_blue/service/api \
    | ockam message send hello --from /node/yellow --to -/service/uppercase

# In this topology green acts an an encrypted relay between yellow and blue. Yellow and
# blue can be running in completely separate private networks. Green needs to be reachable
# from both yellow and blue and only sees encrypted traffic.
mrinalwadhwa commented 2 years ago

The rust library experience, I suspect, would be somewhat similar to example 4 in this guide https://github.com/build-trust/ockam/tree/develop/documentation/use-cases/end-to-end-encrypt-all-application-layer-communication#04-end-to-end-encryption-over-two-tcp-connection-hops

neil2468 commented 1 year ago

@Retamogordo , @mrinalwadhwa : Is work ongoing with this? If it's not, I'd like to be assigned it and give it a go. Thanks!

mrinalwadhwa commented 1 year ago

@neil2468 Thank you! I don't think anyone is working so all yours. I suggest approaching the problem in small increments. Maybe as a start, prototype the protocol above https://github.com/build-trust/ockam/issues/3507#issue-1381362397

neil2468 commented 1 year ago

It seems ockam_transport_udp creates a new socket on a new UDP port for each outgoing message that's for a new peer. For this use case, that's problematic as we want the Redezvous Serivce and peer B to both see the same source port for messages from peer A.

@mrinalwadhwa: Would it be okay if I modify ockam_transport_udp to use the same UDP socket for all outgoing messages initiaited within the local node (i.e. for 'client' mode messages but not 'server' mode where the local node listens on a well know port)?

mrinalwadhwa commented 1 year ago

@neil2468 yes, I think that should be okay. Copying @etorreborre & @SanjoDeundiak just in case they have some more thoughts to add.