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

Rewrite cloaking

tags/v1.0.2^2
9seconds 6 лет назад
Родитель
Сommit
93686377d5
3 измененных файлов: 111 добавлений и 20 удалений
  1. 1
    20
      faketls/client_protocol.go
  2. 62
    0
      faketls/cloak.go
  3. 48
    0
      wrappers/rwc/ping.go

+ 1
- 20
faketls/client_protocol.go Просмотреть файл

@@ -8,7 +8,6 @@ import (
8 8
 	"io"
9 9
 	"net"
10 10
 	"strconv"
11
-	"sync"
12 11
 	"time"
13 12
 
14 13
 	"github.com/9seconds/mtg/antireplay"
@@ -110,25 +109,7 @@ func (c *ClientProtocol) cloakHost(clientConn io.ReadWriteCloser) {
110 109
 		return
111 110
 	}
112 111
 
113
-	defer hostConn.Close()
114
-
115
-	wg := &sync.WaitGroup{}
116
-	wg.Add(2)
117
-
118
-	go c.pipe(hostConn, clientConn, wg)
119
-
120
-	go c.pipe(clientConn, hostConn, wg)
121
-
122
-	wg.Wait()
123
-}
124
-
125
-func (c *ClientProtocol) pipe(dst io.WriteCloser, src io.Reader, wg *sync.WaitGroup) {
126
-	defer func() {
127
-		wg.Done()
128
-		dst.Close()
129
-	}()
130
-
131
-	io.Copy(dst, src) // nolint: errcheck
112
+	cloak(clientConn, hostConn)
132 113
 }
133 114
 
134 115
 func MakeClientProtocol() protocol.ClientProtocol {

+ 62
- 0
faketls/cloak.go Просмотреть файл

@@ -0,0 +1,62 @@
1
+package faketls
2
+
3
+import (
4
+	"context"
5
+	"io"
6
+	"sync"
7
+	"time"
8
+
9
+	"github.com/9seconds/mtg/wrappers/rwc"
10
+)
11
+
12
+const cloakTimeout = 5 * time.Second
13
+
14
+func cloak(one, another io.ReadWriteCloser) {
15
+	defer func() {
16
+		one.Close()
17
+		another.Close()
18
+	}()
19
+
20
+	channelPing := make(chan struct{}, 1)
21
+	ctx, cancel := context.WithCancel(context.Background())
22
+	one = rwc.NewPing(ctx, one, channelPing)
23
+	another = rwc.NewPing(ctx, another, channelPing)
24
+	wg := &sync.WaitGroup{}
25
+
26
+	wg.Add(2)
27
+
28
+	go func() {
29
+		defer wg.Done()
30
+		io.Copy(one, another) // nolint: errcheck
31
+	}()
32
+
33
+	go func() {
34
+		defer wg.Done()
35
+		io.Copy(another, one) // nolint: errcheck
36
+	}()
37
+
38
+	go func() {
39
+		wg.Wait()
40
+		cancel()
41
+	}()
42
+
43
+	go func() {
44
+		timer := time.NewTimer(cloakTimeout)
45
+		defer timer.Stop()
46
+
47
+		for {
48
+			select {
49
+			case <-channelPing:
50
+				timer.Stop()
51
+				timer = time.NewTimer(cloakTimeout)
52
+			case <-ctx.Done():
53
+				return
54
+			case <-timer.C:
55
+				cancel()
56
+				return
57
+			}
58
+		}
59
+	}()
60
+
61
+	<-ctx.Done()
62
+}

+ 48
- 0
wrappers/rwc/ping.go Просмотреть файл

@@ -0,0 +1,48 @@
1
+package rwc
2
+
3
+import (
4
+	"context"
5
+	"io"
6
+)
7
+
8
+type wrapperPing struct {
9
+	parent      io.ReadWriteCloser
10
+	ctx         context.Context
11
+	channelPing chan<- struct{}
12
+}
13
+
14
+func (w *wrapperPing) Read(p []byte) (int, error) {
15
+	n, err := w.parent.Read(p)
16
+	if err == nil {
17
+		select {
18
+		case <-w.ctx.Done():
19
+		case w.channelPing <- struct{}{}:
20
+		}
21
+	}
22
+
23
+	return n, err
24
+}
25
+
26
+func (w *wrapperPing) Write(p []byte) (int, error) {
27
+	n, err := w.parent.Write(p)
28
+	if err == nil {
29
+		select {
30
+		case <-w.ctx.Done():
31
+		case w.channelPing <- struct{}{}:
32
+		}
33
+	}
34
+
35
+	return n, err
36
+}
37
+
38
+func (w *wrapperPing) Close() error {
39
+	return w.parent.Close()
40
+}
41
+
42
+func NewPing(ctx context.Context, parent io.ReadWriteCloser, channelPing chan<- struct{}) io.ReadWriteCloser {
43
+	return &wrapperPing{
44
+		parent:      parent,
45
+		ctx:         ctx,
46
+		channelPing: channelPing,
47
+	}
48
+}

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