Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ulixee
GitHub Repository: ulixee/secret-agent
Path: blob/main/mitm-socket/go/domain_socket_piper.go
1029 views
1
package main
2
3
import (
4
"errors"
5
"fmt"
6
"io"
7
"net"
8
"sync"
9
"time"
10
)
11
12
type DomainSocketPiper struct {
13
id int
14
client net.Conn
15
isClosed bool
16
wg sync.WaitGroup
17
signals *Signals
18
debug bool
19
}
20
21
func (piper *DomainSocketPiper) Pipe(remote net.Conn) {
22
client := piper.client
23
24
piper.wg.Add(2)
25
clientHasDataChan := make(chan bool, 1)
26
// Pipe data
27
go piper.copy(client, remote, clientHasDataChan, true)
28
go piper.copy(remote, client, clientHasDataChan, false)
29
30
piper.wg.Wait()
31
SendToIpc(piper.id, "closing", nil)
32
}
33
34
func (piper *DomainSocketPiper) copy(dst net.Conn, src net.Conn, clientHasData chan bool, isReadingFromRemote bool) {
35
var totalBytes int64
36
var n int
37
var w int
38
var neterr net.Error
39
var ok bool
40
var writeErr error
41
var readErr error
42
var direction string
43
var waitForData bool
44
45
if piper.debug {
46
if isReadingFromRemote {
47
direction = "from remote"
48
} else {
49
direction = "from client"
50
}
51
}
52
53
data := make([]byte, 5*1096)
54
55
defer piper.wg.Done()
56
57
for {
58
if isReadingFromRemote == true && waitForData {
59
select {
60
case <-clientHasData:
61
waitForData = false
62
case <-time.After(50 * time.Millisecond):
63
if piper.signals.IsClosed || piper.isClosed {
64
return
65
}
66
}
67
if waitForData {
68
continue
69
}
70
}
71
src.SetReadDeadline(time.Now().Add(2 * time.Second)) // Set the deadline
72
n, readErr = src.Read(data)
73
74
if n > 0 {
75
if isReadingFromRemote == false && len(clientHasData) == 0 {
76
clientHasData <- true
77
}
78
w, writeErr = dst.Write(data[0:n])
79
if w < 0 || n < w {
80
w = 0
81
if writeErr == nil {
82
writeErr = errors.New("invalid write result")
83
}
84
}
85
totalBytes += int64(w)
86
87
if writeErr == nil && n != w {
88
writeErr = io.ErrShortWrite
89
}
90
if writeErr != nil {
91
SendErrorToIpc(piper.id, "writeErr", writeErr)
92
piper.isClosed = true
93
return
94
}
95
}
96
97
if piper.debug {
98
fmt.Printf("[id=%d] Read %d bytes %s. Total: %d\n", piper.id, n, direction, totalBytes)
99
}
100
101
if n == 0 && readErr == io.EOF {
102
if isReadingFromRemote {
103
if totalBytes == 0 {
104
piper.isClosed = true
105
return
106
}
107
108
SendToIpc(piper.id, "eof", nil)
109
if len(clientHasData) > 0 {
110
// drain
111
<-clientHasData
112
}
113
waitForData = true
114
} else {
115
piper.isClosed = true
116
return
117
}
118
}
119
120
if readErr != nil && readErr != io.EOF {
121
neterr, ok = readErr.(net.Error)
122
// if not a timeout, stop and return
123
if !ok || !neterr.Timeout() {
124
SendErrorToIpc(piper.id, "readErr", readErr)
125
piper.isClosed = true
126
return
127
}
128
}
129
130
if piper.signals.IsClosed || piper.isClosed {
131
return
132
}
133
134
if n == 0 || readErr != nil {
135
time.Sleep(50 * time.Millisecond)
136
}
137
}
138
}
139
140
func (piper *DomainSocketPiper) Close() {
141
piper.isClosed = true
142
}
143
144