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

Merge pull request #259 from 9seconds/go118

Support of Go 1.18
tags/v2.1.6^2
Sergey Arkhipov 4 лет назад
Родитель
Сommit
59b5ff4080
Аккаунт пользователя с таким Email не найден

+ 40
- 3
.github/workflows/ci.yaml Просмотреть файл

42
     strategy:
42
     strategy:
43
       matrix:
43
       matrix:
44
         go_version:
44
         go_version:
45
-          - ^1.17
45
+          - ^1.18
46
     steps:
46
     steps:
47
       - name: Checkout
47
       - name: Checkout
48
         uses: actions/checkout@v2
48
         uses: actions/checkout@v2
69
         with:
69
         with:
70
           file: ./coverage.txt
70
           file: ./coverage.txt
71
 
71
 
72
+  fuzz:
73
+    name: Fuzzing
74
+    runs-on: ubuntu-latest
75
+    timeout-minutes: 20
76
+    steps:
77
+      - name: Checkout
78
+        uses: actions/checkout@v2
79
+        with:
80
+          submodules: recursive
81
+
82
+      - name: Setup Go
83
+        uses: actions/setup-go@v2
84
+        with:
85
+          go-version: ^1.18
86
+
87
+      - name: Cache fuzz results
88
+        uses: actions/cache@v2
89
+        with:
90
+          path: ~/.cache/go-build/fuzz
91
+          key: ${{ runner.os }}-go-${{ hashFiles('**/*_fuzz_test.go', '**/*_fuzz_internal_test.go') }}
92
+          restore-keys: ${{ runner.os }}-go-
93
+
94
+      - name: Cache dependencies
95
+        uses: actions/cache@v2
96
+        with:
97
+          path: ~/go/pkg/mod
98
+          key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
99
+          restore-keys: ${{ runner.os }}-go-
100
+
101
+      - name: Run fuzzing
102
+        run: make -j4 fuzz
103
+
72
   lint:
104
   lint:
73
     name: Lint
105
     name: Lint
74
     runs-on: ubuntu-latest
106
     runs-on: ubuntu-latest
79
         with:
111
         with:
80
           submodules: recursive
112
           submodules: recursive
81
 
113
 
114
+      - name: Setup Go
115
+        uses: actions/setup-go@v2
116
+        with:
117
+          go-version: ^1.18
118
+
82
       - name: Run linter
119
       - name: Run linter
83
-        uses: golangci/golangci-lint-action@v2
120
+        uses: golangci/golangci-lint-action@v3
84
         with:
121
         with:
85
-          version: v1.44.2
122
+          version: v1.45.0
86
 
123
 
87
   docker:
124
   docker:
88
     name: Docker
125
     name: Docker

+ 1
- 1
.golangci.toml Просмотреть файл

9
 
9
 
10
 [linters]
10
 [linters]
11
 enable-all = true
11
 enable-all = true
12
-disable = ["ireturn", "varnamelen", "gochecknoglobals", "gas", "goerr113", "exhaustivestruct", "containedctx"]
12
+disable = ["thelper", "ireturn", "varnamelen", "gochecknoglobals", "gas", "goerr113", "exhaustivestruct", "containedctx"]

+ 1
- 1
Dockerfile Просмотреть файл

1
 ###############################################################################
1
 ###############################################################################
2
 # BUILD STAGE
2
 # BUILD STAGE
3
 
3
 
4
-FROM golang:1.17-alpine AS build
4
+FROM golang:1.18-alpine AS build
5
 
5
 
6
 RUN set -x \
6
 RUN set -x \
7
   && apk --no-cache --update add \
7
   && apk --no-cache --update add \

+ 30
- 7
Makefile Просмотреть файл

2
 IMAGE_NAME   := mtg
2
 IMAGE_NAME   := mtg
3
 APP_NAME     := $(IMAGE_NAME)
3
 APP_NAME     := $(IMAGE_NAME)
4
 
4
 
5
-GOLANGCI_LINT_VERSION := v1.44.2
5
+GOLANGCI_LINT_VERSION := v1.45.0
6
 
6
 
7
-VERSION_GO         := $(shell go version)
8
-VERSION_DATE       := $(shell date -Ru)
9
-VERSION_TAG        := $(shell git describe --tags --always)
10
-COMMON_BUILD_FLAGS := -trimpath -mod=readonly -ldflags="-extldflags '-static' -s -w -X 'main.version=$(VERSION_TAG) ($(VERSION_GO)) [$(VERSION_DATE)]'"
7
+VERSION            := $(shell git describe --exact-match HEAD 2>/dev/null || git describe --tags --always)
8
+COMMON_BUILD_FLAGS := -trimpath -mod=readonly -ldflags="-extldflags '-static' -s -w -X 'main.version=$(VERSION)'"
9
+
10
+FUZZ_FLAGS := -fuzztime=120s
11
 
11
 
12
 GOBIN  := $(ROOT_DIR)/.bin
12
 GOBIN  := $(ROOT_DIR)/.bin
13
 GOTOOL := env "GOBIN=$(GOBIN)" "PATH=$(ROOT_DIR)/.bin:$(PATH)"
13
 GOTOOL := env "GOBIN=$(GOBIN)" "PATH=$(ROOT_DIR)/.bin:$(PATH)"
78
 
78
 
79
 .PHONY: install-tools-lint
79
 .PHONY: install-tools-lint
80
 install-tools-lint: .bin
80
 install-tools-lint: .bin
81
-	@curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh \
81
+	@curl -sfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh \
82
 		| bash -s -- -b "$(GOBIN)" "$(GOLANGCI_LINT_VERSION)"
82
 		| bash -s -- -b "$(GOBIN)" "$(GOLANGCI_LINT_VERSION)"
83
 
83
 
84
 .PHONY: install-tools-godoc
84
 .PHONY: install-tools-godoc
95
 
95
 
96
 .PHONY: update-deps
96
 .PHONY: update-deps
97
 update-deps:
97
 update-deps:
98
-	@go get -u && go mod tidy -go=1.17
98
+	@go get -u && go mod tidy -go=1.18
99
+
100
+.PHONY: fuzz
101
+fuzz: fuzz-ClientHello fuzz-ServerGenerateHandshakeFrame fuzz-ClientHandshake fuzz-ServerReceive fuzz-ServerSend
102
+
103
+.PHONY: fuzz-ClientHello
104
+fuzz-ClientHello:
105
+	@go test -fuzz=FuzzClientHello $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/faketls"
106
+
107
+.PHONY: fuzz-ServerGenerateHandshakeFrame
108
+fuzz-ServerGenerateHandshakeFrame:
109
+	@go test -fuzz=FuzzServerGenerateHandshakeFrame $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/obfuscated2"
110
+
111
+.PHONY: fuzz-ClientHandshake
112
+fuzz-ClientHandshake:
113
+	@go test -fuzz=FuzzClientHandshake $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/obfuscated2"
114
+
115
+.PHONY: fuzz-ServerReceive
116
+fuzz-ServerReceive:
117
+	@go test -fuzz=FuzzServerReceive $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/obfuscated2"
118
+
119
+.PHONY: fuzz-ServerSend
120
+fuzz-ServerSend:
121
+	@go test -fuzz=FuzzServerSend $(FUZZ_FLAGS) "$(ROOT_DIR)/mtglib/internal/obfuscated2"

+ 1
- 1
go.mod Просмотреть файл

1
 module github.com/9seconds/mtg/v2
1
 module github.com/9seconds/mtg/v2
2
 
2
 
3
-go 1.17
3
+go 1.18
4
 
4
 
5
 require (
5
 require (
6
 	github.com/OneOfOne/xxhash v1.2.8
6
 	github.com/OneOfOne/xxhash v1.2.8

+ 0
- 1
go.sum Просмотреть файл

416
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
416
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
417
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
417
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
418
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
418
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
419
-golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
420
 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
419
 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
421
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
420
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
422
 golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
421
 golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=

+ 2
- 1
internal/cli/run_proxy.go Просмотреть файл

89
 func makeIPBlocklist(conf config.ListConfig,
89
 func makeIPBlocklist(conf config.ListConfig,
90
 	logger mtglib.Logger,
90
 	logger mtglib.Logger,
91
 	ntw mtglib.Network,
91
 	ntw mtglib.Network,
92
-	updateCallback ipblocklist.FireholUpdateCallback) (mtglib.IPBlocklist, error) {
92
+	updateCallback ipblocklist.FireholUpdateCallback,
93
+) (mtglib.IPBlocklist, error) {
93
 	if !conf.Enabled.Get(false) {
94
 	if !conf.Enabled.Get(false) {
94
 		return ipblocklist.NewNoop(), nil
95
 		return ipblocklist.NewNoop(), nil
95
 	}
96
 	}

+ 2
- 1
internal/testlib/mtglib_network_mock.go Просмотреть файл

25
 }
25
 }
26
 
26
 
27
 func (m *MtglibNetworkMock) MakeHTTPClient(dialFunc func(ctx context.Context,
27
 func (m *MtglibNetworkMock) MakeHTTPClient(dialFunc func(ctx context.Context,
28
-	network, address string) (essentials.Conn, error)) *http.Client {
28
+	network, address string) (essentials.Conn, error),
29
+) *http.Client {
29
 	return m.Called(dialFunc).Get(0).(*http.Client) // nolint: forcetypeassert
30
 	return m.Called(dialFunc).Get(0).(*http.Client) // nolint: forcetypeassert
30
 }
31
 }

+ 6
- 3
ipblocklist/firehol.go Просмотреть файл

155
 
155
 
156
 func (f *Firehol) updateFromFile(mutex sync.Locker,
156
 func (f *Firehol) updateFromFile(mutex sync.Locker,
157
 	ranger cidranger.Ranger,
157
 	ranger cidranger.Ranger,
158
-	scanner *bufio.Scanner) error {
158
+	scanner *bufio.Scanner,
159
+) error {
159
 	for scanner.Scan() {
160
 	for scanner.Scan() {
160
 		text := scanner.Text()
161
 		text := scanner.Text()
161
 		text = fireholRegexpComment.ReplaceAllLiteralString(text, "")
162
 		text = fireholRegexpComment.ReplaceAllLiteralString(text, "")
216
 	downloadConcurrency uint,
217
 	downloadConcurrency uint,
217
 	urls []string,
218
 	urls []string,
218
 	localFiles []string,
219
 	localFiles []string,
219
-	updateCallback FireholUpdateCallback) (*Firehol, error) {
220
+	updateCallback FireholUpdateCallback,
221
+) (*Firehol, error) {
220
 	blocklists := []files.File{}
222
 	blocklists := []files.File{}
221
 
223
 
222
 	for _, v := range localFiles {
224
 	for _, v := range localFiles {
245
 func NewFireholFromFiles(logger mtglib.Logger,
247
 func NewFireholFromFiles(logger mtglib.Logger,
246
 	downloadConcurrency uint,
248
 	downloadConcurrency uint,
247
 	blocklists []files.File,
249
 	blocklists []files.File,
248
-	updateCallback FireholUpdateCallback) (*Firehol, error) {
250
+	updateCallback FireholUpdateCallback,
251
+) (*Firehol, error) {
249
 	if downloadConcurrency == 0 {
252
 	if downloadConcurrency == 0 {
250
 		downloadConcurrency = DefaultFireholDownloadConcurrency
253
 		downloadConcurrency = DefaultFireholDownloadConcurrency
251
 	}
254
 	}

+ 29
- 0
main.go Просмотреть файл

9
 package main
9
 package main
10
 
10
 
11
 import (
11
 import (
12
+	"fmt"
12
 	"math/rand"
13
 	"math/rand"
14
+	"runtime/debug"
15
+	"strconv"
13
 	"time"
16
 	"time"
14
 
17
 
15
 	"github.com/9seconds/mtg/v2/internal/cli"
18
 	"github.com/9seconds/mtg/v2/internal/cli"
26
 		panic(err)
29
 		panic(err)
27
 	}
30
 	}
28
 
31
 
32
+	if buildInfo, ok := debug.ReadBuildInfo(); ok {
33
+		vcsCommit := "<no-commit>"
34
+		vcsDate := time.Now()
35
+		vcsDirty := ""
36
+
37
+		for _, setting := range buildInfo.Settings {
38
+			switch setting.Key {
39
+			case "vcs.time":
40
+				vcsDate, _ = time.Parse(time.RFC3339, setting.Value)
41
+			case "vcs.revision":
42
+				vcsCommit = setting.Value
43
+			case "vcs.modified":
44
+				if isDirty, _ := strconv.ParseBool(setting.Value); isDirty {
45
+					vcsDirty = " [dirty]"
46
+				}
47
+			}
48
+		}
49
+
50
+		version = fmt.Sprintf("%s (%s: %s on %s%s)",
51
+			version,
52
+			buildInfo.GoVersion,
53
+			vcsDate.Format(time.RFC3339),
54
+			vcsCommit,
55
+			vcsDirty)
56
+	}
57
+
29
 	cli := &cli.CLI{}
58
 	cli := &cli.CLI{}
30
 	ctx := kong.Parse(cli, kong.Vars{
59
 	ctx := kong.Parse(cli, kong.Vars{
31
 		"version": version,
60
 		"version": version,

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

1
+package faketls_test
2
+
3
+import (
4
+	"testing"
5
+
6
+	"github.com/9seconds/mtg/v2/mtglib/internal/faketls"
7
+	"github.com/stretchr/testify/require"
8
+)
9
+
10
+var FuzzClientHelloSecret = []byte{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
11
+
12
+func FuzzClientHello(f *testing.F) {
13
+	f.Add([]byte{1, 2, 3})
14
+
15
+	f.Fuzz(func(t *testing.T, frame []byte) {
16
+		_, err := faketls.ParseClientHello(FuzzClientHelloSecret, frame)
17
+
18
+		// a probability of having != err is almost negligible
19
+		require.Error(t, err)
20
+	})
21
+}

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

19
 
19
 
20
 	// ClientHelloMinLen is a minimal possible length of
20
 	// ClientHelloMinLen is a minimal possible length of
21
 	// ClientHello record.
21
 	// ClientHello record.
22
-	ClientHelloMinLen = 4
22
+	ClientHelloMinLen = 6
23
 
23
 
24
 	// WelcomePacketRandomOffset is an offset of random in ServerHello
24
 	// WelcomePacketRandomOffset is an offset of random in ServerHello
25
 	// packet (including record envelope).
25
 	// packet (including record envelope).

+ 32
- 0
mtglib/internal/obfuscated2/client_handshake_fuzz_internal_test.go Просмотреть файл

1
+package obfuscated2
2
+
3
+import (
4
+	"bytes"
5
+	"testing"
6
+
7
+	"github.com/stretchr/testify/require"
8
+)
9
+
10
+var FuzzClientHandshakeSecret = []byte{1, 2, 3}
11
+
12
+func FuzzClientHandshake(f *testing.F) {
13
+	f.Add([]byte{1, 2, 3})
14
+
15
+	f.Fuzz(func(t *testing.T, frame []byte) {
16
+		data := bytes.NewReader(frame)
17
+
18
+		if _, _, _, err := ClientHandshake(FuzzClientHandshakeSecret, data); err != nil {
19
+			return
20
+		}
21
+
22
+		handshake := clientHandhakeFrame{}
23
+		require.Len(t, frame, handshakeFrameLen)
24
+
25
+		copy(handshake.data[:], frame)
26
+
27
+		decryptor := handshake.decryptor(FuzzClientHandshakeSecret)
28
+		decryptor.XORKeyStream(handshake.data[:], handshake.data[:])
29
+
30
+		require.Equal(t, handshakeConnectionType, handshake.connectionType())
31
+	})
32
+}

+ 54
- 0
mtglib/internal/obfuscated2/init_test.go Просмотреть файл

1
 package obfuscated2_test
1
 package obfuscated2_test
2
 
2
 
3
 import (
3
 import (
4
+	"bytes"
5
+	"crypto/aes"
6
+	"crypto/cipher"
4
 	"encoding/base64"
7
 	"encoding/base64"
5
 	"encoding/json"
8
 	"encoding/json"
6
 	"fmt"
9
 	"fmt"
7
 	"os"
10
 	"os"
8
 	"path/filepath"
11
 	"path/filepath"
9
 	"strings"
12
 	"strings"
13
+	"testing"
14
+
15
+	"github.com/9seconds/mtg/v2/internal/testlib"
16
+	"github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2"
17
+	"github.com/stretchr/testify/require"
10
 )
18
 )
11
 
19
 
12
 type snapshotBytes struct {
20
 type snapshotBytes struct {
50
 	snapshots map[string]*Obfuscated2Snapshot
58
 	snapshots map[string]*Obfuscated2Snapshot
51
 }
59
 }
52
 
60
 
61
+type ServerHandshakeTestData struct {
62
+	connMock *testlib.EssentialsConnMock
63
+
64
+	proxyConn obfuscated2.Conn
65
+	encryptor cipher.Stream
66
+	decryptor cipher.Stream
67
+}
68
+
53
 func (suite *SnapshotTestSuite) IngestSnapshots(dirname, namePrefix string) error {
69
 func (suite *SnapshotTestSuite) IngestSnapshots(dirname, namePrefix string) error {
54
 	suite.snapshots = map[string]*Obfuscated2Snapshot{}
70
 	suite.snapshots = map[string]*Obfuscated2Snapshot{}
55
 
71
 
81
 
97
 
82
 	return nil
98
 	return nil
83
 }
99
 }
100
+
101
+func NewServerHandshakeTestData(t *testing.T) ServerHandshakeTestData {
102
+	buf := &bytes.Buffer{}
103
+	connMock := &testlib.EssentialsConnMock{}
104
+
105
+	handshakeEnc, handshakeDec, err := obfuscated2.ServerHandshake(buf)
106
+	require.NoError(t, err)
107
+
108
+	serverEncrypted := buf.Bytes()
109
+	decBlock, _ := aes.NewCipher(serverEncrypted[8 : 8+32])
110
+	decryptor := cipher.NewCTR(decBlock, serverEncrypted[8+32:8+32+16])
111
+
112
+	serverDecrypted := make([]byte, len(serverEncrypted))
113
+	decryptor.XORKeyStream(serverDecrypted, serverEncrypted)
114
+
115
+	require.Equal(t, "3d3d3Q",
116
+		base64.RawStdEncoding.EncodeToString(serverDecrypted[8+32+16:8+32+16+4]))
117
+
118
+	serverEncryptedReverted := make([]byte, len(serverEncrypted))
119
+
120
+	for i := 0; i < 32+16; i++ {
121
+		serverEncryptedReverted[8+i] = serverEncrypted[8+32+16-1-i]
122
+	}
123
+
124
+	encBlock, _ := aes.NewCipher(serverEncryptedReverted[8 : 8+32])
125
+	encryptor := cipher.NewCTR(encBlock, serverEncryptedReverted[8+32:8+32+16])
126
+
127
+	return ServerHandshakeTestData{
128
+		connMock: connMock,
129
+		proxyConn: obfuscated2.Conn{
130
+			Conn:      connMock,
131
+			Encryptor: handshakeEnc,
132
+			Decryptor: handshakeDec,
133
+		},
134
+		encryptor: encryptor,
135
+		decryptor: decryptor,
136
+	}
137
+}

+ 30
- 0
mtglib/internal/obfuscated2/server_handshake_fuzz_internal_test.go Просмотреть файл

1
+package obfuscated2
2
+
3
+import (
4
+	"encoding/binary"
5
+	"testing"
6
+
7
+	"github.com/stretchr/testify/assert"
8
+)
9
+
10
+func FuzzServerGenerateHandshakeFrame(f *testing.F) {
11
+	f.Fuzz(func(t *testing.T, arg int) {
12
+		frame := generateServerHanshakeFrame()
13
+
14
+		assert.NotEqualValues(t, 0xef, frame.data[0])
15
+
16
+		firstBytes := binary.LittleEndian.Uint32(frame.data[:4])
17
+		assert.NotEqualValues(t, 0x44414548, firstBytes)
18
+		assert.NotEqualValues(t, 0x54534f50, firstBytes)
19
+		assert.NotEqualValues(t, 0x20544547, firstBytes)
20
+		assert.NotEqualValues(t, 0x4954504f, firstBytes)
21
+		assert.NotEqualValues(t, 0xeeeeeeee, firstBytes)
22
+
23
+		assert.NotEqualValues(
24
+			t,
25
+			0,
26
+			frame.data[4]|frame.data[5]|frame.data[6]|frame.data[7])
27
+
28
+		assert.Equal(t, handshakeConnectionType, frame.connectionType())
29
+	})
30
+}

+ 58
- 0
mtglib/internal/obfuscated2/server_handshake_fuzz_test.go Просмотреть файл

1
+package obfuscated2_test
2
+
3
+import (
4
+	"testing"
5
+
6
+	"github.com/stretchr/testify/assert"
7
+	"github.com/stretchr/testify/mock"
8
+)
9
+
10
+func FuzzServerSend(f *testing.F) {
11
+	f.Add([]byte{1, 2, 3, 4, 5})
12
+
13
+	f.Fuzz(func(t *testing.T, data []byte) {
14
+		handshakeData := NewServerHandshakeTestData(t)
15
+
16
+		handshakeData.connMock.
17
+			On("Write", mock.Anything).
18
+			Return(len(data), nil).
19
+			Once().
20
+			Run(func(args mock.Arguments) {
21
+				message := make([]byte, len(data))
22
+				handshakeData.decryptor.XORKeyStream(message, args.Get(0).([]byte)) // nolint: forcetypeassert
23
+				assert.Equal(t, message, data)
24
+			})
25
+
26
+		n, err := handshakeData.proxyConn.Write(data)
27
+
28
+		assert.EqualValues(t, len(data), n)
29
+		assert.NoError(t, err)
30
+		handshakeData.connMock.AssertExpectations(t)
31
+	})
32
+}
33
+
34
+func FuzzServerReceive(f *testing.F) {
35
+	f.Add([]byte{1, 2, 3, 4, 5})
36
+
37
+	f.Fuzz(func(t *testing.T, data []byte) {
38
+		handshakeData := NewServerHandshakeTestData(t)
39
+		buffer := make([]byte, len(data))
40
+
41
+		handshakeData.connMock.
42
+			On("Read", mock.Anything).
43
+			Return(len(data), nil).
44
+			Once().
45
+			Run(func(args mock.Arguments) {
46
+				message := make([]byte, len(data))
47
+				handshakeData.encryptor.XORKeyStream(message, data)
48
+				copy(args.Get(0).([]byte), message) // nolint: forcetypeassert
49
+			})
50
+
51
+		n, err := handshakeData.proxyConn.Read(buffer)
52
+
53
+		assert.EqualValues(t, len(data), n)
54
+		assert.NoError(t, err)
55
+		assert.Equal(t, data, buffer)
56
+		handshakeData.connMock.AssertExpectations(t)
57
+	})
58
+}

+ 9
- 48
mtglib/internal/obfuscated2/server_handshake_test.go Просмотреть файл

1
 package obfuscated2_test
1
 package obfuscated2_test
2
 
2
 
3
 import (
3
 import (
4
-	"bytes"
5
-	"crypto/aes"
6
-	"crypto/cipher"
7
-	"encoding/base64"
8
 	"testing"
4
 	"testing"
9
 
5
 
10
-	"github.com/9seconds/mtg/v2/internal/testlib"
11
-	"github.com/9seconds/mtg/v2/mtglib/internal/obfuscated2"
12
 	"github.com/stretchr/testify/mock"
6
 	"github.com/stretchr/testify/mock"
13
 	"github.com/stretchr/testify/suite"
7
 	"github.com/stretchr/testify/suite"
14
 )
8
 )
16
 type ServerHandshakeTestSuite struct {
10
 type ServerHandshakeTestSuite struct {
17
 	suite.Suite
11
 	suite.Suite
18
 
12
 
19
-	connMock  *testlib.EssentialsConnMock
20
-	proxyConn obfuscated2.Conn
21
-	encryptor cipher.Stream
22
-	decryptor cipher.Stream
13
+	data ServerHandshakeTestData
23
 }
14
 }
24
 
15
 
25
 func (suite *ServerHandshakeTestSuite) SetupTest() {
16
 func (suite *ServerHandshakeTestSuite) SetupTest() {
26
-	buf := &bytes.Buffer{}
27
-	suite.connMock = &testlib.EssentialsConnMock{}
28
-
29
-	encryptor, decryptor, err := obfuscated2.ServerHandshake(buf)
30
-	suite.NoError(err)
31
-
32
-	suite.proxyConn = obfuscated2.Conn{
33
-		Conn:      suite.connMock,
34
-		Encryptor: encryptor,
35
-		Decryptor: decryptor,
36
-	}
37
-
38
-	serverEncrypted := buf.Bytes()
39
-
40
-	decBlock, _ := aes.NewCipher(serverEncrypted[8 : 8+32])
41
-	suite.decryptor = cipher.NewCTR(decBlock, serverEncrypted[8+32:8+32+16])
42
-
43
-	serverDecrypted := make([]byte, len(serverEncrypted))
44
-	suite.decryptor.XORKeyStream(serverDecrypted, serverEncrypted)
45
-
46
-	suite.Equal("3d3d3Q",
47
-		base64.RawStdEncoding.EncodeToString(serverDecrypted[8+32+16:8+32+16+4]))
48
-
49
-	serverEncryptedReverted := make([]byte, len(serverEncrypted))
50
-
51
-	for i := 0; i < 32+16; i++ {
52
-		serverEncryptedReverted[8+i] = serverEncrypted[8+32+16-1-i]
53
-	}
54
-
55
-	encBlock, _ := aes.NewCipher(serverEncryptedReverted[8 : 8+32])
56
-	suite.encryptor = cipher.NewCTR(encBlock, serverEncryptedReverted[8+32:8+32+16])
17
+	suite.data = NewServerHandshakeTestData(suite.T())
57
 }
18
 }
58
 
19
 
59
 func (suite *ServerHandshakeTestSuite) TearDownTest() {
20
 func (suite *ServerHandshakeTestSuite) TearDownTest() {
60
-	suite.connMock.AssertExpectations(suite.T())
21
+	suite.data.connMock.AssertExpectations(suite.T())
61
 }
22
 }
62
 
23
 
63
 func (suite *ServerHandshakeTestSuite) TestSendToTelegram() {
24
 func (suite *ServerHandshakeTestSuite) TestSendToTelegram() {
64
 	messageToTelegram := []byte{10, 11, 12, 13, 14, 'a'}
25
 	messageToTelegram := []byte{10, 11, 12, 13, 14, 'a'}
65
 
26
 
66
-	suite.connMock.
27
+	suite.data.connMock.
67
 		On("Write", mock.Anything).
28
 		On("Write", mock.Anything).
68
 		Return(len(messageToTelegram), nil).
29
 		Return(len(messageToTelegram), nil).
69
 		Once().
30
 		Once().
70
 		Run(func(args mock.Arguments) {
31
 		Run(func(args mock.Arguments) {
71
 			message := make([]byte, len(messageToTelegram))
32
 			message := make([]byte, len(messageToTelegram))
72
-			suite.decryptor.XORKeyStream(message, args.Get(0).([]byte)) // nolint: forcetypeassert
33
+			suite.data.decryptor.XORKeyStream(message, args.Get(0).([]byte)) // nolint: forcetypeassert
73
 			suite.Equal(messageToTelegram, message)
34
 			suite.Equal(messageToTelegram, message)
74
 		})
35
 		})
75
 
36
 
76
-	n, err := suite.proxyConn.Write(messageToTelegram)
37
+	n, err := suite.data.proxyConn.Write(messageToTelegram)
77
 	suite.EqualValues(len(messageToTelegram), n)
38
 	suite.EqualValues(len(messageToTelegram), n)
78
 	suite.NoError(err)
39
 	suite.NoError(err)
79
 }
40
 }
82
 	messageFromTelegram := []byte{10, 11, 12, 13, 14, 'a'}
43
 	messageFromTelegram := []byte{10, 11, 12, 13, 14, 'a'}
83
 	buffer := make([]byte, len(messageFromTelegram))
44
 	buffer := make([]byte, len(messageFromTelegram))
84
 
45
 
85
-	suite.connMock.
46
+	suite.data.connMock.
86
 		On("Read", mock.Anything).
47
 		On("Read", mock.Anything).
87
 		Return(len(messageFromTelegram), nil).
48
 		Return(len(messageFromTelegram), nil).
88
 		Once().
49
 		Once().
89
 		Run(func(args mock.Arguments) {
50
 		Run(func(args mock.Arguments) {
90
 			message := make([]byte, len(messageFromTelegram))
51
 			message := make([]byte, len(messageFromTelegram))
91
-			suite.encryptor.XORKeyStream(message, messageFromTelegram)
52
+			suite.data.encryptor.XORKeyStream(message, messageFromTelegram)
92
 			copy(args.Get(0).([]byte), message) // nolint: forcetypeassert
53
 			copy(args.Get(0).([]byte), message) // nolint: forcetypeassert
93
 		})
54
 		})
94
 
55
 
95
-	n, err := suite.proxyConn.Read(buffer)
56
+	n, err := suite.data.proxyConn.Read(buffer)
96
 	suite.EqualValues(len(messageFromTelegram), n)
57
 	suite.EqualValues(len(messageFromTelegram), n)
97
 	suite.NoError(err)
58
 	suite.NoError(err)
98
 	suite.Equal(messageFromTelegram, buffer)
59
 	suite.Equal(messageFromTelegram, buffer)

+ 10
- 5
network/circuit_breaker.go Просмотреть файл

36
 }
36
 }
37
 
37
 
38
 func (c *circuitBreakerDialer) DialContext(ctx context.Context,
38
 func (c *circuitBreakerDialer) DialContext(ctx context.Context,
39
-	network, address string) (essentials.Conn, error) {
39
+	network, address string,
40
+) (essentials.Conn, error) {
40
 	switch atomic.LoadUint32(&c.state) {
41
 	switch atomic.LoadUint32(&c.state) {
41
 	case circuitBreakerStateClosed:
42
 	case circuitBreakerStateClosed:
42
 		return c.doClosed(ctx, network, address)
43
 		return c.doClosed(ctx, network, address)
48
 }
49
 }
49
 
50
 
50
 func (c *circuitBreakerDialer) doClosed(ctx context.Context,
51
 func (c *circuitBreakerDialer) doClosed(ctx context.Context,
51
-	network, address string) (essentials.Conn, error) {
52
+	network, address string,
53
+) (essentials.Conn, error) {
52
 	conn, err := c.Dialer.DialContext(ctx, network, address)
54
 	conn, err := c.Dialer.DialContext(ctx, network, address)
53
 
55
 
54
 	select {
56
 	select {
80
 }
82
 }
81
 
83
 
82
 func (c *circuitBreakerDialer) doHalfOpened(ctx context.Context,
84
 func (c *circuitBreakerDialer) doHalfOpened(ctx context.Context,
83
-	network, address string) (essentials.Conn, error) {
85
+	network, address string,
86
+) (essentials.Conn, error) {
84
 	if !atomic.CompareAndSwapUint32(&c.halfOpenAttempts, 0, 1) {
87
 	if !atomic.CompareAndSwapUint32(&c.halfOpenAttempts, 0, 1) {
85
 		return nil, ErrCircuitBreakerOpened
88
 		return nil, ErrCircuitBreakerOpened
86
 	}
89
 	}
174
 }
177
 }
175
 
178
 
176
 func (c *circuitBreakerDialer) ensureTimer(timerRef **time.Timer,
179
 func (c *circuitBreakerDialer) ensureTimer(timerRef **time.Timer,
177
-	timeout time.Duration, callback func()) {
180
+	timeout time.Duration, callback func(),
181
+) {
178
 	if *timerRef == nil {
182
 	if *timerRef == nil {
179
 		*timerRef = time.AfterFunc(timeout, callback)
183
 		*timerRef = time.AfterFunc(timeout, callback)
180
 	}
184
 	}
181
 }
185
 }
182
 
186
 
183
 func newCircuitBreakerDialer(baseDialer Dialer,
187
 func newCircuitBreakerDialer(baseDialer Dialer,
184
-	openThreshold uint32, halfOpenTimeout, resetFailuresTimeout time.Duration) Dialer {
188
+	openThreshold uint32, halfOpenTimeout, resetFailuresTimeout time.Duration,
189
+) Dialer {
185
 	cb := &circuitBreakerDialer{
190
 	cb := &circuitBreakerDialer{
186
 		Dialer:               baseDialer,
191
 		Dialer:               baseDialer,
187
 		stateMutexChan:       make(chan bool, 1),
192
 		stateMutexChan:       make(chan bool, 1),

+ 6
- 3
network/network.go Просмотреть файл

61
 }
61
 }
62
 
62
 
63
 func (n *network) MakeHTTPClient(dialFunc func(ctx context.Context,
63
 func (n *network) MakeHTTPClient(dialFunc func(ctx context.Context,
64
-	network, address string) (essentials.Conn, error)) *http.Client {
64
+	network, address string) (essentials.Conn, error),
65
+) *http.Client {
65
 	if dialFunc == nil {
66
 	if dialFunc == nil {
66
 		dialFunc = n.DialContext
67
 		dialFunc = n.DialContext
67
 	}
68
 	}
123
 // It brings simple DNS cache and DNS-Over-HTTPS when necessary.
124
 // It brings simple DNS cache and DNS-Over-HTTPS when necessary.
124
 func NewNetwork(dialer Dialer,
125
 func NewNetwork(dialer Dialer,
125
 	userAgent, dohHostname string,
126
 	userAgent, dohHostname string,
126
-	httpTimeout time.Duration) (mtglib.Network, error) {
127
+	httpTimeout time.Duration,
128
+) (mtglib.Network, error) {
127
 	switch {
129
 	switch {
128
 	case httpTimeout < 0:
130
 	case httpTimeout < 0:
129
 		return nil, fmt.Errorf("timeout should be positive number %s", httpTimeout)
131
 		return nil, fmt.Errorf("timeout should be positive number %s", httpTimeout)
146
 
148
 
147
 func makeHTTPClient(userAgent string,
149
 func makeHTTPClient(userAgent string,
148
 	timeout time.Duration,
150
 	timeout time.Duration,
149
-	dialFunc func(ctx context.Context, network, address string) (essentials.Conn, error)) *http.Client {
151
+	dialFunc func(ctx context.Context, network, address string) (essentials.Conn, error),
152
+) *http.Client {
150
 	return &http.Client{
153
 	return &http.Client{
151
 		Timeout: timeout,
154
 		Timeout: timeout,
152
 		Transport: networkHTTPTransport{
155
 		Transport: networkHTTPTransport{

+ 2
- 1
stats/statsd.go Просмотреть файл

171
 //
171
 //
172
 // Valid tagFormats are 'datadog', 'influxdb' and 'graphite'.
172
 // Valid tagFormats are 'datadog', 'influxdb' and 'graphite'.
173
 func NewStatsd(address string, log logger.StdLikeLogger,
173
 func NewStatsd(address string, log logger.StdLikeLogger,
174
-	metricPrefix, tagFormat string) (StatsdFactory, error) {
174
+	metricPrefix, tagFormat string,
175
+) (StatsdFactory, error) {
175
 	options := []statsd.Option{
176
 	options := []statsd.Option{
176
 		statsd.MetricPrefix(metricPrefix),
177
 		statsd.MetricPrefix(metricPrefix),
177
 		statsd.Logger(log),
178
 		statsd.Logger(log),

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