... | ... | @@ -27,11 +27,17 @@ The following chart shows which NATs are compatible with each other. Columns and |
|
|
|
|
|
## TURN Servers
|
|
|
|
|
|
Most WebRTC applications require matching a specific peer to a specific client (as is the case for a video call), and are left with no choice but to proxy the traffic between two incompatible peers through a centralized server. TURN ([RFC 5766](https://tools.ietf.org/html/rfc5766),[RFC 6062](https://tools.ietf.org/html/rfc6062)) is a common way to accomplish this.
|
|
|
|
|
|
However, using centralized TURN servers isn't ideal for our censorship-resistance use case of WebRTC. A single TURN server or even a small set of TURN servers can be easily targeted and blocked by a censor. Using existing public infrastructure or domain fronting to discourage blocking through collateral damage would be expensive, potentially damaging to other applications that rely on those servers, and generally doesn't scale the way we want Snowflake to be able to scale.
|
|
|
|
|
|
## NAT Matching
|
|
|
|
|
|
Fortunately, we don't have to match specific clients to specific proxies. We can match a client with any available proxy, meaning we can choose from the set of polling proxies one that has a NAT compatible with the client.
|
|
|
|
|
|
### Proxy assignment
|
|
|
|
|
|
Because we aren't worried about matching specific clients with specific proxies, we can have the broker sort proxies into buckets, according to which types of NATs they are compatible with. When a client polls, the broker picks a proxy out of a compatible bucket to give to the client.
|
|
|
The broker is responsible for sorting proxies into buckets, according to which types of NATs they are compatible with. When a client polls, the broker picks a proxy out of a compatible bucket to give to the client.
|
|
|
|
|
|
In practice, we don't need 9 buckets for each possible combination of mapping and filtering behaviour. We simplify this to 2 buckets:
|
|
|
- **unrestricted**: proxies in this bucket will work with all clients, even those with the most restrictive symmetric NATs and filtering behaviour. Only (AI,AI) and (AI,AO) proxies belong in this bucket.
|
... | ... | @@ -43,6 +49,6 @@ We determine the NAT behaviour of clients by using the tricks in [RFC 5780](http |
|
|
|
|
|
However, this method does not work for web-based proxies such as those run with the badge or Snowflake webextension. The Mozilla and Chrome WebRTC APIs do not expose the ability to perform the STUN tests in RFC 5780, nor do these browser allow arbitrary UDP connections to be made by javascript (and for good reason). This presented a problem considering the bast majority of our proxies are web-based.
|
|
|
|
|
|
To solve this, we set up a probe service that allows proxies to test their NAT compatability by attempting to connect to symmetrically NAT'd WebRTC peer. If it is able to successfully open a datachannel with this peer, we classify it as an unrestricted proxy. If the proxy times out without opening the datachannel, we sort it into the restricted bucket.
|
|
|
To solve this, we set up a probe service that allows proxies to test their NAT compatibility by attempting to connect to symmetrically NAT'd WebRTC peer. If it is able to successfully open a datachannel with this peer, we classify it as an unrestricted proxy. If the proxy times out without opening the datachannel, we sort it into the restricted bucket.
|
|
|
|
|
|
[^1]: there is an edge case here where clients with port-dependent filtering behaviour (AI,PD) won't work with symmetrically mapped proxies, i.e. proxies with (AO,X) or (AP,X) behaviours. However, symmetric mapping is relatively rare. At the time of writing this post, (AI,PD) clients work with over 80% of restricted proxies. |
|
|
\ No newline at end of file |