浏览代码

Working version

tags/0.9
9seconds 8 年前
父节点
当前提交
11810253ff
共有 12 个文件被更改,包括 808 次插入8 次删除
  1. 56
    1
      Gopkg.lock
  2. 12
    0
      Gopkg.toml
  3. 23
    7
      main.go
  4. 109
    0
      obfuscated2/frame.go
  5. 83
    0
      obfuscated2/frame_test.go
  6. 79
    0
      obfuscated2/obfuscated2.go
  7. 79
    0
      obfuscated2/obfuscated2_test.go
  8. 52
    0
      server/cipherrwc.go
  9. 52
    0
      server/ctxrwc.go
  10. 41
    0
      server/logrwc.go
  11. 184
    0
      server/server.go
  12. 38
    0
      server/telegram.go

+ 56
- 1
Gopkg.lock 查看文件

@@ -16,6 +16,61 @@
16 16
   packages = ["."]
17 17
   revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a"
18 18
 
19
+[[projects]]
20
+  name = "github.com/davecgh/go-spew"
21
+  packages = ["spew"]
22
+  revision = "346938d642f2ec3594ed81d874461961cd0faa76"
23
+  version = "v1.1.0"
24
+
25
+[[projects]]
26
+  branch = "master"
27
+  name = "github.com/juju/errors"
28
+  packages = ["."]
29
+  revision = "c7d06af17c68cd34c835053720b21f6549d9b0ee"
30
+
31
+[[projects]]
32
+  name = "github.com/pmezard/go-difflib"
33
+  packages = ["difflib"]
34
+  revision = "792786c7400a136282c1664665ae0a8db921c6c2"
35
+  version = "v1.0.0"
36
+
37
+[[projects]]
38
+  name = "github.com/satori/go.uuid"
39
+  packages = ["."]
40
+  revision = "f58768cc1a7a7e77a3bd49e98cdd21419399b6a3"
41
+  version = "v1.2.0"
42
+
43
+[[projects]]
44
+  name = "github.com/stretchr/testify"
45
+  packages = ["assert"]
46
+  revision = "12b6f73e6084dad08a7c6e575284b177ecafbc71"
47
+  version = "v1.2.1"
48
+
49
+[[projects]]
50
+  name = "go.uber.org/atomic"
51
+  packages = ["."]
52
+  revision = "1ea20fb1cbb1cc08cbd0d913a96dead89aa18289"
53
+  version = "v1.3.2"
54
+
55
+[[projects]]
56
+  name = "go.uber.org/multierr"
57
+  packages = ["."]
58
+  revision = "3c4937480c32f4c13a875a1829af76c98ca3d40a"
59
+  version = "v1.1.0"
60
+
61
+[[projects]]
62
+  name = "go.uber.org/zap"
63
+  packages = [
64
+    ".",
65
+    "buffer",
66
+    "internal/bufferpool",
67
+    "internal/color",
68
+    "internal/exit",
69
+    "zapcore"
70
+  ]
71
+  revision = "eeedf312bc6c57391d84767a4cd413f02a917974"
72
+  version = "v1.8.0"
73
+
19 74
 [[projects]]
20 75
   name = "gopkg.in/alecthomas/kingpin.v2"
21 76
   packages = ["."]
@@ -25,6 +80,6 @@
25 80
 [solve-meta]
26 81
   analyzer-name = "dep"
27 82
   analyzer-version = 1
28
-  inputs-digest = "9b3ace12d2b928915476e7d30a29e7e37e0a9d569b37ad070fb0b2d0e06fc088"
83
+  inputs-digest = "36bcaf7701d70b8c4648e01a7fc94e0cda9c2f9b48c42d453c87567f6f058036"
29 84
   solver-name = "gps-cdcl"
30 85
   solver-version = 1

+ 12
- 0
Gopkg.toml 查看文件

@@ -32,3 +32,15 @@
32 32
 [[constraint]]
33 33
   name = "gopkg.in/alecthomas/kingpin.v2"
34 34
   version = "2.2.6"
35
+
36
+[[constraint]]
37
+  branch = "master"
38
+  name = "github.com/juju/errors"
39
+
40
+[[constraint]]
41
+  name = "github.com/stretchr/testify"
42
+  version = "1.2.1"
43
+
44
+[[constraint]]
45
+  name = "github.com/satori/go.uuid"
46
+  version = "1.2.0"

+ 23
- 7
main.go 查看文件

@@ -1,17 +1,21 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"encoding/hex"
4 5
 	"fmt"
5 6
 	"io"
6 7
 	"io/ioutil"
7 8
 	"net/http"
8 9
 	"net/url"
9 10
 	"os"
10
-	"regexp"
11 11
 	"strconv"
12 12
 	"strings"
13 13
 
14
+	"go.uber.org/zap"
15
+	"go.uber.org/zap/zapcore"
14 16
 	kingpin "gopkg.in/alecthomas/kingpin.v2"
17
+
18
+	"github.com/9seconds/mtg/server"
15 19
 )
16 20
 
17 21
 var (
@@ -43,7 +47,8 @@ var (
43 47
 func main() {
44 48
 	kingpin.MustParse(app.Parse(os.Args[1:]))
45 49
 
46
-	if matched, err := regexp.MatchString("[a-fA-F0-9]+", *secret); !matched || err != nil {
50
+	secretBytes, err := hex.DecodeString(*secret)
51
+	if err != nil {
47 52
 		usage("Secret has to be hexadecimal string.")
48 53
 	}
49 54
 
@@ -61,8 +66,23 @@ func main() {
61 66
 		*serverName = strings.TrimSpace(string(myIPBytes))
62 67
 	}
63 68
 
69
+	atom := zap.NewAtomicLevel()
70
+	if *debug {
71
+		atom.SetLevel(zapcore.DebugLevel)
72
+	} else {
73
+		atom.SetLevel(zapcore.ErrorLevel)
74
+	}
75
+	encoderCfg := zap.NewProductionEncoderConfig()
76
+	logger := zap.New(zapcore.NewCore(
77
+		zapcore.NewJSONEncoder(encoderCfg),
78
+		zapcore.Lock(os.Stderr),
79
+		atom,
80
+	)).Sugar()
81
+
64 82
 	printURLs()
65
-	serve()
83
+	if err := server.NewServer(*bindIP, int(*bindPort), secretBytes, logger).Serve(); err != nil {
84
+		logger.Fatal(err.Error())
85
+	}
66 86
 }
67 87
 
68 88
 func usage(msg string) {
@@ -88,7 +108,3 @@ func printURLs() {
88 108
 	tgURL.Path = "proxy"
89 109
 	fmt.Println(tgURL.String())
90 110
 }
91
-
92
-func serve() {
93
-
94
-}

+ 109
- 0
obfuscated2/frame.go 查看文件

@@ -0,0 +1,109 @@
1
+package obfuscated2
2
+
3
+import (
4
+	"bytes"
5
+	"crypto/rand"
6
+	"encoding/binary"
7
+	"io"
8
+
9
+	"github.com/juju/errors"
10
+)
11
+
12
+// https://blog.susanka.eu/how-telegram-obfuscates-its-mtproto-traffic/
13
+// [frameOffsetFirst:frameOffsetKey:frameOffsetIV:frameOffsetMagic:frameOffsetDC:frameOffsetEnd]
14
+const (
15
+	frameLenKey   = 32
16
+	frameLenIV    = 16
17
+	frameLenMagic = 4
18
+	frameLenDC    = 2
19
+
20
+	frameOffsetFirst = 8
21
+	frameOffsetKey   = frameOffsetFirst + frameLenKey
22
+	frameOffsetIV    = frameOffsetKey + frameLenIV
23
+	frameOffsetMagic = frameOffsetIV + frameLenMagic
24
+	frameOffsetDC    = frameOffsetMagic + frameLenDC
25
+
26
+	tgMagicByte = byte(239)
27
+
28
+	FrameLen = 64
29
+)
30
+
31
+var tgMagicBytes = []byte{tgMagicByte, tgMagicByte, tgMagicByte, tgMagicByte}
32
+
33
+type Frame []byte
34
+
35
+func (f Frame) Key() []byte {
36
+	return f[frameOffsetFirst:frameOffsetKey]
37
+}
38
+
39
+func (f Frame) IV() []byte {
40
+	return f[frameOffsetKey:frameOffsetIV]
41
+}
42
+
43
+func (f Frame) Magic() []byte {
44
+	return f[frameOffsetIV:frameOffsetMagic]
45
+}
46
+
47
+func (f Frame) DC() (n int16) {
48
+	buf := bytes.NewReader(f[frameOffsetMagic:frameOffsetDC])
49
+	binary.Read(buf, binary.LittleEndian, &n)
50
+
51
+	if n < 0 {
52
+		n = -n
53
+	} else if n == 0 {
54
+		n = 1
55
+	}
56
+
57
+	return n - 1
58
+}
59
+
60
+func (f Frame) Valid() bool {
61
+	return bytes.Equal(f.Magic(), tgMagicBytes)
62
+}
63
+
64
+func (f Frame) Invert() Frame {
65
+	reversed := make(Frame, FrameLen)
66
+	copy(reversed, f)
67
+
68
+	for i := 0; i < frameLenKey+frameLenIV; i++ {
69
+		reversed[frameOffsetFirst+i] = f[frameOffsetIV-1-i]
70
+	}
71
+
72
+	return reversed
73
+}
74
+
75
+func ExtractFrame(conn io.Reader) (Frame, error) {
76
+	buf := &bytes.Buffer{}
77
+	if _, err := io.CopyN(buf, conn, FrameLen); err != nil {
78
+		return nil, errors.Annotate(err, "Cannot extract obfuscated header")
79
+	}
80
+
81
+	return Frame(buf.Bytes()), nil
82
+}
83
+
84
+func generateFrame() Frame {
85
+	data := make(Frame, FrameLen)
86
+
87
+	for {
88
+		if _, err := rand.Read(data); err != nil {
89
+			continue
90
+		}
91
+		if data[0] == 0xef {
92
+			continue
93
+		}
94
+
95
+		val := (uint32(data[3]) << 24) | (uint32(data[2]) << 16) | (uint32(data[1]) << 8) | uint32(data[0])
96
+		if val == 0x44414548 || val == 0x54534f50 || val == 0x20544547 || val == 0x4954504f || val == 0xeeeeeeee {
97
+			continue
98
+		}
99
+
100
+		val = (uint32(data[7]) << 24) | (uint32(data[6]) << 16) | (uint32(data[5]) << 8) | uint32(data[4])
101
+		if val == 0x00000000 {
102
+			continue
103
+		}
104
+
105
+		copy(data.Magic(), tgMagicBytes)
106
+
107
+		return data
108
+	}
109
+}

+ 83
- 0
obfuscated2/frame_test.go 查看文件

@@ -0,0 +1,83 @@
1
+package obfuscated2
2
+
3
+import (
4
+	"testing"
5
+
6
+	"github.com/stretchr/testify/assert"
7
+)
8
+
9
+func TestFrameKey(t *testing.T) {
10
+	toCompare := make([]byte, 32)
11
+	for i := 0; i < 32; i++ {
12
+		toCompare[i] = byte(1)
13
+	}
14
+
15
+	assert.Equal(t, toCompare, makeFrame().Key())
16
+}
17
+
18
+func TestFrameIV(t *testing.T) {
19
+	toCompare := make([]byte, 16)
20
+	for i := 0; i < 16; i++ {
21
+		toCompare[i] = byte(2)
22
+	}
23
+
24
+	assert.Equal(t, toCompare, makeFrame().IV())
25
+}
26
+
27
+func TestFrameMagic(t *testing.T) {
28
+	toCompare := make([]byte, 4)
29
+	for i := 0; i < 4; i++ {
30
+		toCompare[i] = tgMagicByte
31
+	}
32
+
33
+	assert.Equal(t, toCompare, makeFrame().Magic())
34
+}
35
+
36
+func TestFrameDC(t *testing.T) {
37
+	assert.Equal(t, int16(771), makeFrame().DC())
38
+}
39
+
40
+func TestFrameValid(t *testing.T) {
41
+	frame := makeFrame()
42
+	assert.True(t, frame.Valid())
43
+
44
+	frame[8+32+16+2] = byte(3)
45
+	assert.False(t, frame.Valid())
46
+}
47
+
48
+func TestFrameInvert(t *testing.T) {
49
+	frame := makeFrame()
50
+	reversed := frame.Invert()
51
+
52
+	assert.Exactly(t, frame[:8], reversed[:8])
53
+	assert.Exactly(t, frame[56:], reversed[56:])
54
+
55
+	toCompare := make([]byte, 48)
56
+	for i := 0; i < 48; i++ {
57
+		toCompare[i] = frame[55-i]
58
+	}
59
+	assert.Equal(t, []byte(reversed[8:56]), toCompare)
60
+}
61
+
62
+func TestFrameGenerateValid(t *testing.T) {
63
+	assert.True(t, generateFrame().Valid())
64
+}
65
+
66
+func makeFrame() Frame {
67
+	f := make(Frame, FrameLen)
68
+
69
+	for i := 8; i < (8 + 32); i++ {
70
+		f[i] = byte(1)
71
+	}
72
+	for i := (8 + 32); i < (8 + 32 + 16); i++ {
73
+		f[i] = byte(2)
74
+	}
75
+	for i := (8 + 32 + 16); i < (8 + 32 + 16 + 4); i++ {
76
+		f[i] = tgMagicByte
77
+	}
78
+	for i := (8 + 32 + 16 + 4); i < (8 + 32 + 16 + 4 + 2); i++ {
79
+		f[i] = byte(3)
80
+	}
81
+
82
+	return f
83
+}

+ 79
- 0
obfuscated2/obfuscated2.go 查看文件

@@ -0,0 +1,79 @@
1
+package obfuscated2
2
+
3
+import (
4
+	"crypto/aes"
5
+	"crypto/cipher"
6
+	"crypto/sha256"
7
+
8
+	"github.com/juju/errors"
9
+)
10
+
11
+type Obfuscated2 struct {
12
+	decryptor cipher.Stream
13
+	encryptor cipher.Stream
14
+}
15
+
16
+func (o *Obfuscated2) Encrypt(data []byte) []byte {
17
+	buf := make([]byte, len(data))
18
+	o.encryptor.XORKeyStream(buf, data)
19
+	return buf
20
+}
21
+
22
+func (o *Obfuscated2) Decrypt(data []byte) []byte {
23
+	buf := make([]byte, len(data))
24
+	o.decryptor.XORKeyStream(buf, data)
25
+	return buf
26
+}
27
+
28
+func ParseObfuscated2ClientFrame(secret, data []byte) (*Obfuscated2, int16, error) {
29
+	frame := Frame(data)
30
+
31
+	decHasher := sha256.New()
32
+	decHasher.Write(frame.Key())
33
+	decHasher.Write(secret)
34
+	decryptor := makeStreamCipher(decHasher.Sum(nil), frame.IV())
35
+
36
+	invertedFrame := frame.Invert()
37
+	encHasher := sha256.New()
38
+	encHasher.Write(invertedFrame.Key())
39
+	encHasher.Write(secret)
40
+	encryptor := makeStreamCipher(encHasher.Sum(nil), invertedFrame.IV())
41
+
42
+	decryptedFrame := make(Frame, FrameLen)
43
+	decryptor.XORKeyStream(decryptedFrame, frame)
44
+	if !decryptedFrame.Valid() {
45
+		return nil, 0, errors.New("Unknown protocol")
46
+	}
47
+
48
+	obfs := &Obfuscated2{
49
+		decryptor: decryptor,
50
+		encryptor: encryptor,
51
+	}
52
+
53
+	return obfs, decryptedFrame.DC(), nil
54
+}
55
+
56
+func MakeTelegramObfuscated2Frame() (*Obfuscated2, Frame) {
57
+	frame := generateFrame()
58
+
59
+	encryptor := makeStreamCipher(frame.Key(), frame.IV())
60
+	decryptorFrame := frame.Invert()
61
+	decryptor := makeStreamCipher(decryptorFrame.Key(), decryptorFrame.IV())
62
+
63
+	copyFrame := make(Frame, frameOffsetIV)
64
+	copy(copyFrame, frame)
65
+	encryptor.XORKeyStream(frame, frame)
66
+	copy(frame, copyFrame)
67
+
68
+	obfs := &Obfuscated2{
69
+		decryptor: decryptor,
70
+		encryptor: encryptor,
71
+	}
72
+
73
+	return obfs, frame
74
+}
75
+
76
+func makeStreamCipher(key, iv []byte) cipher.Stream {
77
+	block, _ := aes.NewCipher(key)
78
+	return cipher.NewCTR(block, iv)
79
+}

+ 79
- 0
obfuscated2/obfuscated2_test.go 查看文件

@@ -0,0 +1,79 @@
1
+package obfuscated2
2
+
3
+import (
4
+	"crypto/sha256"
5
+	"fmt"
6
+	"testing"
7
+
8
+	"github.com/stretchr/testify/assert"
9
+)
10
+
11
+func TestObfs2TelegramFrameDecrypt(t *testing.T) {
12
+	_, frame := MakeTelegramObfuscated2Frame()
13
+	decryptor := makeStreamCipher(frame.Key(), frame.IV())
14
+
15
+	decrypted := make(Frame, FrameLen)
16
+	decryptor.XORKeyStream(decrypted, frame)
17
+
18
+	assert.True(t, decrypted.Valid())
19
+}
20
+
21
+func TestObfs2TelegramDecryptEncryptDecrypt(t *testing.T) {
22
+	obfs2, frame := MakeTelegramObfuscated2Frame()
23
+	inverted := frame.Invert()
24
+	encryptor := makeStreamCipher(inverted.Key(), inverted.IV())
25
+
26
+	data := []byte{1, 2, 3}
27
+	encrypted := make([]byte, 3)
28
+	encryptor.XORKeyStream(encrypted, data)
29
+	decrypted := obfs2.Decrypt(encrypted)
30
+
31
+	assert.Equal(t, data, decrypted)
32
+}
33
+
34
+func TestObfs2Full(t *testing.T) {
35
+	secret := []byte{1, 2, 3, 4, 5}
36
+
37
+	clientFrame := generateFrame()
38
+	clientHasher := sha256.New()
39
+	clientHasher.Write(clientFrame.Key())
40
+	clientHasher.Write(secret)
41
+	clientKey := clientHasher.Sum(nil)
42
+
43
+	encryptor := makeStreamCipher(clientKey, clientFrame.IV())
44
+	encrypted := make(Frame, FrameLen)
45
+	encryptor.XORKeyStream(encrypted, clientFrame)
46
+	copy(encrypted[:56], clientFrame[:56])
47
+
48
+	invertedClientFrame := clientFrame.Invert()
49
+	clientHasher = sha256.New()
50
+	clientHasher.Write(invertedClientFrame.Key())
51
+	clientHasher.Write(secret)
52
+	invertedClientKey := clientHasher.Sum(nil)
53
+	clientDecryptor := makeStreamCipher(invertedClientKey, invertedClientFrame.IV())
54
+
55
+	clientObfs, _, err := ParseObfuscated2ClientFrame(secret, encrypted)
56
+	assert.Nil(t, err)
57
+
58
+	tgObfs, tgFrame := MakeTelegramObfuscated2Frame()
59
+	tgDecryptor := makeStreamCipher(tgFrame.Key(), tgFrame.IV())
60
+	decrypted := make(Frame, FrameLen)
61
+	tgDecryptor.XORKeyStream(decrypted, tgFrame)
62
+	assert.True(t, decrypted.Valid())
63
+
64
+	tgInvertedFrame := tgFrame.Invert()
65
+	tgEncryptor := makeStreamCipher(tgInvertedFrame.Key(), tgInvertedFrame.IV())
66
+
67
+	message := []byte{1, 2, 3, 4, 5, 6, 7, 8, 9}
68
+	tgEncryptedMessage := make([]byte, len(message))
69
+	tgEncryptor.XORKeyStream(tgEncryptedMessage, message)
70
+
71
+	tgEncDecryptedMessage := tgObfs.Decrypt(tgEncryptedMessage)
72
+	assert.Equal(t, message, tgEncDecryptedMessage)
73
+
74
+	clientEncryptedMessage := clientObfs.Encrypt(tgEncDecryptedMessage)
75
+	finalMessage := make([]byte, len(clientEncryptedMessage))
76
+	clientDecryptor.XORKeyStream(finalMessage, clientEncryptedMessage)
77
+
78
+	assert.Equal(t, finalMessage, message)
79
+}

+ 52
- 0
server/cipherrwc.go 查看文件

@@ -0,0 +1,52 @@
1
+package server
2
+
3
+import (
4
+	"bytes"
5
+	"io"
6
+)
7
+
8
+type Cipher interface {
9
+	Encrypt([]byte) []byte
10
+	Decrypt([]byte) []byte
11
+}
12
+
13
+type CipherReadWriteCloser struct {
14
+	crypt Cipher
15
+	conn  io.ReadWriteCloser
16
+	rest  *bytes.Buffer
17
+}
18
+
19
+func (c *CipherReadWriteCloser) Read(p []byte) (n int, err error) {
20
+	n, err = c.conn.Read(p)
21
+	copy(p, c.crypt.Decrypt(p[:n]))
22
+	return
23
+}
24
+
25
+func (c *CipherReadWriteCloser) Write(p []byte) (n int, err error) {
26
+	c.rest.Write(c.crypt.Encrypt(p))
27
+	newP := c.rest.Bytes()[:len(p)]
28
+	n, err = c.conn.Write(newP)
29
+	c.rest = bytes.NewBuffer(c.rest.Bytes()[n:])
30
+	return
31
+}
32
+
33
+func (c *CipherReadWriteCloser) Close() error {
34
+	var err1 error
35
+	if c.rest.Len() > 0 {
36
+		_, err1 = c.conn.Write(c.rest.Bytes())
37
+	}
38
+	err2 := c.conn.Close()
39
+
40
+	if err2 != nil {
41
+		return err2
42
+	}
43
+	return err1
44
+}
45
+
46
+func newCipherReadWriteCloser(conn io.ReadWriteCloser, crypt Cipher) io.ReadWriteCloser {
47
+	return &CipherReadWriteCloser{
48
+		conn:  conn,
49
+		crypt: crypt,
50
+		rest:  &bytes.Buffer{},
51
+	}
52
+}

+ 52
- 0
server/ctxrwc.go 查看文件

@@ -0,0 +1,52 @@
1
+package server
2
+
3
+import (
4
+	"context"
5
+	"io"
6
+
7
+	"github.com/juju/errors"
8
+)
9
+
10
+type CtxReadWriteCloser struct {
11
+	ctx    context.Context
12
+	conn   io.ReadWriteCloser
13
+	cancel context.CancelFunc
14
+}
15
+
16
+func (c *CtxReadWriteCloser) Read(p []byte) (int, error) {
17
+	select {
18
+	case <-c.ctx.Done():
19
+		return 0, errors.Annotate(c.ctx.Err(), "Read is failed because of closed context")
20
+	default:
21
+		n, err := c.conn.Read(p)
22
+		if err != nil {
23
+			c.cancel()
24
+		}
25
+		return n, err
26
+	}
27
+}
28
+
29
+func (c *CtxReadWriteCloser) Write(p []byte) (int, error) {
30
+	select {
31
+	case <-c.ctx.Done():
32
+		return 0, errors.Annotate(c.ctx.Err(), "Write is failed because of closed context")
33
+	default:
34
+		n, err := c.conn.Write(p)
35
+		if err != nil {
36
+			c.cancel()
37
+		}
38
+		return n, err
39
+	}
40
+}
41
+
42
+func (c *CtxReadWriteCloser) Close() error {
43
+	return c.conn.Close()
44
+}
45
+
46
+func newCtxReadWriteCloser(conn io.ReadWriteCloser, ctx context.Context, cancel context.CancelFunc) io.ReadWriteCloser {
47
+	return &CtxReadWriteCloser{
48
+		conn:   conn,
49
+		ctx:    ctx,
50
+		cancel: cancel,
51
+	}
52
+}

+ 41
- 0
server/logrwc.go 查看文件

@@ -0,0 +1,41 @@
1
+package server
2
+
3
+import (
4
+	"io"
5
+
6
+	"go.uber.org/zap"
7
+)
8
+
9
+type LogReadWriteCloser struct {
10
+	conn   io.ReadWriteCloser
11
+	logger *zap.SugaredLogger
12
+	sockid string
13
+	name   string
14
+}
15
+
16
+func (l *LogReadWriteCloser) Read(p []byte) (n int, err error) {
17
+	n, err = l.conn.Read(p)
18
+	l.logger.Debugw("Finish reading", "name", l.name, "socketid", l.sockid, "nbytes", n, "error", err)
19
+	return
20
+}
21
+
22
+func (l *LogReadWriteCloser) Write(p []byte) (n int, err error) {
23
+	n, err = l.conn.Write(p)
24
+	l.logger.Debugw("Finish writing", "name", l.name, "socketid", l.sockid, "nbytes", n, "error", err)
25
+	return
26
+}
27
+
28
+func (l *LogReadWriteCloser) Close() error {
29
+	err := l.conn.Close()
30
+	l.logger.Debugw("Finish closing socket", "name", l.name, "socketid", l.sockid, "error", err)
31
+	return err
32
+}
33
+
34
+func newLogReadWriteCloser(conn io.ReadWriteCloser, logger *zap.SugaredLogger, sockid string, name string) io.ReadWriteCloser {
35
+	return &LogReadWriteCloser{
36
+		conn:   conn,
37
+		logger: logger,
38
+		sockid: sockid,
39
+		name:   name,
40
+	}
41
+}

+ 184
- 0
server/server.go 查看文件

@@ -0,0 +1,184 @@
1
+package server
2
+
3
+import (
4
+	"context"
5
+	"fmt"
6
+	"io"
7
+	"net"
8
+	"strconv"
9
+	"sync"
10
+
11
+	"github.com/9seconds/mtg/obfuscated2"
12
+	"github.com/juju/errors"
13
+	uuid "github.com/satori/go.uuid"
14
+	"go.uber.org/zap"
15
+)
16
+
17
+type Server struct {
18
+	ip     net.IP
19
+	port   int
20
+	secret []byte
21
+	logger *zap.SugaredLogger
22
+	lsock  net.Listener
23
+	ctx    context.Context
24
+}
25
+
26
+func (s *Server) Serve() error {
27
+	lsock, err := net.Listen("tcp", s.Addr())
28
+	if err != nil {
29
+		return errors.Annotate(err, "Cannot create listen socket")
30
+	}
31
+
32
+	for {
33
+		if conn, err := lsock.Accept(); err != nil {
34
+			s.logger.Warn("Cannot allocate incoming connection", "error", err)
35
+		} else {
36
+			go s.accept(conn)
37
+		}
38
+	}
39
+
40
+	return nil
41
+}
42
+
43
+func (s *Server) Addr() string {
44
+	return net.JoinHostPort(s.ip.String(), strconv.Itoa(s.port))
45
+}
46
+
47
+func (s *Server) accept(conn net.Conn) {
48
+	defer conn.Close()
49
+
50
+	ctx, cancel := context.WithCancel(context.Background())
51
+	socketID := s.makeSocketID()
52
+
53
+	s.logger.Debugw("Client connected",
54
+		"secret", s.secret,
55
+		"addr", conn.RemoteAddr().String(),
56
+		"socketid", socketID,
57
+	)
58
+
59
+	clientCipher, dc := s.getClientStream(conn, ctx, cancel, socketID)
60
+	// if err != nil {
61
+	// 	s.logger.Warnw("Cannot initialize client connection",
62
+	// 		"secret", s.secret,
63
+	// 		"addr", conn.RemoteAddr().String(),
64
+	// 		"socketid", socketID,
65
+	// 		"error", err,
66
+	// 	)
67
+	// 	return
68
+	// }
69
+
70
+	tgConn, tgCipher := s.getTelegramStream(dc, ctx, cancel, socketID)
71
+	// if err != nil {
72
+	// 	s.logger.Warnw("Cannot initialize Telegram connection",
73
+	// 		"socketid", socketID,
74
+	// 		"error", err,
75
+	// 	)
76
+	// 	return
77
+	// }
78
+	defer tgConn.Close()
79
+
80
+	wait := &sync.WaitGroup{}
81
+	wait.Add(2)
82
+	go func() {
83
+		buf := make([]byte, 128)
84
+		for {
85
+			n, err := conn.Read(buf)
86
+			if err != nil {
87
+				return
88
+			}
89
+			decrypted := clientCipher.Decrypt(buf[:n])
90
+			encrypted := tgCipher.Encrypt(decrypted)
91
+			tgConn.Write(encrypted)
92
+		}
93
+	}()
94
+	go func() {
95
+		buf := make([]byte, 128)
96
+		for {
97
+			n, err := tgConn.Read(buf)
98
+			if err != nil {
99
+				return
100
+			}
101
+			decrypted := tgCipher.Decrypt(buf[:n])
102
+			encrypted := clientCipher.Encrypt(decrypted)
103
+			conn.Write(encrypted)
104
+		}
105
+	}()
106
+	// go func() {
107
+	// 	buf := make([]byte, 128)
108
+	// 	for {
109
+	// 		n, err := conn.
110
+	// 	}
111
+	// 	defer wait.Done()
112
+	// 	io.Copy(tgConn, clientConn)
113
+	// }()
114
+	// go func() {
115
+	// 	defer wait.Done()
116
+	// 	io.Copy(clientConn, tgConn)
117
+	// }()
118
+	<-ctx.Done()
119
+	wait.Wait()
120
+
121
+	s.logger.Debugw("Client disconnected",
122
+		"secret", s.secret,
123
+		"addr", conn.RemoteAddr().String(),
124
+		"socketid", socketID,
125
+	)
126
+}
127
+
128
+func (s *Server) makeSocketID() string {
129
+	return uuid.NewV4().String()
130
+}
131
+
132
+func (s *Server) getClientStream(conn net.Conn, ctx context.Context, cancel context.CancelFunc, socketID string) (Cipher, int16) {
133
+	frame, err := obfuscated2.ExtractFrame(conn)
134
+	if err != nil {
135
+		fmt.Println(err)
136
+		// return nil, 0, errors.Annotate(err, "Cannot create client stream")
137
+	}
138
+
139
+	obfs2, dc, err := obfuscated2.ParseObfuscated2ClientFrame(s.secret, frame)
140
+	if err != nil {
141
+		fmt.Println(err)
142
+		// return nil, 0, errors.Annotate(err, "Cannot create client stream")
143
+	}
144
+
145
+	return obfs2, dc
146
+
147
+	// cipherConn := newCipherReadWriteCloser(conn, obfs2)
148
+	// ctxConn := newCtxReadWriteCloser(cipherConn, ctx, cancel)
149
+	// // logConn := newLogReadWriteCloser(ctxConn, s.logger, socketID, "client")
150
+
151
+	// return ctxConn, dc, nil
152
+}
153
+
154
+func (s *Server) getTelegramStream(dc int16, ctx context.Context, cancel context.CancelFunc, socketID string) (io.ReadWriteCloser, Cipher) {
155
+	socket, err := dialToTelegram(dc)
156
+	if err != nil {
157
+		fmt.Println(err)
158
+		// return nil, errors.Annotate(err, "Cannot dial")
159
+	}
160
+
161
+	obfs2, frame := obfuscated2.MakeTelegramObfuscated2Frame()
162
+	if n, err := socket.Write(frame); err != nil || n != len(frame) {
163
+		fmt.Println(err)
164
+		// return nil, errors.Annotate(err, "Cannot write hadnshake frame")
165
+	}
166
+
167
+	return socket, obfs2
168
+
169
+	// 	cipherConn := newCipherReadWriteCloser(socket, obfs2)
170
+	// 	ctxConn := newCtxReadWriteCloser(cipherConn, ctx, cancel)
171
+	// 	logConn := newLogReadWriteCloser(ctxConn, s.logger, socketID, "telegram")
172
+
173
+	// 	return logConn, nil
174
+}
175
+
176
+func NewServer(ip net.IP, port int, secret []byte, logger *zap.SugaredLogger) *Server {
177
+	return &Server{
178
+		ip:     ip,
179
+		port:   port,
180
+		secret: secret,
181
+		ctx:    context.Background(),
182
+		logger: logger,
183
+	}
184
+}

+ 38
- 0
server/telegram.go 查看文件

@@ -0,0 +1,38 @@
1
+package server
2
+
3
+import (
4
+	"net"
5
+	"time"
6
+
7
+	"github.com/juju/errors"
8
+)
9
+
10
+var telegramDCIPs = [5]string{
11
+	"149.154.175.50:443",
12
+	"149.154.167.51:443",
13
+	"149.154.175.100:443",
14
+	"149.154.167.91:443",
15
+	"149.154.171.5:443",
16
+}
17
+
18
+const telegramKeepAlive = 30 * time.Second
19
+
20
+func dialToTelegram(dcIdx int16) (net.Conn, error) {
21
+	if dcIdx < 0 || dcIdx >= 5 {
22
+		return nil, errors.New("Incorrect DC IDX")
23
+	}
24
+
25
+	conn, err := net.Dial("tcp", telegramDCIPs[dcIdx])
26
+	if err != nil {
27
+		return nil, errors.Annotate(err, "Cannot dial")
28
+	}
29
+
30
+	// if err := conn.SetKeepAlive(true); err != nil {
31
+	// 	return nil, errors.Annotate(err, "Cannot establish keepalive connection")
32
+	// }
33
+	// if err := conn.SetKeepAlivePeriod(telegramKeepAlive); err != nil {
34
+	// 	return nil, errors.Annotate(err, "Cannot set keepalive timeout")
35
+	// }
36
+
37
+	return conn, nil
38
+}

正在加载...
取消
保存