Open n8fr8 opened 1 year ago
Uh-oh. I dove into this a little bit, but this is not straightforward.
Snowflake uses WebRTC, to be exact, the Pion WebRTC library.
WebRTC itself relies heavily on other protocols. The ones important to us are ICE, STUN and TURN.
WebRTC encapsulates basically all of the connectivity details, so things like ports are not flying around in the Snowflake code.
AFAIU, it's not that straightforward as just getting one port number where a Snowflake Proxy listens on and open that.
The broker hands around WebRTC SDP (Session Description Protocol) packets and peers find each other using ICE, TURN and STUN.
We should consult with @cohosh, on what's actually possible. Can you chime in here straight away, @cohosh, or should I poke you via mail?
Hi @tladesignz! Just acknowledging that I've seen this and I should be able to take a look early next week.
AFAIU, it's not that straightforward as just getting one port number where a Snowflake Proxy listens on and open that.
This is correct. It's not one static port that the proxy is listening on. Similar to when a client makes any outgoing connection, the port used is determined when the socket is created. Every time a proxy connects to a new client, a different port may be used.
I'm not very familiar with android, and I don't know how this UPnP library would be integrated with Orbot/Snowflake. Would you run it as a separate process? If so, then the best way to approach this might be some kind of netstat-like tool that feeds opened ports into it? Modifying Snowflake to log out these ports or feed them through a channel of some sort would be a non-trivial amount of work and requires modifications to the pion libraries we're using.
@cohosh thanks for the response, and can understand if this is non-trivial. The idea was to add some more advanced UPnP negotiation in our Android codebase, that could help make our Android-based Snowflake Proxies more useful, i.e. not stuck behind a NAT'd home router firewall.
It is interesting thought that you say "when a proxy connects to a new client". I just have this old school mentality of a proxy behing a server socket that announces itself on a port, and then a client connects to it. Is that not happening in this case?
It is interesting thought that you say "when a proxy connects to a new client". I just have this old school mentality of a proxy behing a server socket that announces itself on a port, and then a client connects to it. Is that not happening in this case?
Yeah, in the peer-to-peer connection between the client and proxy, both the client and proxy are performing the same steps for each rendezvous:
The proxy only starts these steps after it has been matched and is attempting to establish a connection with the client. Another way to think about it is that both the snowflake "proxy" and the snowflake "client" are making outgoing connections like a traditional client would. This distinguishes it as a peer-to-peer connection rather than a client-server connection.
@cohosh, thank you for these detailed description, that is very enlightening!
So, is there actually a way to improve the "quality" of a proxy? Can you explain what exactly is the difference between the different qualities?
There are a few different things that could be meant by quality. The one most relevant to this discussion is the type of NAT the proxy is operating behind, which is what @n8fr8 proposed using UPnP to change.
Proxies in the case of Orbot are running on mobile devices and connected to WiFi, which means they are almost certainly behind a NAT and a firewall of some type. This is why the client and proxy need to use STUN to perform what's called NAT traversal. There is a lose notion of more or less restrictive NAT/firewall types, and not all peers will be compatible with all NAT types. See our wiki page on NAT matching for more information on how we match clients with proxies.
UPnP uses something different than STUN for NAT traversal, called the Internet Gateway Device (IGD) protocol, which dynamically asks the router to open a port for the peer so that it is not subject to the NAT/firewall rules that other connections are. So theoretically it could be used to make the NAT/firewall of the peer less restrictive. I'm a bit wary of the security implications of using UPnP, especially if ports at the router are not being closed properly when they are no longer needed.
We have determined that we can first use UPNP to ask the firewall to map a series of ports to our device, then supply the range of ports to Snowflake to use.
We will consider more the security implications of this, once we figure out if it actually works or helps at all.
@cohosh, thank you very much for your explanations! The linked wiki page was especially helpful.
I want to use UPNP to open a temporarily firewall port when someone runs a Snowflake Proxy on Android.
I will be using this library: https://github.com/adolfintel/WaifUPnP
I need to know the port that the proxy is listening on so that I can do that!
Thanks!