Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • pierov/lyrebird
  • eta/lyrebird
  • tpo/anti-censorship/pluggable-transports/lyrebird
  • meskio/obfs4
  • vbauerster/lyrebird
  • Gedsh/lyrebird
  • danialbehzadi/lyrebird
  • shelikhoo/lyrebird
  • jmwample/lyrebird
  • cohosh/lyrebird
  • Odups/lyrebird
  • tla/lyrebird
  • akwizgran/lyrebird
13 results
Show changes
Commits on Source (17)
Changes in version 0.5.0 - 2024-11-07:
- Add snowflake transport to Lyrebird
- Add event logging support for all transports
Changes in version 0.4.0 - 2024-10-08: Changes in version 0.4.0 - 2024-10-08:
- Use go 1.21 - Use go 1.21
......
...@@ -38,13 +38,15 @@ import ( ...@@ -38,13 +38,15 @@ import (
"net/url" "net/url"
"os" "os"
"path" "path"
"slices"
"syscall" "syscall"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/log" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/log"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/socks5" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/socks5"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base"
sf "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/client/lib"
"golang.org/x/net/proxy" "golang.org/x/net/proxy"
) )
...@@ -64,7 +66,7 @@ func clientSetup() (launched bool, listeners []net.Listener) { ...@@ -64,7 +66,7 @@ func clientSetup() (launched bool, listeners []net.Listener) {
} }
pt.ReportVersion("lyrebird", lyrebirdVersion) pt.ReportVersion("lyrebird", lyrebirdVersion)
ptClientProxy, err := ptGetProxy() ptClientProxy, err := ptGetProxy(slices.Contains(ptClientInfo.MethodNames, "snowflake"))
if err != nil { if err != nil {
golog.Fatal(err) golog.Fatal(err)
} else if ptClientProxy != nil { } else if ptClientProxy != nil {
...@@ -85,6 +87,10 @@ func clientSetup() (launched bool, listeners []net.Listener) { ...@@ -85,6 +87,10 @@ func clientSetup() (launched bool, listeners []net.Listener) {
continue continue
} }
f.OnEvent(func(e base.TransportEvent) {
pt.Log(pt.LogSeverityNotice, e.String())
})
ln, err := net.Listen("tcp", socksAddr) ln, err := net.Listen("tcp", socksAddr)
if err != nil { if err != nil {
_ = pt.CmethodError(name, err.Error()) _ = pt.CmethodError(name, err.Error())
...@@ -155,6 +161,17 @@ func clientHandler(f base.ClientFactory, conn net.Conn, proxyURI *url.URL) { ...@@ -155,6 +161,17 @@ func clientHandler(f base.ClientFactory, conn net.Conn, proxyURI *url.URL) {
return return
} }
dialFn = dialer.Dial dialFn = dialer.Dial
// The snowflake library takes care of configuring the proxy, so rather than
// relying on dialfn, we need to add the proxy URL to the Snowflake args
if name == "snowflake" {
config, ok := args.(sf.ClientConfig)
if !ok {
log.Errorf("Error adding snowflake proxy URL to args")
return
}
config.CommunicationProxy = proxyURI
}
} }
remote, err := f.Dial("tcp", socksReq.Target, dialFn, args) remote, err := f.Dial("tcp", socksReq.Target, dialFn, args)
if err != nil { if err != nil {
......
...@@ -70,11 +70,6 @@ func (s *httpProxy) Dial(network, addr string) (net.Conn, error) { ...@@ -70,11 +70,6 @@ func (s *httpProxy) Dial(network, addr string) (net.Conn, error) {
} }
conn := new(httpConn) conn := new(httpConn)
conn.httpConn = httputil.NewClientConn(c, nil) // nolint: staticcheck conn.httpConn = httputil.NewClientConn(c, nil) // nolint: staticcheck
conn.remoteAddr, err = net.ResolveTCPAddr(network, addr)
if err != nil {
conn.httpConn.Close()
return nil, err
}
// HACK HACK HACK HACK. http.ReadRequest also does this. // HACK HACK HACK HACK. http.ReadRequest also does this.
reqURL, err := url.Parse("http://" + addr) reqURL, err := url.Parse("http://" + addr)
...@@ -112,7 +107,6 @@ func (s *httpProxy) Dial(network, addr string) (net.Conn, error) { ...@@ -112,7 +107,6 @@ func (s *httpProxy) Dial(network, addr string) (net.Conn, error) {
} }
type httpConn struct { type httpConn struct {
remoteAddr *net.TCPAddr
httpConn *httputil.ClientConn // nolint: staticcheck httpConn *httputil.ClientConn // nolint: staticcheck
hijackedConn net.Conn hijackedConn net.Conn
staleReader *bufio.Reader staleReader *bufio.Reader
...@@ -141,7 +135,7 @@ func (c *httpConn) LocalAddr() net.Addr { ...@@ -141,7 +135,7 @@ func (c *httpConn) LocalAddr() net.Addr {
} }
func (c *httpConn) RemoteAddr() net.Addr { func (c *httpConn) RemoteAddr() net.Addr {
return c.remoteAddr return &net.UnixAddr{Net: "unknown_HTTPProxy"}
} }
func (c *httpConn) SetDeadline(t time.Time) error { func (c *httpConn) SetDeadline(t time.Time) error {
......
...@@ -35,7 +35,8 @@ import ( ...@@ -35,7 +35,8 @@ import (
"os" "os"
"strconv" "strconv"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/proxy"
) )
// This file contains things that probably should be in goptlib but are not // This file contains things that probably should be in goptlib but are not
...@@ -71,7 +72,7 @@ func ptIsClient() (bool, error) { ...@@ -71,7 +72,7 @@ func ptIsClient() (bool, error) {
return false, errors.New("not launched as a managed transport") return false, errors.New("not launched as a managed transport")
} }
func ptGetProxy() (*url.URL, error) { func ptGetProxy(isSnowflake bool) (*url.URL, error) {
specString := os.Getenv("TOR_PT_PROXY") specString := os.Getenv("TOR_PT_PROXY")
if specString == "" { if specString == "" {
return nil, nil return nil, nil
...@@ -95,6 +96,22 @@ func ptGetProxy() (*url.URL, error) { ...@@ -95,6 +96,22 @@ func ptGetProxy() (*url.URL, error) {
return nil, ptProxyError("proxy URI has a fragment defined") return nil, ptProxyError("proxy URI has a fragment defined")
} }
// Snowflake has extra restrictions on which proxy types are supported.
// Perform the necessary checks if snowflake is one of the configured
// transports.
if isSnowflake {
if err := proxy.CheckProxyProtocolSupport(spec); err != nil {
return nil, pt.ProxyError("proxy is not supported:" + err.Error())
} else {
client := proxy.NewSocks5UDPClient(spec)
conn, err := client.ListenPacket("udp", nil)
if err != nil {
return nil, pt.ProxyError("proxy test failure:" + err.Error())
}
conn.Close()
}
}
switch spec.Scheme { switch spec.Scheme {
case "http": case "http":
// The most forgiving of proxies. // The most forgiving of proxies.
......
...@@ -5,71 +5,78 @@ require ( ...@@ -5,71 +5,78 @@ require (
github.com/dchest/siphash v1.2.3 github.com/dchest/siphash v1.2.3
github.com/refraction-networking/utls v1.6.7 github.com/refraction-networking/utls v1.6.7
gitlab.com/yawning/edwards25519-extra v0.0.0-20231005122941-2149dcafc266 gitlab.com/yawning/edwards25519-extra v0.0.0-20231005122941-2149dcafc266
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.5.0 gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.6.0
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/webtunnel v0.0.0-20240711104640-e64b1b3562f3 gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2 v2.10.1
golang.org/x/crypto v0.28.0 gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/webtunnel v0.0.2
golang.org/x/net v0.30.0 golang.org/x/crypto v0.36.0
golang.org/x/net v0.37.0
) )
require ( require (
github.com/andybalholm/brotli v1.0.6 // indirect github.com/andybalholm/brotli v1.1.1 // indirect
github.com/aws/aws-sdk-go-v2 v1.25.3 // indirect github.com/aws/aws-sdk-go-v2 v1.32.8 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.7 // indirect github.com/aws/aws-sdk-go-v2/config v1.28.10 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.7 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.17.51 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.23 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.27 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.27 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.11.1 // indirect github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.1 // indirect
github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.5 // indirect github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.31.2 // indirect github.com/aws/aws-sdk-go-v2/service/sqs v1.37.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.33.6 // indirect
github.com/aws/smithy-go v1.20.1 // indirect github.com/aws/smithy-go v1.22.1 // indirect
github.com/cloudflare/circl v1.3.7 // indirect github.com/cloudflare/circl v1.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/mock v1.6.0 // indirect github.com/golang/mock v1.6.0 // indirect
github.com/google/uuid v1.3.1 // indirect github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.4 // indirect github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/klauspost/reedsolomon v1.12.0 // indirect github.com/klauspost/reedsolomon v1.12.4 // indirect
github.com/miekg/dns v1.1.58 // indirect github.com/miekg/dns v1.1.62 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pion/datachannel v1.5.5 // indirect github.com/pion/datachannel v1.5.10 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect github.com/pion/dtls/v2 v2.2.12 // indirect
github.com/pion/ice/v2 v2.3.13 // indirect github.com/pion/dtls/v3 v3.0.4 // indirect
github.com/pion/interceptor v0.1.25 // indirect github.com/pion/ice/v2 v2.3.37 // indirect
github.com/pion/interceptor v0.1.37 // indirect
github.com/pion/logging v0.2.2 // indirect github.com/pion/logging v0.2.2 // indirect
github.com/pion/mdns v0.0.12 // indirect github.com/pion/mdns v0.0.12 // indirect
github.com/pion/randutil v0.1.0 // indirect github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.12 // indirect github.com/pion/rtcp v1.2.15 // indirect
github.com/pion/rtp v1.8.3 // indirect github.com/pion/rtp v1.8.10 // indirect
github.com/pion/sctp v1.8.12 // indirect github.com/pion/sctp v1.8.35 // indirect
github.com/pion/sdp/v3 v3.0.8 // indirect github.com/pion/sdp/v3 v3.0.10 // indirect
github.com/pion/srtp/v2 v2.0.18 // indirect github.com/pion/srtp/v2 v2.0.20 // indirect
github.com/pion/stun v0.6.1 // indirect github.com/pion/stun v0.6.1 // indirect
github.com/pion/transport/v2 v2.2.4 // indirect github.com/pion/stun/v3 v3.0.0 // indirect
github.com/pion/turn/v2 v2.1.4 // indirect github.com/pion/transport/v2 v2.2.10 // indirect
github.com/pion/webrtc/v3 v3.2.29 // indirect github.com/pion/transport/v3 v3.0.7 // indirect
github.com/pion/turn/v2 v2.1.6 // indirect
github.com/pion/webrtc/v3 v3.3.5 // indirect
github.com/pkg/errors v0.9.1 // indirect github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/realclientip/realclientip-go v1.0.0 // indirect github.com/realclientip/realclientip-go v1.0.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect github.com/stretchr/testify v1.10.0 // indirect
github.com/templexxx/cpu v0.1.0 // indirect github.com/templexxx/cpu v0.1.1 // indirect
github.com/templexxx/xorsimd v0.4.2 // indirect github.com/templexxx/xorsimd v0.4.3 // indirect
github.com/tjfoc/gmsm v1.4.1 // indirect github.com/tjfoc/gmsm v1.4.1 // indirect
github.com/txthinking/runnergroup v0.0.0-20210608031112-152c7c4432bf // indirect github.com/txthinking/runnergroup v0.0.0-20241229123329-7b873ad00768 // indirect
github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 // indirect github.com/txthinking/socks5 v0.0.0-20230325130024-4230056ae301 // indirect
github.com/xtaci/kcp-go/v5 v5.6.8 // indirect github.com/wlynxg/anet v0.0.5 // indirect
github.com/xtaci/smux v1.5.24 // indirect github.com/xtaci/kcp-go/v5 v5.6.18 // indirect
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2 v2.9.2 // indirect github.com/xtaci/smux v1.5.33 // indirect
golang.org/x/mod v0.17.0 // indirect gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/ptutil v0.0.0-20240710081135-6c4d8ed41027 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/mod v0.22.0 // indirect
golang.org/x/sys v0.26.0 // indirect golang.org/x/sync v0.12.0 // indirect
golang.org/x/text v0.19.0 // indirect golang.org/x/sys v0.31.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect golang.org/x/text v0.23.0 // indirect
golang.org/x/tools v0.29.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )
go 1.21 go 1.23.0
toolchain go1.23.7
This diff is collapsed.
{ {
"$schema": "https://docs.renovatebot.com/renovate-schema.json", "$schema": "https://docs.renovatebot.com/renovate-schema.json",
"constraints": { "constraints": {
"go": "1.20" "go": "1.21"
}, },
"postUpdateOptions": ["gomodTidy", "gomodUpdateImportPaths"], "postUpdateOptions": ["gomodTidy", "gomodUpdateImportPaths"],
"osvVulnerabilityAlerts": true "osvVulnerabilityAlerts": true
......
...@@ -32,7 +32,7 @@ package base // import "gitlab.torproject.org/tpo/anti-censorship/pluggable-tran ...@@ -32,7 +32,7 @@ package base // import "gitlab.torproject.org/tpo/anti-censorship/pluggable-tran
import ( import (
"net" "net"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
) )
type DialFunc func(string, string) (net.Conn, error) type DialFunc func(string, string) (net.Conn, error)
...@@ -54,6 +54,11 @@ type ClientFactory interface { ...@@ -54,6 +54,11 @@ type ClientFactory interface {
// (eg: handshaking) to get the connection to the point where it is // (eg: handshaking) to get the connection to the point where it is
// ready to relay data. // ready to relay data.
Dial(network, address string, dialFn DialFunc, args interface{}) (net.Conn, error) Dial(network, address string, dialFn DialFunc, args interface{}) (net.Conn, error)
// OnEvent sets a callback that can be called by transports when notable
// events in the connection happen. This is especially useful for logging
// and UX purposes.
OnEvent(f func(TransportEvent))
} }
// ServerFactory is the interface that defines the factory for creating // ServerFactory is the interface that defines the factory for creating
...@@ -88,3 +93,7 @@ type Transport interface { ...@@ -88,3 +93,7 @@ type Transport interface {
// protocol. This can fail if the provided arguments are invalid. // protocol. This can fail if the provided arguments are invalid.
ServerFactory(stateDir string, args *pt.Args) (ServerFactory, error) ServerFactory(stateDir string, args *pt.Args) (ServerFactory, error)
} }
type TransportEvent interface {
String() string
}
...@@ -36,7 +36,7 @@ import ( ...@@ -36,7 +36,7 @@ import (
"fmt" "fmt"
"net" "net"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base"
) )
...@@ -85,6 +85,9 @@ func (cf *meekClientFactory) Dial(network, addr string, dialFn base.DialFunc, ar ...@@ -85,6 +85,9 @@ func (cf *meekClientFactory) Dial(network, addr string, dialFn base.DialFunc, ar
return newMeekConn(network, addr, dialFn, ca) return newMeekConn(network, addr, dialFn, ca)
} }
// Not yet implemented
func (cf *meekClientFactory) OnEvent(f func(base.TransportEvent)) {}
var ( var (
_ base.ClientFactory = (*meekClientFactory)(nil) _ base.ClientFactory = (*meekClientFactory)(nil)
_ base.Transport = (*Transport)(nil) _ base.Transport = (*Transport)(nil)
......
package meeklite
import (
"crypto/x509"
"log"
)
// https://crt.sh/?id=9314791
const LetsEncryptRootCert = `-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----`
// GetRootCAs is a workaround for older versions of Android that do not trust
// Let's Encrypt's ISRG Root X1. This manually adds the ISRG root to the device's
// existing cert pool.
func GetRootCAs() *x509.CertPool {
rootCerts, err := x509.SystemCertPool()
if err != nil {
rootCerts = x509.NewCertPool()
}
if ok := rootCerts.AppendCertsFromPEM([]byte(LetsEncryptRootCert)); !ok {
log.Println("Error appending Let's Encrypt root certificate to cert poool")
return nil
}
return rootCerts
}
...@@ -115,6 +115,7 @@ func (rt *roundTripper) dialTLS(network, addr string) (net.Conn, error) { ...@@ -115,6 +115,7 @@ func (rt *roundTripper) dialTLS(network, addr string) (net.Conn, error) {
// a good optimization and is a relatively common server feature, // a good optimization and is a relatively common server feature,
// neither Firefox nor Chromium appear to use such optimizations. // neither Firefox nor Chromium appear to use such optimizations.
DynamicRecordSizingDisabled: true, DynamicRecordSizingDisabled: true,
RootCAs: GetRootCAs(),
}, *rt.clientHelloID) }, *rt.clientHelloID)
if err = conn.Handshake(); err != nil { if err = conn.Handshake(); err != nil {
......
...@@ -40,7 +40,7 @@ import ( ...@@ -40,7 +40,7 @@ import (
"net" "net"
"time" "time"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/csrand" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/csrand"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base"
) )
...@@ -121,6 +121,9 @@ func (cf *obfs2ClientFactory) Dial(network, addr string, dialFn base.DialFunc, a ...@@ -121,6 +121,9 @@ func (cf *obfs2ClientFactory) Dial(network, addr string, dialFn base.DialFunc, a
return conn, nil return conn, nil
} }
// Not yet implemented
func (cf *obfs2ClientFactory) OnEvent(f func(base.TransportEvent)) {}
type obfs2ServerFactory struct { type obfs2ServerFactory struct {
transport base.Transport transport base.Transport
} }
......
...@@ -40,7 +40,7 @@ import ( ...@@ -40,7 +40,7 @@ import (
"net" "net"
"time" "time"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/csrand" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/csrand"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/uniformdh" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/uniformdh"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base"
...@@ -105,6 +105,9 @@ func (cf *obfs3ClientFactory) Dial(network, addr string, dialFn base.DialFunc, a ...@@ -105,6 +105,9 @@ func (cf *obfs3ClientFactory) Dial(network, addr string, dialFn base.DialFunc, a
return conn, nil return conn, nil
} }
// Not yet implemented
func (cf *obfs3ClientFactory) OnEvent(f func(base.TransportEvent)) {}
type obfs3ServerFactory struct { type obfs3ServerFactory struct {
transport base.Transport transport base.Transport
} }
......
...@@ -42,7 +42,7 @@ import ( ...@@ -42,7 +42,7 @@ import (
"syscall" "syscall"
"time" "time"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/drbg" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/drbg"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/ntor" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/ntor"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/probdist" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/common/probdist"
...@@ -223,6 +223,9 @@ func (cf *obfs4ClientFactory) Dial(network, addr string, dialFn base.DialFunc, a ...@@ -223,6 +223,9 @@ func (cf *obfs4ClientFactory) Dial(network, addr string, dialFn base.DialFunc, a
return conn, nil return conn, nil
} }
// Not yet implemented
func (cf *obfs4ClientFactory) OnEvent(f func(base.TransportEvent)) {}
type obfs4ServerFactory struct { type obfs4ServerFactory struct {
transport base.Transport transport base.Transport
args *pt.Args args *pt.Args
......
...@@ -33,7 +33,7 @@ import ( ...@@ -33,7 +33,7 @@ import (
"fmt" "fmt"
"net" "net"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base"
) )
...@@ -95,5 +95,8 @@ func (cf *ssClientFactory) Dial(network, addr string, dialFn base.DialFunc, args ...@@ -95,5 +95,8 @@ func (cf *ssClientFactory) Dial(network, addr string, dialFn base.DialFunc, args
return conn, nil return conn, nil
} }
// Not yet implemented
func (cf *ssClientFactory) OnEvent(f func(base.TransportEvent)) {}
var _ base.ClientFactory = (*ssClientFactory)(nil) var _ base.ClientFactory = (*ssClientFactory)(nil)
var _ base.Transport = (*Transport)(nil) var _ base.Transport = (*Transport)(nil)
...@@ -4,16 +4,29 @@ import ( ...@@ -4,16 +4,29 @@ import (
"errors" "errors"
"fmt" "fmt"
"net" "net"
"net/url"
"strconv" "strconv"
"strings" "strings"
pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib" pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base" "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base"
sf "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/client/lib" sf "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/client/lib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/event"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2/common/proxy"
) )
const transportName = "snowflake" const transportName = "snowflake"
type sfEventLogger struct {
onEventCallback func(e base.TransportEvent)
}
func (el *sfEventLogger) OnNewSnowflakeEvent(e event.SnowflakeEvent) {
if el.onEventCallback != nil {
el.onEventCallback(e)
}
}
type Transport struct{} type Transport struct{}
// Name returns the name of the snowflake transport protocol. // Name returns the name of the snowflake transport protocol.
...@@ -24,6 +37,7 @@ func (t *Transport) Name() string { ...@@ -24,6 +37,7 @@ func (t *Transport) Name() string {
// ClientFactory returns a new snowflakeClientFactory instance. // ClientFactory returns a new snowflakeClientFactory instance.
func (t *Transport) ClientFactory(stateDir string) (base.ClientFactory, error) { func (t *Transport) ClientFactory(stateDir string) (base.ClientFactory, error) {
cf := &snowflakeClientFactory{transport: t} cf := &snowflakeClientFactory{transport: t}
cf.eventLogger = &sfEventLogger{}
return cf, nil return cf, nil
} }
...@@ -33,7 +47,8 @@ func (t *Transport) ServerFactory(stateDir string, args *pt.Args) (base.ServerFa ...@@ -33,7 +47,8 @@ func (t *Transport) ServerFactory(stateDir string, args *pt.Args) (base.ServerFa
} }
type snowflakeClientFactory struct { type snowflakeClientFactory struct {
transport base.Transport transport base.Transport
eventLogger *sfEventLogger
} }
func (cf *snowflakeClientFactory) Transport() base.Transport { func (cf *snowflakeClientFactory) Transport() base.Transport {
...@@ -83,9 +98,29 @@ func (cf *snowflakeClientFactory) ParseArgs(args *pt.Args) (interface{}, error) ...@@ -83,9 +98,29 @@ func (cf *snowflakeClientFactory) ParseArgs(args *pt.Args) (interface{}, error)
if arg, ok := args.Get("fingerprint"); ok { if arg, ok := args.Get("fingerprint"); ok {
config.BridgeFingerprint = arg config.BridgeFingerprint = arg
} }
if arg, ok := args.Get("proxy"); ok {
outboundProxy, err := url.Parse(arg)
if err != nil {
return nil, fmt.Errorf("Invalid SOCKS arg: proxy=%s", arg)
}
if err := proxy.CheckProxyProtocolSupport(outboundProxy); err != nil {
return nil, fmt.Errorf("proxy is not supported: %s", err.Error())
}
client := proxy.NewSocks5UDPClient(outboundProxy)
conn, err := client.ListenPacket("udp", nil)
if err != nil {
return nil, fmt.Errorf("proxy test failure: %s", err.Error())
}
conn.Close()
config.CommunicationProxy = outboundProxy
}
return config, nil return config, nil
} }
func (cf *snowflakeClientFactory) OnEvent(f func(e base.TransportEvent)) {
cf.eventLogger.onEventCallback = f
}
func (cf *snowflakeClientFactory) Dial(network, address string, dialFn base.DialFunc, args interface{}) (net.Conn, error) { func (cf *snowflakeClientFactory) Dial(network, address string, dialFn base.DialFunc, args interface{}) (net.Conn, error) {
config, ok := args.(sf.ClientConfig) config, ok := args.(sf.ClientConfig)
if !ok { if !ok {
...@@ -95,5 +130,6 @@ func (cf *snowflakeClientFactory) Dial(network, address string, dialFn base.Dial ...@@ -95,5 +130,6 @@ func (cf *snowflakeClientFactory) Dial(network, address string, dialFn base.Dial
if err != nil { if err != nil {
return nil, err return nil, err
} }
transport.AddSnowflakeEventListener(cf.eventLogger)
return transport.Dial() return transport.Dial()
} }
package webtunnel package webtunnel
import ( import (
"errors"
"fmt" "fmt"
"log"
"net" "net"
"net/url" "net/url"
"strings" "strings"
...@@ -16,7 +14,7 @@ import ( ...@@ -16,7 +14,7 @@ import (
) )
type clientConfig struct { type clientConfig struct {
RemoteAddresses []string RemoteAddress string
Path string Path string
TLSKind string TLSKind string
...@@ -64,12 +62,12 @@ func (c *clientFactory) parseArgs(args *pt.Args) (interface{}, error) { ...@@ -64,12 +62,12 @@ func (c *clientFactory) parseArgs(args *pt.Args) (interface{}, error) {
if port == "" { if port == "" {
port = defaultPort port = defaultPort
} }
config.RemoteAddress = url.Hostname() + ":" + port
config.RemoteAddresses, err = getAddressesFromHostname(url.Hostname(), port) if remoteAddress, ok := args.Get("addr"); ok {
if err != nil { config.RemoteAddress = remoteAddress
log.Println(err)
return nil, errors.New("")
} }
config.TLSServerName = url.Hostname() config.TLSServerName = url.Hostname()
} }
...@@ -102,16 +100,12 @@ func (c *clientFactory) Dial(network, address string, dialFn base.DialFunc, args ...@@ -102,16 +100,12 @@ func (c *clientFactory) Dial(network, address string, dialFn base.DialFunc, args
func (c *clientFactory) dial(network, address string, dialFn base.DialFunc, args interface{}) (net.Conn, error) { func (c *clientFactory) dial(network, address string, dialFn base.DialFunc, args interface{}) (net.Conn, error) {
config := args.(clientConfig) config := args.(clientConfig)
var conn net.Conn
for _, addr := range config.RemoteAddresses { conn, err := dialFn("tcp", config.RemoteAddress)
if tcpConn, err := dialFn("tcp", addr); err == nil { if err != nil {
conn = tcpConn return nil, fmt.Errorf("error dialing %s: %v", config.RemoteAddress, err)
break
}
}
if conn == nil {
return nil, fmt.Errorf("Can't connect to %v", config.RemoteAddresses)
} }
if config.TLSKind != "" { if config.TLSKind != "" {
conf := &tls.Config{ServerName: config.TLSServerName} conf := &tls.Config{ServerName: config.TLSServerName}
if config.UTLSFingerprint == "" { if config.UTLSFingerprint == "" {
...@@ -150,27 +144,5 @@ func (c *clientFactory) dial(network, address string, dialFn base.DialFunc, args ...@@ -150,27 +144,5 @@ func (c *clientFactory) dial(network, address string, dialFn base.DialFunc, args
return conn, nil return conn, nil
} }
func getAddressesFromHostname(hostname, port string) ([]string, error) { // Not yet implemented
addresses := []string{} func (cf *clientFactory) OnEvent(f func(base.TransportEvent)) {}
addr, err := net.LookupHost(hostname)
if err != nil {
return addresses, fmt.Errorf("Lookup error for host %s: %v", hostname, err)
}
for _, a := range addr {
ip := net.ParseIP(a)
if ip == nil || ip.IsLoopback() || ip.IsUnspecified() || ip.IsMulticast() || ip.IsLinkLocalUnicast() || ip.IsPrivate() {
continue
}
if ip.To4() != nil {
addresses = append(addresses, a+":"+port)
} else {
addresses = append(addresses, "["+a+"]:"+port)
}
}
if len(addresses) == 0 {
return addresses, fmt.Errorf("Could not find any valid IP for %s", hostname)
}
return addresses, nil
}