Skip to content

Commit cdfbdbc

Browse files
committed
decoy-registrar: move Send() to registrars/
1 parent 3198263 commit cdfbdbc

File tree

2 files changed

+249
-155
lines changed

2 files changed

+249
-155
lines changed

pkg/registrars/decoy-registrar/decoy-registrar.go

Lines changed: 71 additions & 155 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,12 @@ import (
99

1010
"github.com/refraction-networking/conjure/pkg/registrars/lib"
1111
pb "github.com/refraction-networking/conjure/proto"
12-
"github.com/refraction-networking/gotapdance/tapdance"
12+
tls "github.com/refraction-networking/utls"
1313

14-
// td imports assets/
14+
// td imports assets/RegError/generateHTTPRequestBeginning
1515
td "github.com/refraction-networking/gotapdance/tapdance"
16-
tls "github.com/refraction-networking/utls"
16+
1717
"github.com/sirupsen/logrus"
18-
"google.golang.org/protobuf/proto"
1918
)
2019

2120
/**
@@ -30,6 +29,21 @@ const deadlineConnectTDStationMax = 14231
3029
const deadlineTCPtoDecoyMin = deadlineConnectTDStationMin
3130
const deadlineTCPtoDecoyMax = deadlineConnectTDStationMax
3231

32+
// Fixed-Size-Payload has a 1 byte flags field.
33+
// bit 0 (1 << 7) determines if flow is bidirectional(0) or upload-only(1)
34+
// bit 1 (1 << 6) enables dark-decoys
35+
// bits 2-5 are unassigned
36+
// bit 6 determines whether PROXY-protocol-formatted string will be sent
37+
// bit 7 (1 << 0) signals to use TypeLen outer proto
38+
var (
39+
tdFlagUploadOnly = uint8(1 << 7)
40+
// tdFlagDarkDecoy = uint8(1 << 6)
41+
tdFlagProxyHeader = uint8(1 << 1)
42+
tdFlagUseTIL = uint8(1 << 0)
43+
)
44+
45+
var default_flags = tdFlagUseTIL
46+
3347
type DialFunc = func(ctx context.Context, network, addr string) (net.Conn, error)
3448

3549
type DecoyRegistrar struct {
@@ -41,10 +55,8 @@ type DecoyRegistrar struct {
4155
logger logrus.FieldLogger
4256

4357
// Fields taken from ConjureReg struct
44-
m sync.Mutex
45-
stats *pb.SessionStats
46-
sessionIDStr string
47-
covertAddress string
58+
m sync.Mutex
59+
stats *pb.SessionStats
4860
}
4961

5062
// CurrentClientLibraryVersion returns the current client library version used
@@ -71,61 +83,6 @@ func currentClientLibraryVersion() uint32 {
7183
// return 0
7284
}
7385

74-
// RegError - Registration Error passed during registration to indicate failure mode
75-
type RegError struct {
76-
code uint
77-
msg string
78-
}
79-
80-
func NewRegError(code uint, msg string) RegError {
81-
return RegError{code: code, msg: msg}
82-
}
83-
84-
func (err RegError) Error() string {
85-
return fmt.Sprintf("Registration Error [%v]: %v", err.CodeStr(), err.msg)
86-
}
87-
88-
func (err RegError) Code() uint {
89-
return err.code
90-
}
91-
92-
// CodeStr - Get desctriptor associated with error code
93-
func (err RegError) CodeStr() string {
94-
switch err.code {
95-
case Unreachable:
96-
return "UNREACHABLE"
97-
case DialFailure:
98-
return "DIAL_FAILURE"
99-
case NotImplemented:
100-
return "NOT_IMPLEMENTED"
101-
case TLSError:
102-
return "TLS_ERROR"
103-
default:
104-
return "UNKNOWN"
105-
}
106-
}
107-
108-
const (
109-
// Unreachable -Dial Error Unreachable -- likely network unavailable (i.e. ipv6 error)
110-
Unreachable = iota
111-
112-
// DialFailure - Dial Error Other than unreachable
113-
DialFailure
114-
115-
// NotImplemented - Related Function Not Implemented
116-
NotImplemented
117-
118-
// TLSError (Expired, Wrong-Host, Untrusted-Root, ...)
119-
TLSError
120-
121-
// Unknown - Error occurred without obvious explanation
122-
Unknown
123-
)
124-
125-
func (r *DecoyRegistrar) getPbTransport() pb.TransportType {
126-
return r.Transport.ID()
127-
}
128-
12986
func (r *DecoyRegistrar) setTCPToDecoy(tcprtt *uint32) {
13087
r.m.Lock()
13188
defer r.m.Unlock()
@@ -136,76 +93,49 @@ func (r *DecoyRegistrar) setTCPToDecoy(tcprtt *uint32) {
13693
r.stats.TcpToDecoy = tcprtt
13794
}
13895

139-
func (reg *DecoyRegistrar) setTLSToDecoy(tlsrtt *uint32) {
140-
reg.m.Lock()
141-
defer reg.m.Unlock()
96+
func (r *DecoyRegistrar) setTLSToDecoy(tlsrtt *uint32) {
97+
r.m.Lock()
98+
defer r.m.Unlock()
14299

143-
if reg.stats == nil {
144-
reg.stats = &pb.SessionStats{}
100+
if r.stats == nil {
101+
r.stats = &pb.SessionStats{}
145102
}
146-
reg.stats.TlsToDecoy = tlsrtt
103+
r.stats.TlsToDecoy = tlsrtt
147104
}
148105

149-
func (r *DecoyRegistrar) generateClientToStation() (*pb.ClientToStation, error) {
150-
var covert *string
151-
if len(r.covertAddress) > 0 {
152-
//[TODO]{priority:medium} this isn't the correct place to deal with signaling to the station
153-
//transition = pb.C2S_Transition_C2S_SESSION_COVERT_INIT
154-
covert = &r.covertAddress
155-
}
156-
157-
//[reference] Generate ClientToStation protobuf
158-
// transition := pb.C2S_Transition_C2S_SESSION_INIT
159-
currentGen := td.Assets().GetGeneration()
160-
currentLibVer := currentClientLibraryVersion()
161-
transport := reg.getPbTransport()
162-
transportParams, err := reg.getPbTransportParams()
163-
if err != nil {
164-
// Logger().Debugf("%s failed to marshal transport parameters ", reg.sessionIDStr)
165-
}
166-
167-
// remove type url to save space for DNS registration
168-
// for server side changes see https://github.com/refraction-networking/conjure/pull/163
169-
transportParams.TypeUrl = ""
170-
171-
initProto := &pb.ClientToStation{
172-
ClientLibVersion: &currentLibVer,
173-
CovertAddress: covert,
174-
DecoyListGeneration: &currentGen,
175-
V6Support: reg.getV6Support(),
176-
V4Support: reg.getV4Support(),
177-
Transport: &transport,
178-
Flags: reg.generateFlags(),
179-
TransportParams: transportParams,
180-
181-
DisableRegistrarOverrides: &reg.ConjureSession.DisableRegistrarOverrides,
182-
183-
//[TODO]{priority:medium} specify width in C2S because different width might
184-
// be useful in different regions (constant for now.)
185-
}
106+
func (r *DecoyRegistrar) GetRandomDuration(base, min, max int) time.Duration {
107+
addon := getRandInt(min, max) / 1000 // why this min and max???
108+
rtt := rttInt(r.getTcpToDecoy())
109+
return time.Millisecond * time.Duration(base+rtt*addon)
110+
}
186111

187-
if len(reg.phantomSNI) > 0 {
188-
initProto.MaskedDecoyServerName = &reg.phantomSNI
112+
func (r *DecoyRegistrar) getTcpToDecoy() uint32 {
113+
r.m.Lock()
114+
defer r.m.Unlock()
115+
if r != nil {
116+
if r.stats != nil {
117+
return r.stats.GetTcpToDecoy()
118+
}
189119
}
120+
return 0
121+
}
190122

191-
for (proto.Size(initProto)+AES_GCM_TAG_SIZE)%3 != 0 {
192-
initProto.Padding = append(initProto.Padding, byte(0))
123+
func generateFlags(cjSession *td.ConjureSession) *pb.RegistrationFlags {
124+
flags := &pb.RegistrationFlags{}
125+
mask := default_flags
126+
if cjSession.UseProxyHeader {
127+
mask |= tdFlagProxyHeader
193128
}
194129

195-
return initProto, nil
196-
}
130+
uploadOnly := mask&tdFlagUploadOnly == tdFlagUploadOnly
131+
proxy := mask&tdFlagProxyHeader == tdFlagProxyHeader
132+
til := mask&tdFlagUseTIL == tdFlagUseTIL
197133

198-
func NewDecoyRegistrar() *DecoyRegistrar {
199-
return &DecoyRegistrar{
200-
logger: tapdance.Logger(),
201-
}
202-
}
134+
flags.UploadOnly = &uploadOnly
135+
flags.ProxyHeader = &proxy
136+
flags.Use_TIL = &til
203137

204-
func NewDecoyRegistrarWithDialer(dialer DialFunc) *DecoyRegistrar {
205-
return &DecoyRegistrar{
206-
dialContex: dialer,
207-
logger: tapdance.Logger(),
208-
}
138+
return flags
209139
}
210140

211141
func (r DecoyRegistrar) createTLSConn(dialConn net.Conn, address string, hostname string, deadline time.Time) (*tls.UConn, error) {
@@ -241,39 +171,31 @@ func (r DecoyRegistrar) createTLSConn(dialConn net.Conn, address string, hostnam
241171
return tlsConn, nil
242172
}
243173

244-
func generateVSP() ([]byte, error) {
245-
c2s, err := reg.generateClientToStation()
246-
if err != nil {
247-
return nil, err
248-
}
249-
250-
//[reference] Marshal ClientToStation protobuf
251-
return proto.Marshal(c2s)
252-
}
174+
// Register -> Send -> createRequest -> generateVSP -> generateClientToStation
253175

254-
func (r *DecoyRegistrar) createRequest(tlsConn *tls.UConn, decoy *pb.TLSDecoySpec) ([]byte, error) {
176+
func (r *DecoyRegistrar) createRequest(tlsConn *tls.UConn, decoy *pb.TLSDecoySpec, cjSession *td.ConjureSession) ([]byte, error) {
255177
//[reference] generate and encrypt variable size payload
256-
vsp, err := reg.generateVSP()
178+
vsp, err := generateVSP(cjSession)
257179
if err != nil {
258180
return nil, err
259181
}
260182
if len(vsp) > int(^uint16(0)) {
261183
return nil, fmt.Errorf("Variable-Size Payload exceeds %v", ^uint16(0))
262184
}
263-
encryptedVsp, err := aesGcmEncrypt(vsp, reg.keys.VspKey, reg.keys.VspIv)
185+
encryptedVsp, err := aesGcmEncrypt(vsp, cjSession.Keys.VspKey, cjSession.Keys.VspIv)
264186
if err != nil {
265187
return nil, err
266188
}
267189

268190
//[reference] generate and encrypt fixed size payload
269-
fsp := reg.generateFSP(uint16(len(encryptedVsp)))
270-
encryptedFsp, err := aesGcmEncrypt(fsp, reg.keys.FspKey, reg.keys.FspIv)
191+
fsp := generateFSP(uint16(len(encryptedVsp)))
192+
encryptedFsp, err := aesGcmEncrypt(fsp, cjSession.Keys.FspKey, cjSession.Keys.FspIv)
271193
if err != nil {
272194
return nil, err
273195
}
274196

275197
var tag []byte // tag will be base-64 style encoded
276-
tag = append(encryptedVsp, reg.keys.Representative...)
198+
tag = append(encryptedVsp, cjSession.Keys.Representative...)
277199
tag = append(tag, encryptedFsp...)
278200

279201
httpRequest := generateHTTPRequestBeginning(decoy.GetHostname())
@@ -289,7 +211,7 @@ func (r *DecoyRegistrar) createRequest(tlsConn *tls.UConn, decoy *pb.TLSDecoySpe
289211
return httpRequest, nil
290212
}
291213

292-
func (r DecoyRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context.Context) (*tapdance.ConjureReg, error) {
214+
func (r DecoyRegistrar) Register(cjSession *td.ConjureSession, ctx context.Context) (*td.ConjureReg, error) {
293215
logger := r.logger.WithFields(logrus.Fields{"type": "unidirectional", "sessionID": cjSession.IDString()})
294216

295217
logger.Debugf("Registering V4 and V6 via DecoyRegistrar")
@@ -326,15 +248,15 @@ func (r DecoyRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context
326248
for _, decoy := range decoys {
327249
logger.Debugf("Sending Reg: %v, %v", decoy.GetHostname(), decoy.GetIpAddrStr())
328250
//decoyAddr := decoy.GetIpAddrStr()
329-
go r.Send(ctx, reg, decoy, dialErrors)
251+
go r.Send(ctx, cjSession, decoy, dialErrors)
330252
}
331253

332254
//[reference] Dial errors happen immediately so block until all N dials complete
333255
var unreachableCount uint = 0
334256
for err := range dialErrors {
335257
if err != nil {
336258
logger.Debugf("%v", err)
337-
if dialErr, ok := err.(tapdance.RegError); ok && dialErr.Code() == tapdance.Unreachable {
259+
if dialErr, ok := err.(td.RegError); ok && dialErr.Code() == td.Unreachable {
338260
// If we failed because ipv6 network was unreachable try v4 only.
339261
unreachableCount++
340262
if unreachableCount < width {
@@ -351,18 +273,19 @@ func (r DecoyRegistrar) Register(cjSession *tapdance.ConjureSession, ctx context
351273
//[reference] if ALL fail to dial return error (retry in parent if ipv6 unreachable)
352274
if unreachableCount == width {
353275
logger.Debugf("NETWORK UNREACHABLE")
354-
return nil, tapdance.NewRegError(tapdance.Unreachable, "All decoys failed to register -- Dial Unreachable")
276+
return nil, td.NewRegError(td.Unreachable, "All decoys failed to register -- Dial Unreachable")
355277
}
356278

357279
// randomized sleeping here to break the intraflow signal
358-
toSleep := reg.GetRandomDuration(3000, 212, 3449)
280+
// TODO: is this okay?
281+
toSleep := r.GetRandomDuration(3000, 212, 3449)
359282
logger.Debugf("Successfully sent registrations, sleeping for: %v", toSleep)
360283
lib.SleepWithContext(ctx, toSleep)
361284

362285
return reg, nil
363286
}
364287

365-
func (r *DecoyRegistrar) Send(ctx context.Context, reg *tapdance.ConjureReg, decoy *pb.TLSDecoySpec, dialError chan error) {
288+
func (r *DecoyRegistrar) Send(ctx context.Context, cjSession *td.ConjureSession, decoy *pb.TLSDecoySpec, dialError chan error) {
366289

367290
deadline, deadlineAlreadySet := ctx.Deadline()
368291
if !deadlineAlreadySet {
@@ -380,7 +303,7 @@ func (r *DecoyRegistrar) Send(ctx context.Context, reg *tapdance.ConjureReg, dec
380303
r.setTCPToDecoy(durationToU32ptrMs(time.Since(tcpToDecoyStartTs)))
381304
if err != nil {
382305
if opErr, ok := err.(*net.OpError); ok && opErr.Err.Error() == "connect: network is unreachable" {
383-
dialError <- RegError{msg: err.Error(), code: Unreachable}
306+
dialError <- td.NewRegError(td.Unreachable, err.Error())
384307
return
385308
}
386309
dialError <- err
@@ -397,16 +320,16 @@ func (r *DecoyRegistrar) Send(ctx context.Context, reg *tapdance.ConjureReg, dec
397320
if err != nil {
398321
dialConn.Close()
399322
msg := fmt.Sprintf("%v - %v createConn: %v", decoy.GetHostname(), decoy.GetIpAddrStr(), err.Error())
400-
dialError <- RegError{msg: msg, code: TLSError}
323+
dialError <- td.NewRegError(td.TLSError, msg)
401324
return
402325
}
403326
r.setTLSToDecoy(durationToU32ptrMs(time.Since(tlsToDecoyStartTs)))
404327

405328
//[reference] Create the HTTP request for the registration
406-
httpRequest, err := reg.createRequest(tlsConn, decoy)
329+
httpRequest, err := r.createRequest(tlsConn, decoy, cjSession)
407330
if err != nil {
408331
msg := fmt.Sprintf("%v - %v createReq: %v", decoy.GetHostname(), decoy.GetIpAddrStr(), err.Error())
409-
dialError <- RegError{msg: msg, code: TLSError}
332+
dialError <- td.NewRegError(td.TLSError, msg)
410333
return
411334
}
412335

@@ -417,17 +340,10 @@ func (r *DecoyRegistrar) Send(ctx context.Context, reg *tapdance.ConjureReg, dec
417340
// Logger().Errorf("%v - %v Could not send Conjure registration request, error: %v", decoy.GetHostname(), decoy.GetIpAddrStr(), err.Error())
418341
tlsConn.Close()
419342
msg := fmt.Sprintf("%v - %v Write: %v", decoy.GetHostname(), decoy.GetIpAddrStr(), err.Error())
420-
dialError <- RegError{msg: msg, code: TLSError}
343+
dialError <- td.NewRegError(td.TLSError, msg)
421344
return
422345
}
423346

424347
dialError <- nil
425348
readAndClose(dialConn, time.Second*15)
426349
}
427-
428-
// Move to other file eventually?
429-
func GetRandomDuration(base, min, max int) time.Duration {
430-
addon := getRandInt(min, max) / 1000 // why this min and max???
431-
rtt := rttInt(reg.getTcpToDecoy())
432-
return time.Millisecond * time.Duration(base+rtt*addon)
433-
}

0 commit comments

Comments
 (0)