[tor-commits] [meek/utls_2] Honor a ServerName in utls.Config if given.

dcf at torproject.org dcf at torproject.org
Thu Feb 7 01:45:37 UTC 2019


commit 553a0b6d63f36987e542460187957f49780740a7
Author: David Fifield <david at bamsoftware.com>
Date:   Wed Feb 6 16:58:23 2019 -0700

    Honor a ServerName in utls.Config if given.
---
 meek-client/utls.go      |  12 +++--
 meek-client/utls_test.go | 121 +++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 128 insertions(+), 5 deletions(-)

diff --git a/meek-client/utls.go b/meek-client/utls.go
index 1ea0cd0..6f3d594 100644
--- a/meek-client/utls.go
+++ b/meek-client/utls.go
@@ -94,12 +94,14 @@ func dialUTLS(network, addr string, cfg *utls.Config, clientHelloID *utls.Client
 	if err != nil {
 		return nil, err
 	}
-	serverName, _, err := net.SplitHostPort(addr)
-	if err != nil {
-		return nil, err
-	}
 	uconn := utls.UClient(conn, cfg, *clientHelloID)
-	uconn.SetSNI(serverName)
+	if cfg == nil || cfg.ServerName == "" {
+		serverName, _, err := net.SplitHostPort(addr)
+		if err != nil {
+			return nil, err
+		}
+		uconn.SetSNI(serverName)
+	}
 	err = uconn.Handshake()
 	if err != nil {
 		return nil, err
diff --git a/meek-client/utls_test.go b/meek-client/utls_test.go
index 8facb88..8607604 100644
--- a/meek-client/utls_test.go
+++ b/meek-client/utls_test.go
@@ -1,8 +1,14 @@
 package main
 
 import (
+	"bytes"
+	"io"
+	"net"
 	"net/http"
+	"net/url"
 	"testing"
+
+	utls "github.com/refraction-networking/utls"
 )
 
 func TestCopyPublicFieldsHTTPTransport(t *testing.T) {
@@ -39,3 +45,118 @@ func TestCopyPublicFieldsHTTPTransport(t *testing.T) {
 		t.Errorf("mismatch on MaxResponseHeaderBytes")
 	}
 }
+
+// Return a byte slice which is the ClientHello sent when rt does a RoundTrip.
+// Opens a temporary listener on an ephemeral port on localhost. The host you
+// provide can be an IP address like "127.0.0.1" or a name like "localhost", but
+// it has to resolve to localhost.
+func clientHelloResultingFromRoundTrip(t *testing.T, host string, rt *UTLSRoundTripper) ([]byte, error) {
+	ch := make(chan []byte, 1)
+
+	ln, err := net.Listen("tcp", "127.0.0.1:0")
+	if err != nil {
+		return nil, err
+	}
+	defer ln.Close()
+
+	go func() {
+		defer func() {
+			close(ch)
+		}()
+		conn, err := ln.Accept()
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		defer conn.Close()
+		buf := make([]byte, 1024)
+		n, err := conn.Read(buf)
+		if err != nil {
+			t.Error(err)
+			return
+		}
+		ch <- buf[:n]
+	}()
+
+	_, port, err := net.SplitHostPort(ln.Addr().String())
+	if err != nil {
+		return nil, err
+	}
+	u := &url.URL{
+		Scheme: "https",
+		Host:   net.JoinHostPort(host, port),
+	}
+	req, err := http.NewRequest("POST", u.String(), nil)
+	if err != nil {
+		return nil, err
+	}
+	// The RoundTrip fails because the goroutine "server" hangs up. So
+	// ignore an EOF error.
+	_, err = rt.RoundTrip(req)
+	if err != nil && err != io.EOF {
+		return nil, err
+	}
+
+	return <-ch, nil
+}
+
+func TestUTLSServerName(t *testing.T) {
+	const clientHelloIDName = "HelloFirefox_63"
+
+	// No ServerName, dial IP address. Results in an invalid server_name
+	// extension with a 0-length host_name. Not sure if that's what it
+	// should do, but check if the behavior ever changes.
+	rt, err := NewUTLSRoundTripper(clientHelloIDName, &utls.Config{InsecureSkipVerify: true}, nil)
+	if err != nil {
+		panic(err)
+	}
+	buf, err := clientHelloResultingFromRoundTrip(t, "127.0.0.1", rt.(*UTLSRoundTripper))
+	if err != nil {
+		panic(err)
+	}
+	if !bytes.Contains(buf, []byte("\x00\x00\x00\x05\x00\x03\x00\x00\x00")) {
+		t.Errorf("expected 0-length server_name extension with no ServerName and IP address dial")
+	}
+
+	// No ServerName, dial hostname. server_name extension should come from
+	// the dial address.
+	rt, err = NewUTLSRoundTripper(clientHelloIDName, &utls.Config{InsecureSkipVerify: true}, nil)
+	if err != nil {
+		panic(err)
+	}
+	buf, err = clientHelloResultingFromRoundTrip(t, "localhost", rt.(*UTLSRoundTripper))
+	if err != nil {
+		panic(err)
+	}
+	if !bytes.Contains(buf, []byte("\x00\x00\x00\x0e\x00\x0c\x00\x00\x09localhost")) {
+		t.Errorf("expected \"localhost\" server_name extension with no ServerName and hostname dial")
+	}
+
+	// Given ServerName, dial IP address. server_name extension should from
+	// the ServerName.
+	rt, err = NewUTLSRoundTripper(clientHelloIDName, &utls.Config{InsecureSkipVerify: true, ServerName: "test.example"}, nil)
+	if err != nil {
+		panic(err)
+	}
+	buf, err = clientHelloResultingFromRoundTrip(t, "127.0.0.1", rt.(*UTLSRoundTripper))
+	if err != nil {
+		panic(err)
+	}
+	if !bytes.Contains(buf, []byte("\x00\x00\x00\x11\x00\x0f\x00\x00\x0ctest.example")) {
+		t.Errorf("expected \"test.example\" server_name extension with given ServerName and IP address dial")
+	}
+
+	// Given ServerName, dial hostname. server_name extension should from
+	// the ServerName.
+	rt, err = NewUTLSRoundTripper(clientHelloIDName, &utls.Config{InsecureSkipVerify: true, ServerName: "test.example"}, nil)
+	if err != nil {
+		panic(err)
+	}
+	buf, err = clientHelloResultingFromRoundTrip(t, "localhost", rt.(*UTLSRoundTripper))
+	if err != nil {
+		panic(err)
+	}
+	if !bytes.Contains(buf, []byte("\x00\x00\x00\x11\x00\x0f\x00\x00\x0ctest.example")) {
+		t.Errorf("expected \"test.example\" server_name extension with given ServerName and hostname dial")
+	}
+}





More information about the tor-commits mailing list