Skip to content

QuantumGate Relays

Karel Donk edited this page Oct 29, 2021 · 24 revisions

QuantumGate supports relayed connections between instances (nodes or peers) on the network. Relayed connections offer advantages and disadvantages. Some of the advantages of relayed connections are increased privacy and the possibility to evade restrictions (such as censorship and traffic analysis/shaping). A disadvantage is the decrease in efficiency, having to do with more bandwidth and processing overhead.

A relayed connection uses the exact same communications protocol as a normal connection. All the data being sent and received is simply encapsulated and tunneled through another connection. Basically the Message Transport data that would normally be sent over the wire becomes the data in a Message which gets added to another Message Transport, comparable in concept to a Russian Matryoshka doll.

When building your own applications using the QuantumGate library and API, you can choose to enable or disable the relay functionality via the Startup Parameters and member functions of the Local instance. The relay functionality is disabled by default.

Relayed connections to other peers can be made over a variable number of hops, starting with just a single hop.

Single hop relay

While a single hop relay doesn't offer advantages in terms of privacy and anonymity, it does offer some benefits among which a doubling of the amount of encryption being used and altering the signature of the traffic.

A single hop relay starts off with a normal connection from peer A to peer B, through which a second relayed connection is made. By using the relayed connection and tunneling through the first normal connection, you get the benefit of double the amount of encryption being used.

Multiple hop relay

Relays with multiple hops offer more possibilities for privacy and anonymity. A multi-hop relay between peer A and peer C might start with A establishing a normal connection to peer B, and then asking B to connect to C, after which A can connect directly to C through B.

It's also possible for relays to be established through other relayed connections. If we take the above relayed connection from A to C, and peer D joins the network, and wants to connect to C through a relayed connection of 2 hops, it can connect to A first and then ask A to connect to C. But since A already has a relayed connection to C, instead of making a normal connection to C it allows D to connect to C through its relayed connection. From the perspective of D, it connected to C through A over 2 hops, not knowing there's another relayed connection in between adding an additional hop (through B).

Choice of peers

When a QuantumGate instance receives an incoming request to establish a relayed connection on behalf of a peer, it randomly selects another peer that is connected to the local instance and forwards the request to that peer. Because of this, the local instance should have other connections to randomly select from (and depending on the configuration from different IP networks), otherwise it will inform the requesting peer that it can't establish a connection to the requested destination endpoint. This also means that all the peers participating in a relayed connection should have at least one other connection (but preferably multiple connections) to choose from to keep forwarding the request for the requested number of hops until the destination has been reached.

When a QuantumGate instance randomly selects a peer to establish a relayed connection, it tries to make sure that the chosen peer is:

  • Not on the same IP network as the local instance
  • Not on the same IP network as the requesting peer (the previous hop)
  • Not on the same IP network as the final destination endpoint

The tolerance for how close the IP network of the chosen peer may be can be configured through the StartupParameters with the IPv4ExcludedNetworksCIDRLeadingBits and IPv6ExcludedNetworksCIDRLeadingBits members.

For example, let's say IPv4ExcludedNetworksCIDRLeadingBits is set to 16. If a peer B (IP 201.1.157.11) receives a request from peer A (IP 66.171.45.90) to connect to destination IP 180.30.30.20 via one additional hop, then B will make sure that the peer it chooses for the additional hop won't be on the networks 201.1.157.11/16 or 180.30.30.20/16 or 66.171.45.90/16. If B finds no local connections that are not on those networks, it will inform A that it cannot establish a relayed connection to the requested destination.

Relay Ports

On the QuantumGate network relayed connections are distinguished based on their Relay Ports, which is a 64-bit integer. You can see this as similar to the TCP and UDP port number, which is a 16-bit integer. Every time when a peer wants to establish a relayed connection, it first randomly picks a unique 64-bit number to serve as the Relay Port. This number gets sent along with the final destination IP address to another peer to request the connection to be established. The number is forwarded along with the request on all hops to other peers until the destination is reached.

Because peers can serve multiple relayed connections over the same normal connection between each other (multiplexing), they can use the Relay Port number to distinguish between relayed connections and route messages accordingly. The advantage of serving multiple relayed connections over a single normal connection is that it becomes more difficult to perform traffic analysis and to determine the real source and destination of the transmitted data, especially when multiple hops are involved.

The source and destination endpoints of a relayed connection are displayed in the following format: [IP Address]:[TCP/UDP Port Number]:[Relay Port Number], e.g. 192.168.1.10:999:748383123929.

Example 1

To give you an idea of how a relayed connection is established here's an example.

Peer Action
A Wants to connect to peer D via a 3 hop relay. It looks to see if it's connected to any peers and if so randomly selects one of the connections. If there are no existing connections, it will first have to connect to another peer and then select it. We'll refer to the selected peer as B. When the normal connection to B is established, it sends a request to B to establish a relayed connection to D over an additional 2 hops.
B Receives the request from A and then looks if it has any other peers it can ask to participate in the relay. If there are no other connections to B that can be used, it tells A that it's unable to reach the final destination. However, it just so happens that B had 5 other active connections to choose from and it randomly picks one which happens to be C. It sends a request to C to establish a relayed connection to D over an additional 1 hop.
C Receives the request from B, and since it notices that this is the final hop, it establishes a connection directly to D. If C was coincidentally already connected to D, that connection is used. It then sends D a request to establish a relayed connection.
D Receives the request from C, and if its local configuration allows it, tells C that it accepts the request.
C Tells B that the request was accepted.
B Tells A that the request was accepted.
A Begins the handshake with D.
B, C From now on forward the data being sent between A and D for this specific relayed connection until the connection closes or breaks.
A, D Once the handshake is complete, communication between A and D is encrypted with their session keys. The communication is additionally also encrypted with session keys between A and B, and session keys between B and C, as well as session keys between C and D. And if A and D have authenticated each other, it's guaranteed that B and C don't know what they're communicating because they don't have access to the session keys between A and D.
A, B, C, D Meanwhile, A and B, B and C, and C and D, also handle other communications between themselves and there may even be other relayed connections established through them simultaneously for other peers over the same existing connections (see below).

A few things to note:

  • Note that although B knows that A asked to connect to D, B can't be sure if A is requesting for itself, or if A is forwarding a request from another peer and is itself participating as a peer somewhere in the middle of the relay. Remember that A asked B to establish a relayed connection to D over 2 additional hops. So there may be more hops before these.
  • C only knows that B asked to establish a relay to D, and doesn't know where the request originated from. For all C knows, B could be asking for itself.
  • D only knows that C is requesting to establish a relayed connection. It doesn't know if C is asking for itself (because a single hop relay is possible), or for another peer (A in this case). D only sees the IP address of C. It's only if, and until, A authenticates itself to D, that D will know the UUID of A (but not its IP address) and know that it's communicating with A. If A doesn't authenticate itself and D is fine with that, D never knows who it's actually talking to; it just knows that it is talking to that peer through C.
  • It's difficult for someone listening in on the traffic between two peers to know if all that traffic is just between those two peers, or if they are also forwarding some or most of it to other destinations. In addition, when noise is enabled on any of these connections, it becomes even more difficult and confusing to understand the traffic.

As mentioned above, the peers A, B, C and D are able to handle additional relayed connections over the same existing connections. If we take the situation discussed above, we can add peers E and F, where:

  • Peer E is connected to peer D via a 3 hop relay through peers B and C.
  • Peer F is connected to peer B via a 2 hop relay through peer C.

Note that the normal connection between peers B and C is servicing 3 relayed connections simultaneously, while the normal connection between peers C and D is servicing 2 relayed connections simultaneously. And this is in addition to any private communications between peers B and C and between peers C and D.

Example 2

In the first example above you'll note that the peers B and C both know the final destination (D) of the relay connection that A is trying to establish. But what if we don't want all the peers in between to know the final destination, and only know the address of the peer they are directly communicating with? That's also possible with QuantumGate, and is similar to the "incremental or telescoping path-building" in TOR.

Here is how that works:

Peer Action
A Wants to connect to peer E via a 4 hop relay. It looks to see if it's connected to any peers and if so randomly selects one of the connections. If there are no existing connections, it will first have to connect to another peer and then select it. We'll refer to the selected peer as B. When the normal connection to B is established, it sends a request to B to establish a relayed connection to C over an additional hop.
B Receives the request from A and establishes a connection directly to C. If B was coincidentally already connected to C, that connection is used. It then sends C a request to establish a relayed connection.
C Receives the request from B, and if its local configuration allows it, tells B that it accepts the request.
B Tells A that the request was accepted.
A Begins the handshake with C and establishes the first relayed connection (yellow) to C. After the handshake is completed, A sends a request to C to establish a relayed connection to D over an additional hop.
C Receives the request from A and establishes a connection directly to D. If C was coincidentally already connected to D, that connection is used. It then sends D a request to establish a relayed connection.
D Receives the request from C, and if its local configuration allows it, tells C that it accepts the request.
C Tells A that the request was accepted.
A Begins the handshake with D and establishes the second relayed connection (blue) to D. After the handshake is completed, A sends a request to D to establish a relayed connection to E over an additional hop.
D Receives the request from A and establishes a connection directly to E. If D was coincidentally already connected to E, that connection is used. It then sends E a request to establish a relayed connection.
E Receives the request from D, and if its local configuration allows it, tells D that it accepts the request.
D Tells A that the request was accepted.
A Begins the handshake with E and establishes the third relayed connection (red) to E.

A few things to note:

  • Note that in this case, B only knows that A is communicating with C and it doesn't know the final destination.
  • C also doesn't know the final destination, and only knows that A is communicating through B with D.
  • D only knows that A is communicating with E through C.
  • E only knows that it's communicating with A through D.
  • It can take a bit longer to establish the relay to the final destination because of the additional relayed connections being established in between. Each of those connections will have to go through a complete handshake.
  • The amount of processing required is a fair bit more compared to the first example above because:
    • A has to apply 4 levels of encryption (one for each connection) to data that it sends to E instead of just 2 in the first example. The 3 additional connections, apart from the final relay connection to E, add processing and data overhead which can add up depending on the settings used.
    • C has to apply 2 levels of encryption to data that it forwards from D to B, instead of just 1 in the first example.
    • D has to apply 2 levels of encryption to data that it forwards from E to C.

So while you gain some more privacy in this second example, you deal with some additional complexity and processing overhead which could cause additional latency. This is a trade-off you'll have to make depending on your situation.

Tutorials

Click on the following links for tutorials on how to create relayed connections using QuantumGate:

Clone this wiki locally