hellais suggested WebRTC (http://www.webrtc.org/, https://en.wikipedia.org/wiki/WebRTC) as a way to directly connect browsers behind NATs. This could be useful for the JavaScript flash proxy, which otherwise doesn't work at all when the censored user is behind NAT.
We should examine WebRTC to find out at least
How much information it discloses to a third party. (For facilitation of NAT punching, for example. This was a problem with the Adobe RTMFP transport in the Flash-based proxy.)
How common it is or can be expected to become; i.e., will a censor be reluctant to block it wholesale.
What are the implications for protocol fingerprinting.
We will probably have to add some metadata to client registrations to indicate what kind of connections the client supports. Registrations currently look like this:
client=1.2.3.4:9000
We can augment them so:
client=1.2.3.4:9000&transports=websocket,webrtc
Maybe that doesn't make sense, as webrtc needs its own port number, or something. Perhaps something like
client-1.2.3.4:9000&client-webrtc=1.2.3.4:10000
Where client is implictly client-websocket.
Flash proxies would also advise the facilitator of the types of connection they can serve. So a Chrome browser arrives supporting websocket and webrtc, and the facilitator is free to give it a client that supports either of those two.
I think we want to use reliable (TCP) "RTCDataChannels"; their API is extremely similar to WebSockets. The support for this part of the WebRTC spec is still very new; most people are using the audio/video UDP APIs instead.
Chrome only supports RTCDataChannels using RDP (which is UDP plus headers) at the moment. Firefox does support reliable RTCDataChannels in Firefox Nightly, behind a flag. Firefox and Chrome RTCDataChannels aren't interoperable, but that's okay for us because the Flashproxy design never has one browser's socket talking to another browser's socket.
So I think the short answer is that we could start implementing in Firefox now, with the expectation that one day the same code will work in Chrome.
Some more information, paraphrasing from what cjb told me.
WebRTC supported only unreliable media (audio/video) channels until recently. RTCDataChannel is in Chrome 26 and Firefox 18. The two browsers don't yet interoperate out of the box. This demo connection, http://www.webrtc.org/demo, requires setting the media.peerconnection.enabled pref. Chrome's RTCDataChannel is unreliable, while Firefox has a reliable one.
http://peerjs.com/ looks interesting, and comes with an open-source server component to broker connections. (It doesn't help with the problems of Chrome not having implemented reliable transfers or binary data types, though.)
I chatted with a friend who is a Google WebRTC developer (Ben Schwartz), and he had some good ideas and pointed out some problems that I hadn't thought of.
The largest problem is how the client transport plugin is going to work, because there's not yet any headless WebRTC implementation; it's very attached to the DOM. I'd been assuming that node.js will grow a library that speaks WebRTC across each of Firefox/Chrome/node with a common API -- socket.io does this for websockets -- but the requirements for WebRTC are far greater. Ideally you need a full libjingle port, and at the least you need ICE and SCTP. Node currently doesn't have any SCTP support, as far as I can see.
So our options include waiting for node to grow a lot of code that doesn't exist right now, or having the client transport plugin be written in C instead of node and linked with libjingle, or finding a way to avoid having a full client transport plugin.
Ben's suggestion for avoiding a client transport plugin is that the plugin could be a SOCKS-style proxy that bounces the data back into the local browser through a websocket on the local machine, and some JavaScript in the browser handles brokering between the websocket and an outgoing WebRTC datachannel.
Current status of the browser-side code is that peerjs.com looks like the right thing for a common API, but it only supports Chrome rather than Firefox, and only Firefox has support for reliable transfers in datachannels. So we're either waiting for Chrome to support reliable transfers, or PeerJS to support Firefox.
The largest problem is how the client transport plugin is going to work, because there's not yet any headless WebRTC implementation; it's very attached to the DOM. I'd been assuming that node.js will grow a library that speaks WebRTC across each of Firefox/Chrome/node with a common API -- socket.io does this for websockets -- but the requirements for WebRTC are far greater. Ideally you need a full libjingle port, and at the least you need ICE and SCTP. Node currently doesn't have any SCTP support, as far as I can see.
So our options include waiting for node to grow a lot of code that doesn't exist right now, or having the client transport plugin be written in C instead of node and linked with libjingle, or finding a way to avoid having a full client transport plugin.
WebRTC is more complicated than I thought. All the things you mention are doable, but it sounds like a big development effort.
I'd rather not have new code written in C. Even if we have to link with C libraries, we should find a way to do it in a safer language.
Ben's suggestion for avoiding a client transport plugin is that the plugin could be a SOCKS-style proxy that bounces the data back into the local browser through a websocket on the local machine, and some JavaScript in the browser handles brokering between the websocket and an outgoing WebRTC datachannel.
This works, but only as a prototype. I don't want to deploy the "browser-as-transport" because it's confusing and leads to mistakes. From the user's point of view, you launch your TBB, that's fine, but then for some reason you also have to have another browser open, that is not a TBB, and then you have to remember to do your anonymous browsing in one and not the other.
We did something like the above a long time ago when we still used Flash, in order to use the Adobe RTMFP transport, which has uses similar to those of WebRTC. Our implementation let you register either an IP address or an RTMFP address, and then the proxy code used either a TCP socket or a socket abstraction over RTMFP. I didn't like it for the reasons above, plus the fact that it required running proprietary code on the client. (Plus the fact that the code was the same program as the flash proxy code, just with a different query string, which was way confusing. Try explaining that to anyone: "No, the flash proxy runs outside the firewall, where it can reach the Tor relay. Well, technically it also runs inside the firewall, but that's only for the sake of code reuse.")
I'm fine if we have an implementation of WebRTC that only does the things we need. I realize though, that this may still be most of the hard parts. Perhaps an implementation could be pulled out of a browser too.
Suppose we used the unreliable transport as if it were reliable. What could go wrong? If a packet gets dropped or duplicated, it will get noticed by the integrity checks in lower-level crypto. It seems the worst is that some of your circuits would get killed, if you're dropping packets.