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

Can correctly accept faketls messages

tags/v2.0.0-rc1
9seconds 5 лет назад
Родитель
Сommit
4a2d1df384

+ 8
- 7
mtglib/init.go Просмотреть файл

@@ -9,13 +9,14 @@ import (
9 9
 )
10 10
 
11 11
 var (
12
-	ErrSecretEmpty                 = errors.New("secret is empty")
13
-	ErrSecretInvalid               = errors.New("secret is invalid")
14
-	ErrNetworkIsNotDefined         = errors.New("network is not defined")
15
-	ErrAntiReplayCacheIsNotDefined = errors.New("anti-replay cache is not defined")
16
-	ErrIPBlocklistIsNotDefined     = errors.New("ip blocklist is not defined")
17
-	ErrEventStreamIsNotDefined     = errors.New("event stream is not defined")
18
-	ErrLoggerIsNotDefined          = errors.New("logger is not defined")
12
+	ErrSecretEmpty                    = errors.New("secret is empty")
13
+	ErrSecretInvalid                  = errors.New("secret is invalid")
14
+	ErrNetworkIsNotDefined            = errors.New("network is not defined")
15
+	ErrAntiReplayCacheIsNotDefined    = errors.New("anti-replay cache is not defined")
16
+	ErrTimeAttackDetectorIsNotDefined = errors.New("time attack detector is not defined")
17
+	ErrIPBlocklistIsNotDefined        = errors.New("ip blocklist is not defined")
18
+	ErrEventStreamIsNotDefined        = errors.New("event stream is not defined")
19
+	ErrLoggerIsNotDefined             = errors.New("logger is not defined")
19 20
 )
20 21
 
21 22
 const (

+ 67
- 0
mtglib/internal/faketls/clienthello/clienthello.go Просмотреть файл

@@ -0,0 +1,67 @@
1
+package clienthello
2
+
3
+import (
4
+	"crypto/hmac"
5
+	"crypto/sha256"
6
+	"encoding/binary"
7
+	"fmt"
8
+	"time"
9
+
10
+	"github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
11
+)
12
+
13
+type ClientHello struct {
14
+	Time      time.Time
15
+	Digest    [RandomLen]byte
16
+	SessionID []byte
17
+}
18
+
19
+func ParseHandshake(secret, handshake []byte) (ClientHello, error) {
20
+	hello := ClientHello{}
21
+
22
+	if len(handshake) < MinLen {
23
+		return hello, fmt.Errorf("lengh of handshake is too small: %d", len(handshake))
24
+	}
25
+
26
+	if handshake[0] != HandshakeTypeClient {
27
+		return hello, fmt.Errorf("unknown handshake type %#x", handshake[0])
28
+	}
29
+
30
+	copy(hello.Digest[:], handshake[RandomOffset:])
31
+
32
+	for i := RandomOffset; i < RandomOffset+RandomLen; i++ {
33
+		handshake[i] = 0
34
+	}
35
+
36
+	rec := record.AcquireRecord()
37
+	defer record.ReleaseRecord(rec)
38
+
39
+	rec.Type = record.TypeHandshake
40
+	rec.Version = record.Version10
41
+	rec.Payload.Write(handshake)
42
+
43
+	// mac is calculated for the whole record, not only
44
+	// for the payload part
45
+	mac := hmac.New(sha256.New, secret)
46
+	rec.Dump(mac)
47
+
48
+	computedDigest := mac.Sum(nil)
49
+
50
+	for i := 0; i < RandomLen; i++ {
51
+		computedDigest[i] ^= hello.Digest[i]
52
+	}
53
+
54
+	for i := 0; i < RandomLen-4; i++ {
55
+		if computedDigest[i] != 0 {
56
+			return hello, ErrBadDigest
57
+		}
58
+	}
59
+
60
+	timestamp := int64(binary.LittleEndian.Uint32(computedDigest[RandomLen-4:]))
61
+	hello.Time = time.Unix(timestamp, 0)
62
+
63
+	hello.SessionID = make([]byte, handshake[SessionIDOffset])
64
+	copy(hello.SessionID, handshake[SessionIDOffset+1:])
65
+
66
+	return hello, nil
67
+}

+ 17
- 0
mtglib/internal/faketls/clienthello/init.go Просмотреть файл

@@ -0,0 +1,17 @@
1
+package clienthello
2
+
3
+import "errors"
4
+
5
+const (
6
+	RandomLen       = 32
7
+	RandomOffset    = 6
8
+	SessionIDOffset = RandomOffset + RandomLen
9
+	MinLen          = SessionIDOffset + 1
10
+
11
+	HandshakeTypeClient = 0x01
12
+)
13
+
14
+var (
15
+	ErrBadDigest        = errors.New("bad digest")
16
+	ErrAntiReplayAttack = errors.New("antireplay attack was detected")
17
+)

+ 66
- 0
mtglib/internal/faketls/record/init.go Просмотреть файл

@@ -0,0 +1,66 @@
1
+package record
2
+
3
+import "fmt"
4
+
5
+type Type uint8
6
+
7
+const (
8
+	TypeChangeCipherSpec Type = 0x14
9
+	TypeHandshake        Type = 0x16
10
+	TypeApplicationData  Type = 0x17
11
+)
12
+
13
+func (t Type) String() string {
14
+	switch t {
15
+	case TypeChangeCipherSpec:
16
+		return "changeCipher(0x14)"
17
+	case TypeHandshake:
18
+		return "handshake(0x16)"
19
+	case TypeApplicationData:
20
+		return "applicationData(0x17)"
21
+	}
22
+
23
+	return fmt.Sprintf("unknown(%#x)", byte(t))
24
+}
25
+
26
+func (t Type) Valid() error {
27
+	switch t {
28
+	case TypeChangeCipherSpec, TypeHandshake, TypeApplicationData:
29
+		return nil
30
+	}
31
+
32
+	return fmt.Errorf("unknown type %#x", byte(t))
33
+}
34
+
35
+type Version uint16
36
+
37
+const (
38
+	Version10 Version = 769 // 0x03 0x01
39
+	Version11 Version = 770 // 0x03 0x02
40
+	Version12 Version = 771 // 0x03 0x03
41
+	Version13 Version = 772 // 0x03 0x04
42
+)
43
+
44
+func (v Version) String() string {
45
+	switch v {
46
+	case Version10:
47
+		return "tls1.0"
48
+	case Version11:
49
+		return "tls1.1"
50
+	case Version12:
51
+		return "tls1.2"
52
+	case Version13:
53
+		return "tls1.3"
54
+	}
55
+
56
+	return fmt.Sprintf("tls(%d)", uint16(v))
57
+}
58
+
59
+func (v Version) Valid() error {
60
+	switch v {
61
+	case Version10, Version11, Version12, Version13:
62
+		return nil
63
+	}
64
+
65
+	return fmt.Errorf("unknown version %d", uint16(v))
66
+}

+ 18
- 0
mtglib/internal/faketls/record/pools.go Просмотреть файл

@@ -0,0 +1,18 @@
1
+package record
2
+
3
+import "sync"
4
+
5
+var recordPool = sync.Pool{
6
+	New: func() interface{} {
7
+		return &Record{}
8
+	},
9
+}
10
+
11
+func AcquireRecord() *Record {
12
+	return recordPool.Get().(*Record)
13
+}
14
+
15
+func ReleaseRecord(r *Record) {
16
+	r.Reset()
17
+	recordPool.Put(r)
18
+}

+ 87
- 0
mtglib/internal/faketls/record/record.go Просмотреть файл

@@ -0,0 +1,87 @@
1
+package record
2
+
3
+import (
4
+	"bytes"
5
+	"encoding/base64"
6
+	"encoding/binary"
7
+	"fmt"
8
+	"io"
9
+)
10
+
11
+type Record struct {
12
+	Type    Type
13
+	Version Version
14
+	Payload bytes.Buffer
15
+}
16
+
17
+func (r *Record) String() string {
18
+	return fmt.Sprintf("<tlsRecord(type=%v, version=%v, payload=%s)>",
19
+		r.Type,
20
+		r.Version,
21
+		base64.StdEncoding.EncodeToString(r.Payload.Bytes()))
22
+}
23
+
24
+func (r *Record) Reset() {
25
+	r.Payload.Reset()
26
+}
27
+
28
+func (r *Record) Read(reader io.Reader) error {
29
+	r.Reset()
30
+
31
+	buf := [2]byte{}
32
+
33
+	if _, err := io.ReadFull(reader, buf[:1]); err != nil {
34
+		return fmt.Errorf("cannot read type: %w", err)
35
+	}
36
+
37
+	r.Type = Type(buf[0])
38
+	if err := r.Type.Valid(); err != nil {
39
+		return fmt.Errorf("invalid type: %w", err)
40
+	}
41
+
42
+	if _, err := io.ReadFull(reader, buf[:]); err != nil {
43
+		return fmt.Errorf("cannot read version: %w", err)
44
+	}
45
+
46
+	r.Version = Version(binary.BigEndian.Uint16(buf[:]))
47
+	if err := r.Version.Valid(); err != nil {
48
+		return fmt.Errorf("invalid version: %w", err)
49
+	}
50
+
51
+	if _, err := io.ReadFull(reader, buf[:]); err != nil {
52
+		return fmt.Errorf("cannot read payload length: %w", err)
53
+	}
54
+
55
+	length := int64(binary.BigEndian.Uint16(buf[:]))
56
+	if _, err := io.CopyN(&r.Payload, reader, length); err != nil {
57
+		return fmt.Errorf("cannot read payload: %w", err)
58
+	}
59
+
60
+	return nil
61
+}
62
+
63
+func (r *Record) Dump(writer io.Writer) error {
64
+	buf := [2]byte{byte(r.Type), 0}
65
+
66
+	if _, err := writer.Write(buf[:1]); err != nil {
67
+		return fmt.Errorf("cannot dump type: %w", err)
68
+	}
69
+
70
+	binary.BigEndian.PutUint16(buf[:], uint16(r.Version))
71
+
72
+	if _, err := writer.Write(buf[:]); err != nil {
73
+		return fmt.Errorf("cannot dump version: %w", err)
74
+	}
75
+
76
+	binary.BigEndian.PutUint16(buf[:], uint16(r.Payload.Len()))
77
+
78
+	if _, err := writer.Write(buf[:]); err != nil {
79
+		return fmt.Errorf("cannot dump payload length: %w", err)
80
+	}
81
+
82
+	if _, err := writer.Write(r.Payload.Bytes()); err != nil {
83
+		return fmt.Errorf("cannot dump payload: %w", err)
84
+	}
85
+
86
+	return nil
87
+}

+ 42
- 15
mtglib/proxy.go Просмотреть файл

@@ -8,6 +8,8 @@ import (
8 8
 	"sync"
9 9
 	"time"
10 10
 
11
+	"github.com/9seconds/mtg/v2/mtglib/internal/faketls/clienthello"
12
+	"github.com/9seconds/mtg/v2/mtglib/internal/faketls/record"
11 13
 	"github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2"
12 14
 	"github.com/9seconds/mtg/v2/mtglib/internal/relay"
13 15
 	"github.com/9seconds/mtg/v2/mtglib/internal/telegram"
@@ -24,11 +26,12 @@ type Proxy struct {
24 26
 	workerPool  *ants.PoolWithFunc
25 27
 	telegram    *telegram.Telegram
26 28
 
27
-	secret          Secret
28
-	antiReplayCache AntiReplayCache
29
-	ipBlocklist     IPBlocklist
30
-	eventStream     EventStream
31
-	logger          Logger
29
+	secret             Secret
30
+	antiReplayCache    AntiReplayCache
31
+	timeAttackDetector TimeAttackDetector
32
+	ipBlocklist        IPBlocklist
33
+	eventStream        EventStream
34
+	logger             Logger
32 35
 }
33 36
 
34 37
 func (p *Proxy) ServeConn(conn net.Conn) {
@@ -55,6 +58,12 @@ func (p *Proxy) ServeConn(conn net.Conn) {
55 58
 		ctx.logger.Info("Stream has been finished")
56 59
 	}()
57 60
 
61
+	if err := p.doFakeTLSHandshake(ctx); err != nil {
62
+		p.logger.InfoError("faketls handshake is failed", err)
63
+
64
+		return
65
+	}
66
+
58 67
 	if err := p.doObfuscated2Handshake(ctx); err != nil {
59 68
 		p.logger.InfoError("obfuscated2 handshake is failed", err)
60 69
 
@@ -112,6 +121,21 @@ func (p *Proxy) Shutdown() {
112 121
 	p.workerPool.Release()
113 122
 }
114 123
 
124
+func (p *Proxy) doFakeTLSHandshake(ctx *streamContext) error {
125
+	clientHelloRecord := record.AcquireRecord()
126
+	defer record.ReleaseRecord(clientHelloRecord)
127
+
128
+	if err := clientHelloRecord.Read(ctx.clientConn); err != nil {
129
+		return fmt.Errorf("cannot read client hello: %w", err)
130
+	}
131
+
132
+	hello, _ := clienthello.ParseHandshake(p.secret.Key[:],
133
+		clientHelloRecord.Payload.Bytes())
134
+	fmt.Println(hello)
135
+
136
+	return fmt.Errorf("SUCCESS")
137
+}
138
+
115 139
 func (p *Proxy) doObfuscated2Handshake(ctx *streamContext) error {
116 140
 	dc, encryptor, decryptor, err := obfuscated2.ClientHandshake(p.secret.Key[:], ctx.clientConn)
117 141
 	if err != nil {
@@ -173,6 +197,8 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { // nolint: cyclop
173 197
 		return nil, ErrIPBlocklistIsNotDefined
174 198
 	case opts.EventStream == nil:
175 199
 		return nil, ErrEventStreamIsNotDefined
200
+	case opts.TimeAttackDetector == nil:
201
+		return nil, ErrTimeAttackDetectorIsNotDefined
176 202
 	case opts.Logger == nil:
177 203
 		return nil, ErrLoggerIsNotDefined
178 204
 	case !opts.Secret.Valid():
@@ -201,16 +227,17 @@ func NewProxy(opts ProxyOpts) (*Proxy, error) { // nolint: cyclop
201 227
 
202 228
 	ctx, cancel := context.WithCancel(context.Background())
203 229
 	proxy := &Proxy{
204
-		ctx:             ctx,
205
-		ctxCancel:       cancel,
206
-		secret:          opts.Secret,
207
-		antiReplayCache: opts.AntiReplayCache,
208
-		ipBlocklist:     opts.IPBlocklist,
209
-		eventStream:     opts.EventStream,
210
-		logger:          opts.Logger.Named("proxy"),
211
-		idleTimeout:     idleTimeout,
212
-		bufferSize:      int(bufferSize),
213
-		telegram:        tg,
230
+		ctx:                ctx,
231
+		ctxCancel:          cancel,
232
+		secret:             opts.Secret,
233
+		antiReplayCache:    opts.AntiReplayCache,
234
+		timeAttackDetector: opts.TimeAttackDetector,
235
+		ipBlocklist:        opts.IPBlocklist,
236
+		eventStream:        opts.EventStream,
237
+		logger:             opts.Logger.Named("proxy"),
238
+		idleTimeout:        idleTimeout,
239
+		bufferSize:         int(bufferSize),
240
+		telegram:           tg,
214 241
 	}
215 242
 
216 243
 	pool, err := ants.NewPoolWithFunc(int(concurrency), func(arg interface{}) {

Загрузка…
Отмена
Сохранить