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:
- Use go 1.21
......
......@@ -38,13 +38,15 @@ import (
"net/url"
"os"
"path"
"slices"
"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/socks5"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports"
"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"
)
......@@ -64,7 +66,7 @@ func clientSetup() (launched bool, listeners []net.Listener) {
}
pt.ReportVersion("lyrebird", lyrebirdVersion)
ptClientProxy, err := ptGetProxy()
ptClientProxy, err := ptGetProxy(slices.Contains(ptClientInfo.MethodNames, "snowflake"))
if err != nil {
golog.Fatal(err)
} else if ptClientProxy != nil {
......@@ -85,6 +87,10 @@ func clientSetup() (launched bool, listeners []net.Listener) {
continue
}
f.OnEvent(func(e base.TransportEvent) {
pt.Log(pt.LogSeverityNotice, e.String())
})
ln, err := net.Listen("tcp", socksAddr)
if err != nil {
_ = pt.CmethodError(name, err.Error())
......@@ -155,6 +161,17 @@ func clientHandler(f base.ClientFactory, conn net.Conn, proxyURI *url.URL) {
return
}
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)
if err != nil {
......
......@@ -70,11 +70,6 @@ func (s *httpProxy) Dial(network, addr string) (net.Conn, error) {
}
conn := new(httpConn)
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.
reqURL, err := url.Parse("http://" + addr)
......@@ -112,7 +107,6 @@ func (s *httpProxy) Dial(network, addr string) (net.Conn, error) {
}
type httpConn struct {
remoteAddr *net.TCPAddr
httpConn *httputil.ClientConn // nolint: staticcheck
hijackedConn net.Conn
staleReader *bufio.Reader
......@@ -141,7 +135,7 @@ func (c *httpConn) LocalAddr() 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 {
......
......@@ -35,7 +35,8 @@ import (
"os"
"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
......@@ -71,7 +72,7 @@ func ptIsClient() (bool, error) {
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")
if specString == "" {
return nil, nil
......@@ -95,6 +96,22 @@ func ptGetProxy() (*url.URL, error) {
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 {
case "http":
// The most forgiving of proxies.
......
......@@ -5,71 +5,78 @@ require (
github.com/dchest/siphash v1.2.3
github.com/refraction-networking/utls v1.6.7
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/webtunnel v0.0.0-20240711104640-e64b1b3562f3
golang.org/x/crypto v0.28.0
golang.org/x/net v0.30.0
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib v1.6.0
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2 v2.10.1
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/webtunnel v0.0.2
golang.org/x/crypto v0.36.0
golang.org/x/net v0.37.0
)
require (
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/aws/aws-sdk-go-v2 v1.25.3 // indirect
github.com/aws/aws-sdk-go-v2/config v1.27.7 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.7 // indirect
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.15.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.3 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // 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/presigned-url v1.11.5 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.31.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.20.2 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.23.2 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.28.4 // indirect
github.com/aws/smithy-go v1.20.1 // indirect
github.com/cloudflare/circl v1.3.7 // indirect
github.com/andybalholm/brotli v1.1.1 // indirect
github.com/aws/aws-sdk-go-v2 v1.32.8 // indirect
github.com/aws/aws-sdk-go-v2/config v1.28.10 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.17.51 // 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.27 // 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.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.12.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sqs v1.37.6 // indirect
github.com/aws/aws-sdk-go-v2/service/sso v1.24.9 // indirect
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.8 // indirect
github.com/aws/aws-sdk-go-v2/service/sts v1.33.6 // indirect
github.com/aws/smithy-go v1.22.1 // indirect
github.com/cloudflare/circl v1.5.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang/mock v1.6.0 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/klauspost/compress v1.17.4 // indirect
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
github.com/klauspost/reedsolomon v1.12.0 // indirect
github.com/miekg/dns v1.1.58 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.9 // indirect
github.com/klauspost/reedsolomon v1.12.4 // indirect
github.com/miekg/dns v1.1.62 // indirect
github.com/patrickmn/go-cache v2.1.0+incompatible // indirect
github.com/pion/datachannel v1.5.5 // indirect
github.com/pion/dtls/v2 v2.2.7 // indirect
github.com/pion/ice/v2 v2.3.13 // indirect
github.com/pion/interceptor v0.1.25 // indirect
github.com/pion/datachannel v1.5.10 // indirect
github.com/pion/dtls/v2 v2.2.12 // indirect
github.com/pion/dtls/v3 v3.0.4 // 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/mdns v0.0.12 // indirect
github.com/pion/randutil v0.1.0 // indirect
github.com/pion/rtcp v1.2.12 // indirect
github.com/pion/rtp v1.8.3 // indirect
github.com/pion/sctp v1.8.12 // indirect
github.com/pion/sdp/v3 v3.0.8 // indirect
github.com/pion/srtp/v2 v2.0.18 // indirect
github.com/pion/rtcp v1.2.15 // indirect
github.com/pion/rtp v1.8.10 // indirect
github.com/pion/sctp v1.8.35 // indirect
github.com/pion/sdp/v3 v3.0.10 // indirect
github.com/pion/srtp/v2 v2.0.20 // indirect
github.com/pion/stun v0.6.1 // indirect
github.com/pion/transport/v2 v2.2.4 // indirect
github.com/pion/turn/v2 v2.1.4 // indirect
github.com/pion/webrtc/v3 v3.2.29 // indirect
github.com/pion/stun/v3 v3.0.0 // indirect
github.com/pion/transport/v2 v2.2.10 // 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/pmezard/go-difflib v1.0.0 // indirect
github.com/realclientip/realclientip-go v1.0.0 // indirect
github.com/stretchr/testify v1.9.0 // indirect
github.com/templexxx/cpu v0.1.0 // indirect
github.com/templexxx/xorsimd v0.4.2 // indirect
github.com/stretchr/testify v1.10.0 // indirect
github.com/templexxx/cpu v0.1.1 // indirect
github.com/templexxx/xorsimd v0.4.3 // 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/xtaci/kcp-go/v5 v5.6.8 // indirect
github.com/xtaci/smux v1.5.24 // indirect
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/snowflake/v2 v2.9.2 // indirect
golang.org/x/mod v0.17.0 // indirect
golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.26.0 // indirect
golang.org/x/text v0.19.0 // indirect
golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
github.com/wlynxg/anet v0.0.5 // indirect
github.com/xtaci/kcp-go/v5 v5.6.18 // indirect
github.com/xtaci/smux v1.5.33 // indirect
gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/ptutil v0.0.0-20240710081135-6c4d8ed41027 // indirect
golang.org/x/mod v0.22.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // 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
)
go 1.21
go 1.23.0
toolchain go1.23.7
This diff is collapsed.
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"constraints": {
"go": "1.20"
"go": "1.21"
},
"postUpdateOptions": ["gomodTidy", "gomodUpdateImportPaths"],
"osvVulnerabilityAlerts": true
......
......@@ -32,7 +32,7 @@ package base // import "gitlab.torproject.org/tpo/anti-censorship/pluggable-tran
import (
"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)
......@@ -54,6 +54,11 @@ type ClientFactory interface {
// (eg: handshaking) to get the connection to the point where it is
// ready to relay data.
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
......@@ -88,3 +93,7 @@ type Transport interface {
// protocol. This can fail if the provided arguments are invalid.
ServerFactory(stateDir string, args *pt.Args) (ServerFactory, error)
}
type TransportEvent interface {
String() string
}
......@@ -36,7 +36,7 @@ import (
"fmt"
"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"
)
......@@ -85,6 +85,9 @@ func (cf *meekClientFactory) Dial(network, addr string, dialFn base.DialFunc, ar
return newMeekConn(network, addr, dialFn, ca)
}
// Not yet implemented
func (cf *meekClientFactory) OnEvent(f func(base.TransportEvent)) {}
var (
_ base.ClientFactory = (*meekClientFactory)(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) {
// a good optimization and is a relatively common server feature,
// neither Firefox nor Chromium appear to use such optimizations.
DynamicRecordSizingDisabled: true,
RootCAs: GetRootCAs(),
}, *rt.clientHelloID)
if err = conn.Handshake(); err != nil {
......
......@@ -40,7 +40,7 @@ import (
"net"
"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/transports/base"
)
......@@ -121,6 +121,9 @@ func (cf *obfs2ClientFactory) Dial(network, addr string, dialFn base.DialFunc, a
return conn, nil
}
// Not yet implemented
func (cf *obfs2ClientFactory) OnEvent(f func(base.TransportEvent)) {}
type obfs2ServerFactory struct {
transport base.Transport
}
......
......@@ -40,7 +40,7 @@ import (
"net"
"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/uniformdh"
"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
return conn, nil
}
// Not yet implemented
func (cf *obfs3ClientFactory) OnEvent(f func(base.TransportEvent)) {}
type obfs3ServerFactory struct {
transport base.Transport
}
......
......@@ -42,7 +42,7 @@ import (
"syscall"
"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/ntor"
"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
return conn, nil
}
// Not yet implemented
func (cf *obfs4ClientFactory) OnEvent(f func(base.TransportEvent)) {}
type obfs4ServerFactory struct {
transport base.Transport
args *pt.Args
......
......@@ -33,7 +33,7 @@ import (
"fmt"
"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"
)
......@@ -95,5 +95,8 @@ func (cf *ssClientFactory) Dial(network, addr string, dialFn base.DialFunc, args
return conn, nil
}
// Not yet implemented
func (cf *ssClientFactory) OnEvent(f func(base.TransportEvent)) {}
var _ base.ClientFactory = (*ssClientFactory)(nil)
var _ base.Transport = (*Transport)(nil)
......@@ -4,16 +4,29 @@ import (
"errors"
"fmt"
"net"
"net/url"
"strconv"
"strings"
pt "gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/goptlib"
"gitlab.torproject.org/tpo/anti-censorship/pluggable-transports/lyrebird/transports/base"
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"
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{}
// Name returns the name of the snowflake transport protocol.
......@@ -24,6 +37,7 @@ func (t *Transport) Name() string {
// ClientFactory returns a new snowflakeClientFactory instance.
func (t *Transport) ClientFactory(stateDir string) (base.ClientFactory, error) {
cf := &snowflakeClientFactory{transport: t}
cf.eventLogger = &sfEventLogger{}
return cf, nil
}
......@@ -33,7 +47,8 @@ func (t *Transport) ServerFactory(stateDir string, args *pt.Args) (base.ServerFa
}
type snowflakeClientFactory struct {
transport base.Transport
transport base.Transport
eventLogger *sfEventLogger
}
func (cf *snowflakeClientFactory) Transport() base.Transport {
......@@ -83,9 +98,29 @@ func (cf *snowflakeClientFactory) ParseArgs(args *pt.Args) (interface{}, error)
if arg, ok := args.Get("fingerprint"); ok {
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
}
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) {
config, ok := args.(sf.ClientConfig)
if !ok {
......@@ -95,5 +130,6 @@ func (cf *snowflakeClientFactory) Dial(network, address string, dialFn base.Dial
if err != nil {
return nil, err
}
transport.AddSnowflakeEventListener(cf.eventLogger)
return transport.Dial()
}
package webtunnel
import (
"errors"
"fmt"
"log"
"net"
"net/url"
"strings"
......@@ -16,7 +14,7 @@ import (
)
type clientConfig struct {
RemoteAddresses []string
RemoteAddress string
Path string
TLSKind string
......@@ -64,12 +62,12 @@ func (c *clientFactory) parseArgs(args *pt.Args) (interface{}, error) {
if port == "" {
port = defaultPort
}
config.RemoteAddress = url.Hostname() + ":" + port
config.RemoteAddresses, err = getAddressesFromHostname(url.Hostname(), port)
if err != nil {
log.Println(err)
return nil, errors.New("")
if remoteAddress, ok := args.Get("addr"); ok {
config.RemoteAddress = remoteAddress
}
config.TLSServerName = url.Hostname()
}
......@@ -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) {
config := args.(clientConfig)
var conn net.Conn
for _, addr := range config.RemoteAddresses {
if tcpConn, err := dialFn("tcp", addr); err == nil {
conn = tcpConn
break
}
}
if conn == nil {
return nil, fmt.Errorf("Can't connect to %v", config.RemoteAddresses)
conn, err := dialFn("tcp", config.RemoteAddress)
if err != nil {
return nil, fmt.Errorf("error dialing %s: %v", config.RemoteAddress, err)
}
if config.TLSKind != "" {
conf := &tls.Config{ServerName: config.TLSServerName}
if config.UTLSFingerprint == "" {
......@@ -150,27 +144,5 @@ func (c *clientFactory) dial(network, address string, dialFn base.DialFunc, args
return conn, nil
}
func getAddressesFromHostname(hostname, port string) ([]string, error) {
addresses := []string{}
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
}
// Not yet implemented
func (cf *clientFactory) OnEvent(f func(base.TransportEvent)) {}