snowflake/server
David Fifield 19b317e781 Use ListenAndServe{TLS} rather than separate Listen and Serve.
This is a port of commit cea86c937dc278ba6b2100c238b1d5206bbae2f0 from
meek. Its purpose is to remove the need to copy-paste parts of
net/http.Server.ListenAndServeTLS. Here is a copy of the commit message
from meek:

    The net/http package provides ListenAndServe and ListenAndServeTLS
    functions, but it doesn't provide a way to set up a listener without
    also entering an infinite serve loop. This matters for
    ListenAndServeTLS, which sets up a lot of magic behind the scenes for
    TLS and HTTP/2 support. Formerly, we had copy-pasted code from
    ListenAndServeTLS, but that code has only gotten more complicated in
    upstream net/http.

    The price we pay for this is that it's no longer possible for a server
    bindaddr to ask to listen on port 0 (i.e., a random ephemeral port).
    That's because we never get a change to find out what the listening
    address is, before entering the serve loop.

    What we gain is HTTP/2 support; formerly our copy-pasted code had the
    side effect of disabling HTTP/2, because it was copied from an older
    version and did things like
            config.NextProtos = []string{"http/1.1"}

    The new code calls http2.ConfigureServer first, but that's not what's
    providing HTTP/2 support. HTTP/2 support happens by default. The reason
    we call http2.ConfigureServer is because we need to set
    TLSConfig.GetCertificate, and http2.ConfigureServer is a convenient way
    to initialize TLSConfig in a way that is guaranteed to work with HTTP/2.
2018-03-13 19:18:52 -07:00
..
README.md Use Manager.HTTPHandler for automatic TLS support in the server. 2018-03-05 21:16:51 -08:00
server.go Use ListenAndServe{TLS} rather than separate Listen and Serve. 2018-03-13 19:18:52 -07:00
server_test.go Rough tests for the clientAddr function. 2017-10-17 22:13:56 -07:00
stats.go Use %.f not %.g to format stats interval. 2017-10-20 12:26:44 -07:00
torrc README and documentation for server. 2017-01-21 14:53:51 -08:00

This is the server transport plugin for Snowflake. The actual transport protocol it uses is WebSocket. In Snowflake, the client connects to the proxy using WebRTC, and the proxy connects to the server (this program) using WebSocket.

Setup

The server needs to be able to listen on port 80 in order to generate its TLS certificates. On Linux, use the setcap program to enable the server to listen on port 80 without running as root:

setcap 'cap_net_bind_service=+ep' /usr/local/bin/snowflake-server

Here is a short example of configuring your torrc file to run the Snowflake server under Tor:

SocksPort 0
ORPort 9001
ExtORPort auto
BridgeRelay 1

ServerTransportListenAddr snowflake 0.0.0.0:443
ServerTransportPlugin snowflake exec ./server --acme-hostnames snowflake.example --acme-email admin@snowflake.example --log /var/log/tor/snowflake-server.log

The domain names given to the --acme-hostnames option should resolve to the IP address of the server. You can give more than one, separated by commas.

TLS

The server uses TLS WebSockets by default: wss:// not ws://. There is a --disable-tls option for testing purposes, but you should use TLS in production.

The server automatically fetches certificates from Let's Encrypt as needed. Use the --acme-hostnames option to tell the server what hostnames it may request certificates for. You can optionally provide a contact email address, using the --acme-email option, so that Let's Encrypt can inform you of any problems. The server will cache TLS certificate data in the directory pt_state/snowflake-certificate-cache inside the tor state directory.

In order to fetch certificates automatically, the server needs to listen on port 80, in addition to whatever ports it is listening on for WebSocket connections. This is a requirement of the ACME protocol used by Let's Encrypt. The program will exit if it can't bind to port 80. On Linux, you can use the setcap program, part of libcap2, to enable the server to bind to low-numbered ports without having to run as root:

setcap 'cap_net_bind_service=+ep' /usr/local/bin/snowflake-server