Просмотр исходного кода

Add conditional compilation for QUIC

Rod Hynes 6 лет назад
Родитель
Сommit
5112cdf9fb

+ 1 - 1
psiphon/common/marionette/marionette.go

@@ -59,7 +59,7 @@ type Listener struct {
 
 // Listen creates a new Marionette Listener. The address input should not
 // include a port number as the port is defined in the Marionette format.
-func Listen(address, format string) (*Listener, error) {
+func Listen(address, format string) (net.Listener, error) {
 
 	data, err := mar.ReadFormat(format)
 	if err != nil {

+ 1 - 1
psiphon/common/marionette/marionette_disabled.go

@@ -41,7 +41,7 @@ type Listener struct {
 
 // Listen creates a new Marionette Listener. The address input should not
 // include a port number as that's defined in the Marionette format.
-func Listen(_, _ string) (*Listener, error) {
+func Listen(_, _ string) (net.Listener, error) {
 	return nil, errors.TraceNew("operation is not enabled")
 }
 

+ 15 - 0
psiphon/common/protocol/serverEntry.go

@@ -445,9 +445,18 @@ func (serverEntry *ServerEntry) SupportsProtocol(protocol string) bool {
 	return common.Contains(serverEntry.Capabilities, requiredCapability)
 }
 
+// ConditionallyEnabledComponents defines an interface which can be queried to
+// determine which conditionally compiled protocol components are present.
+type ConditionallyEnabledComponents interface {
+	QUICEnabled() bool
+	MarionetteEnabled() bool
+	TapdanceEnabled() bool
+}
+
 // GetSupportedProtocols returns a list of tunnel protocols supported
 // by the ServerEntry's capabilities.
 func (serverEntry *ServerEntry) GetSupportedProtocols(
+	conditionallyEnabled ConditionallyEnabledComponents,
 	useUpstreamProxy bool,
 	limitTunnelProtocols []string,
 	excludeIntensive bool) []string {
@@ -476,6 +485,12 @@ func (serverEntry *ServerEntry) GetSupportedProtocols(
 			continue
 		}
 
+		if (TunnelProtocolUsesQUIC(protocol) && !conditionallyEnabled.QUICEnabled()) ||
+			(TunnelProtocolUsesMarionette(protocol) && !conditionallyEnabled.MarionetteEnabled()) ||
+			(TunnelProtocolUsesTapdance(protocol) && !conditionallyEnabled.TapdanceEnabled()) {
+			continue
+		}
+
 		if serverEntry.SupportsProtocol(protocol) {
 			supportedProtocols = append(supportedProtocols, protocol)
 		}

+ 2 - 0
psiphon/common/quic/obfuscator.go

@@ -1,3 +1,5 @@
+// +build !DISABLE_QUIC
+
 /*
  * Copyright (c) 2018, Psiphon Inc.
  * All rights reserved.

+ 8 - 1
psiphon/common/quic/quic.go

@@ -1,3 +1,5 @@
+// +build !DISABLE_QUIC
+
 /*
  * Copyright (c) 2018, Psiphon Inc.
  * All rights reserved.
@@ -69,6 +71,11 @@ const (
 	CLIENT_IDLE_TIMEOUT      = 30 * time.Second
 )
 
+// Enabled indicates if QUIC functionality is enabled.
+func Enabled() bool {
+	return true
+}
+
 const ietfQUICDraft24VersionNumber = 0xff000018
 
 var supportedVersionNumbers = map[string]uint32{
@@ -103,7 +110,7 @@ type Listener struct {
 func Listen(
 	logger common.Logger,
 	address string,
-	obfuscationKey string) (*Listener, error) {
+	obfuscationKey string) (net.Listener, error) {
 
 	certificate, privateKey, err := common.GenerateWebServerCertificate(
 		values.GetHostName())

+ 80 - 0
psiphon/common/quic/quic_disabled.go

@@ -0,0 +1,80 @@
+// +build DISABLE_QUIC
+
+/*
+ * Copyright (c) 2020, Psiphon Inc.
+ * All rights reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+package quic
+
+import (
+	"context"
+	"net"
+	"net/http"
+
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
+)
+
+// Enabled indicates if QUIC functionality is enabled.
+func Enabled() bool {
+	return false
+}
+
+func Listen(
+	logger common.Logger,
+	address string,
+	obfuscationKey string) (net.Listener, error) {
+
+	return nil, errors.TraceNew("operation is not enabled")
+}
+
+func Dial(
+	ctx context.Context,
+	packetConn net.PacketConn,
+	remoteAddr *net.UDPAddr,
+	quicSNIAddress string,
+	negotiateQUICVersion string,
+	obfuscationKey string,
+	obfuscationPaddingSeed *prng.Seed) (net.Conn, error) {
+
+	return nil, errors.TraceNew("operation is not enabled")
+}
+
+type QUICTransporter struct {
+}
+
+func (t *QUICTransporter) SetRequestContext(ctx context.Context) {
+}
+
+func (t *QUICTransporter) CloseIdleConnections() {
+}
+
+func (t *QUICTransporter) RoundTrip(req *http.Request) (resp *http.Response, err error) {
+	return nil, errors.TraceNew("operation is not enabled")
+}
+
+func NewQUICTransporter(
+	ctx context.Context,
+	noticeEmitter func(string),
+	udpDialer func(ctx context.Context) (net.PacketConn, *net.UDPAddr, error),
+	quicSNIAddress string,
+	negotiateQUICVersion string) (*QUICTransporter, error) {
+
+	return nil, errors.TraceNew("operation is not enabled")
+}

+ 2 - 0
psiphon/common/quic/quic_test.go

@@ -1,3 +1,5 @@
+// +build !DISABLE_QUIC
+
 /*
  * Copyright (c) 2018, Psiphon Inc.
  * All rights reserved.

+ 1 - 1
psiphon/common/tapdance/tapdance.go

@@ -65,7 +65,7 @@ type Listener struct {
 // RemoteAddr. RemoteAddr _must_ be called non-concurrently before calling Read
 // on accepted conns as the HAProxy proxy protocol header reading logic sets
 // SetReadDeadline and performs a Read.
-func Listen(address string) (*Listener, error) {
+func Listen(address string) (net.Listener, error) {
 
 	tcpListener, err := net.Listen("tcp", address)
 	if err != nil {

+ 1 - 1
psiphon/common/tapdance/tapdance_disabled.go

@@ -40,7 +40,7 @@ type Listener struct {
 }
 
 // Listen creates a new Tapdance listener.
-func Listen(_ string) (*Listener, error) {
+func Listen(_ string) (net.Listener, error) {
 	return nil, errors.TraceNew("operation is not enabled")
 }
 

+ 11 - 2
psiphon/controller.go

@@ -1084,7 +1084,11 @@ func (p *protocolSelectionConstraints) isInitialCandidate(
 	serverEntry *protocol.ServerEntry) bool {
 
 	return p.hasInitialProtocols() &&
-		len(serverEntry.GetSupportedProtocols(p.useUpstreamProxy, p.initialLimitProtocols, excludeIntensive)) > 0
+		len(serverEntry.GetSupportedProtocols(
+			conditionallyEnabledComponents{},
+			p.useUpstreamProxy,
+			p.initialLimitProtocols,
+			excludeIntensive)) > 0
 }
 
 func (p *protocolSelectionConstraints) isCandidate(
@@ -1092,7 +1096,11 @@ func (p *protocolSelectionConstraints) isCandidate(
 	serverEntry *protocol.ServerEntry) bool {
 
 	return len(p.limitProtocols) == 0 ||
-		len(serverEntry.GetSupportedProtocols(p.useUpstreamProxy, p.limitProtocols, excludeIntensive)) > 0
+		len(serverEntry.GetSupportedProtocols(
+			conditionallyEnabledComponents{},
+			p.useUpstreamProxy,
+			p.limitProtocols,
+			excludeIntensive)) > 0
 }
 
 func (p *protocolSelectionConstraints) canReplay(
@@ -1122,6 +1130,7 @@ func (p *protocolSelectionConstraints) supportedProtocols(
 	}
 
 	return serverEntry.GetSupportedProtocols(
+		conditionallyEnabledComponents{},
 		p.useUpstreamProxy,
 		limitProtocols,
 		excludeIntensive)

+ 7 - 0
psiphon/controller_test.go

@@ -40,6 +40,7 @@ import (
 	socks "github.com/Psiphon-Labs/goptlib"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic"
 	"github.com/elazarl/goproxy"
 )
 
@@ -419,6 +420,9 @@ func TestFrontedMeekFragmentor(t *testing.T) {
 }
 
 func TestQUIC(t *testing.T) {
+	if !quic.Enabled() {
+		t.Skip("QUIC is not enabled")
+	}
 	controllerRun(t,
 		&controllerRunConfig{
 			expectNoServerEntries:    false,
@@ -436,6 +440,9 @@ func TestQUIC(t *testing.T) {
 }
 
 func TestFrontedQUIC(t *testing.T) {
+	if !quic.Enabled() {
+		t.Skip("QUIC is not enabled")
+	}
 	controllerRun(t,
 		&controllerRunConfig{
 			expectNoServerEntries:    false,

+ 4 - 1
psiphon/dataStore.go

@@ -487,7 +487,10 @@ func newTargetServerEntryIterator(config *Config, isTactics bool) (bool, *Server
 			// At the ServerEntryIterator level, only limitTunnelProtocols is applied;
 			// excludeIntensive is handled higher up.
 			if len(serverEntry.GetSupportedProtocols(
-				config.UseUpstreamProxy(), limitTunnelProtocols, false)) == 0 {
+				conditionallyEnabledComponents{},
+				config.UseUpstreamProxy(),
+				limitTunnelProtocols,
+				false)) == 0 {
 				return false, nil, errors.TraceNew("TargetServerEntry does not support LimitTunnelProtocols")
 			}
 		}

+ 4 - 0
psiphon/server/server_test.go

@@ -45,6 +45,7 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/parameters"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/prng"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/protocol"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/tactics"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/values"
 	"golang.org/x/net/proxy"
@@ -270,6 +271,9 @@ func TestUnfrontedMeekSessionTicketTLS13(t *testing.T) {
 }
 
 func TestQUICOSSH(t *testing.T) {
+	if !quic.Enabled() {
+		t.Skip("QUIC is not enabled")
+	}
 	runServer(t,
 		&runServerConfig{
 			tunnelProtocol:       "QUIC-OSSH",

+ 20 - 0
psiphon/utils.go

@@ -37,7 +37,10 @@ import (
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/crypto/ssh"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/errors"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/marionette"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/quic"
 	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/stacktrace"
+	"github.com/Psiphon-Labs/psiphon-tunnel-core/psiphon/common/tapdance"
 )
 
 // MakePsiphonUserAgent constructs a User-Agent value to use for web service
@@ -260,3 +263,20 @@ func DoGarbageCollection() {
 	debug.SetGCPercent(5)
 	debug.FreeOSMemory()
 }
+
+// conditionallyEnabledComponents implements the
+// protocol.ConditionallyEnabledComponents interface.
+type conditionallyEnabledComponents struct {
+}
+
+func (c conditionallyEnabledComponents) QUICEnabled() bool {
+	return quic.Enabled()
+}
+
+func (c conditionallyEnabledComponents) MarionetteEnabled() bool {
+	return marionette.Enabled()
+}
+
+func (c conditionallyEnabledComponents) TapdanceEnabled() bool {
+	return tapdance.Enabled()
+}