commit 5cd2a226aae41a9fe834f19dee15a851b115e7bb Author: Arlo Breault arlolra@gmail.com Date: Mon Dec 19 14:57:46 2016 -0800
Enable tls websockets on the server
* Code lifted from meek-server --- broker/broker.go | 2 +- server-webrtc/torrc | 2 +- server/server.go | 84 ++++++++++++++++++++++++++++++++++++++++++++++------- server/torrc | 8 +++++ 4 files changed, 84 insertions(+), 12 deletions(-)
diff --git a/broker/broker.go b/broker/broker.go index 0ba29dc..1673601 100644 --- a/broker/broker.go +++ b/broker/broker.go @@ -159,7 +159,7 @@ func clientOffers(ctx *BrokerContext, w http.ResponseWriter, r *http.Request) { return } // Otherwise, find the most available snowflake proxy, and pass the offer to it. - // Delete must be deferred in order to correctly process answer request later. + // Delete must be deferred in order to correctly process answer request later. snowflake := heap.Pop(ctx.snowflakes).(*Snowflake) defer delete(ctx.idToSnowflake, snowflake.id) snowflake.offerChannel <- offer diff --git a/server-webrtc/torrc b/server-webrtc/torrc index 44b5964..e037c97 100644 --- a/server-webrtc/torrc +++ b/server-webrtc/torrc @@ -5,4 +5,4 @@ SocksPort 0 ExitPolicy reject *:* DataDirectory datadir
-ServerTransportPlugin snowflake exec ./server +ServerTransportPlugin snowflake exec ./server-webrtc diff --git a/server/server.go b/server/server.go index fc41364..672c79e 100644 --- a/server/server.go +++ b/server/server.go @@ -8,6 +8,7 @@ package main
import ( + "crypto/tls" "encoding/base64" "errors" "flag" @@ -41,13 +42,12 @@ var ptInfo pt.ServerInfo var handlerChan = make(chan int)
func usage() { - fmt.Printf("Usage: %s [OPTIONS]\n", os.Args[0]) + fmt.Printf("Usage: %s [OPTIONS]\n\n", os.Args[0]) fmt.Printf("WebSocket server pluggable transport for Tor.\n") fmt.Printf("Works only as a managed proxy.\n") fmt.Printf("\n") - fmt.Printf(" -h, --help show this help.\n") - fmt.Printf(" --log FILE log messages to FILE (default stderr).\n") - fmt.Printf(" --port PORT listen on PORT (overrides Tor's requested port).\n") + fmt.Printf(" -h, -help show this help.\n") + flag.PrintDefaults() }
// An abstraction that makes an underlying WebSocket connection look like an @@ -181,11 +181,56 @@ func webSocketHandler(ws *websocket.WebSocket) { proxy(or, &conn) }
-func startListener(addr *net.TCPAddr) (*net.TCPListener, error) { - ln, err := net.ListenTCP("tcp", addr) +func listenTLS(network string, addr *net.TCPAddr, certFilename, keyFilename string) (net.Listener, error) { + // This is cribbed from the source of net/http.Server.ListenAndServeTLS. + // We have to separate the Listen and Serve parts because we need to + // report the listening address before entering Serve (which is an + // infinite loop). + // https://groups.google.com/d/msg/Golang-nuts/3F1VRCCENp8/3hcayZiwYM8J + config := &tls.Config{} + config.NextProtos = []string{"http/1.1"} + + var err error + config.Certificates = make([]tls.Certificate, 1) + config.Certificates[0], err = tls.LoadX509KeyPair(certFilename, keyFilename) + if err != nil { + return nil, err + } + + conn, err := net.ListenTCP(network, addr) + if err != nil { + return nil, err + } + + // Additionally disable SSLv3 because of the POODLE attack. + // http://googleonlinesecurity.blogspot.com/2014/10/this-poodle-bites-exploitin... + // https://code.google.com/p/go/source/detail?r=ad9e191a51946e43f1abac8b6a2fefb... + config.MinVersion = tls.VersionTLS10 + + tlsListener := tls.NewListener(conn, config) + + return tlsListener, nil +} + +func startListener(network string, addr *net.TCPAddr) (net.Listener, error) { + ln, err := net.ListenTCP(network, addr) if err != nil { return nil, err } + log.Printf("listening with plain HTTP on %s", ln.Addr()) + return startServer(ln) +} + +func startListenerTLS(network string, addr *net.TCPAddr, certFilename, keyFilename string) (net.Listener, error) { + ln, err := listenTLS(network, addr, certFilename, keyFilename) + if err != nil { + return nil, err + } + log.Printf("listening with HTTPS on %s", ln.Addr()) + return startServer(ln) +} + +func startServer(ln net.Listener) (net.Listener, error) { go func() { defer ln.Close() var config websocket.Config @@ -195,7 +240,7 @@ func startListener(addr *net.TCPAddr) (*net.TCPListener, error) { Handler: config.Handler(webSocketHandler), ReadTimeout: requestTimeout, } - err = s.Serve(ln) + err := s.Serve(ln) if err != nil { log.Printf("http.Serve: " + err.Error()) } @@ -204,10 +249,15 @@ func startListener(addr *net.TCPAddr) (*net.TCPListener, error) { }
func main() { + var disableTLS bool + var certFilename, keyFilename string var logFilename string var port int
flag.Usage = usage + flag.BoolVar(&disableTLS, "disable-tls", false, "don't use HTTPS") + flag.StringVar(&certFilename, "cert", "", "TLS certificate file (required without --disable-tls)") + flag.StringVar(&keyFilename, "key", "", "TLS private key file (required without --disable-tls)") flag.StringVar(&logFilename, "log", "", "log file to write to") flag.IntVar(&port, "port", 0, "port to listen on if unspecified by Tor") flag.Parse() @@ -221,6 +271,16 @@ func main() { log.SetOutput(f) }
+ if disableTLS { + if certFilename != "" || keyFilename != "" { + log.Fatalf("The --cert and --key options are not allowed with --disable-tls.\n") + } + } else { + if certFilename == "" || keyFilename == "" { + log.Fatalf("The --cert and --key options are required.\n") + } + } + log.SetFlags(log.LstdFlags | log.LUTC) log.Printf("starting") var err error @@ -230,7 +290,7 @@ func main() { os.Exit(1) }
- listeners := make([]*net.TCPListener, 0) + listeners := make([]net.Listener, 0) for _, bindaddr := range ptInfo.Bindaddrs { // Override tor's requested port (which is 0 if this transport // has not been run before) with the one requested by the --port @@ -241,13 +301,17 @@ func main() {
switch bindaddr.MethodName { case ptMethodName: - ln, err := startListener(bindaddr.Addr) + var ln net.Listener + if disableTLS { + ln, err = startListener("tcp", bindaddr.Addr) + } else { + ln, err = startListenerTLS("tcp", bindaddr.Addr, certFilename, keyFilename) + } if err != nil { pt.SmethodError(bindaddr.MethodName, err.Error()) break } pt.Smethod(bindaddr.MethodName, ln.Addr()) - log.Printf("listening on %s", ln.Addr().String()) listeners = append(listeners, ln) default: pt.SmethodError(bindaddr.MethodName, "no such method") diff --git a/server/torrc b/server/torrc new file mode 100644 index 0000000..5cb891d --- /dev/null +++ b/server/torrc @@ -0,0 +1,8 @@ +BridgeRelay 1 +ORPort 9001 +ExtORPort auto +SocksPort 0 +ExitPolicy reject *:* +DataDirectory datadir + +ServerTransportPlugin snowflake exec ./server --disable-tls --log snowflake.log --port 9902
tor-commits@lists.torproject.org