/
dialer.go
215 lines (182 loc) · 6.78 KB
/
dialer.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
package tapdance
import (
"context"
"errors"
"fmt"
"net"
"strings"
"time"
transports "github.com/refraction-networking/conjure/pkg/transports/client"
pb "github.com/refraction-networking/conjure/proto"
)
var sessionsTotal CounterUint64
var randomizePortDefault = false
// Dialer contains options and implements advanced functions for establishing TapDance connection.
type Dialer struct {
SplitFlows bool
// THIS IS REQUIRED TO INTERFACE WITH PSIPHON ANDROID
// we use their dialer to prevent connection loopback into our own proxy
// connection when tunneling the whole device.
//
// Deprecated: Dialer does not allow specifying the local address used for NAT traversal in
// some transports. Use DialerWithLaddr instead.
Dialer func(context.Context, string, string) (net.Conn, error)
// DialerWithLaddr allows a custom dialer to be used for the underlying TCP/UDP connection.
//
// THIS IS REQUIRED TO INTERFACE WITH PSIPHON ANDROID
// we use their dialer to prevent connection loopback into our own proxy
// connection when tunneling the whole device.
DialerWithLaddr dialFunc
DarkDecoy bool
// The type of registrar to use when performing Conjure registrations.
DarkDecoyRegistrar Registrar
// DisableRegistrarOverrides Indicates whether the client will allow the registrar to provide
// alternative parameters that may work better in substitute for the deterministically selected
// parameters. This only works for bidirectional registration methods where the client receives
// a RegistrationResponse.
DisableRegistrarOverrides bool
// The type of transport to use for Conjure connections.
Transport pb.TransportType
TransportConfig Transport
// RegDelay is the delay duration to wait for registration ingest.
RegDelay time.Duration
UseProxyHeader bool
V6Support bool
// Width indicates the number of independent decoy registrations to send in parallel as success
// rates for individual decoy registrations are relatively low. (Default 5)
//
// Deprecated: Use the Width parameter in the Decoy Registrar.
Width int
// Subnet that we want to limit to (or empty if they're all fine)
PhantomNet string
// Whether we want to register and connect to a phantom, or register only
RegisterOnly bool
}
// Dial connects to the address on the named network.
//
// The only supported network at this time: "tcp".
// The address has the form "host:port".
// The host must be a literal IP address, or a host name that can be
// resolved to IP addresses.
// To avoid abuse, only certain whitelisted ports are allowed.
//
// Example: Dial("tcp", "golang.org:80")
func Dial(network, address string) (net.Conn, error) {
var d Dialer
return d.Dial(network, address)
}
// Dial connects to the address on the named network.
func (d *Dialer) Dial(network, address string) (net.Conn, error) {
return d.DialContext(context.Background(), network, address)
}
// DialContext connects to the address on the named network using the provided context.
// Long deadline is strongly advised, since tapdance will try multiple decoys.
//
// The only supported network at this time: "tcp".
// The address has the form "host:port".
// The host must be a literal IP address, or a host name that can be
// resolved to IP addresses.
// To avoid abuse, only certain whitelisted ports are allowed.
//
// Example: Dial("tcp", "golang.org:80")
func (d *Dialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) {
if network != "tcp" {
return nil, &net.OpError{Op: "dial", Net: network, Err: net.UnknownNetworkError(network)}
}
if len(address) > 0 {
_, _, err := net.SplitHostPort(address)
if err != nil {
return nil, err
}
}
if d.DialerWithLaddr != nil && d.Dialer != nil {
return nil, fmt.Errorf("both DialerWithLaddr and Dialer are defined, only one dialer can be used")
}
if d.Dialer != nil {
d.DialerWithLaddr = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) {
if laddr != "" {
return nil, errUnsupportedLaddr
}
return d.Dialer(ctx, network, raddr)
}
} else if d.DialerWithLaddr == nil {
// custom dialer is not set, use default
d.DialerWithLaddr = func(ctx context.Context, network, laddr, raddr string) (net.Conn, error) {
defaultDialer := net.Dialer{}
localAddr, err := resolveAddr(network, laddr)
if err != nil {
return nil, fmt.Errorf("error resolving laddr: %v", err)
}
defaultDialer.LocalAddr = localAddr
return defaultDialer.DialContext(ctx, network, raddr)
}
}
if !d.SplitFlows {
if !d.DarkDecoy {
flow, err := makeTdFlow(flowBidirectional, nil, address)
if err != nil {
return nil, err
}
flow.tdRaw.Dialer = d.Dialer
flow.tdRaw.useProxyHeader = d.UseProxyHeader
return flow, flow.DialContext(ctx)
}
// Conjure
var cjSession *ConjureSession
transport := d.TransportConfig
var err error
if d.TransportConfig == nil {
transport, err = transports.ConfigFromTransportType(d.Transport, randomizePortDefault)
}
if err != nil {
return nil, err
}
// If specified, only select a phantom from a given range
if d.PhantomNet != "" {
_, phantomRange, err := net.ParseCIDR(d.PhantomNet)
if err != nil {
return nil, errors.New("Invalid Phantom network goal")
}
cjSession = FindConjureSessionInRange(address, d.TransportConfig, phantomRange)
if cjSession == nil {
return nil, errors.New("Failed to find Phantom in target subnet")
}
} else {
cjSession = MakeConjureSession(address, transport)
}
cjSession.Dialer = d.DialerWithLaddr
cjSession.UseProxyHeader = d.UseProxyHeader
cjSession.DisableRegistrarOverrides = d.DisableRegistrarOverrides
cjSession.RegDelay = d.RegDelay
if d.V6Support {
cjSession.V6Support = &V6{include: both, support: true}
} else {
cjSession.V6Support = &V6{include: v4, support: false}
}
if len(address) == 0 {
return nil, errors.New("Dark Decoys require target address to be set")
}
return DialConjure(ctx, cjSession, d.DarkDecoyRegistrar, d.RegisterOnly)
}
return nil, errors.New("SplitFlows are not supported")
}
// DialProxy establishes direct connection to TapDance station proxy.
// Users are expected to send HTTP CONNECT request next.
func (d *Dialer) DialProxy() (net.Conn, error) {
return d.DialProxyContext(context.Background())
}
// DialProxyContext establishes direct connection to TapDance station proxy using the provided context.
// Users are expected to send HTTP CONNECT request next.
func (d *Dialer) DialProxyContext(ctx context.Context) (net.Conn, error) {
return d.DialContext(ctx, "tcp", "")
}
func resolveAddr(network, addrStr string) (net.Addr, error) {
if addrStr == "" {
return nil, nil
}
if strings.Contains(network, "tcp") {
return net.ResolveTCPAddr(network, addrStr)
}
return net.ResolveUDPAddr(network, addrStr)
}
var errUnsupportedLaddr = fmt.Errorf("dialer does not support laddr")