-
Notifications
You must be signed in to change notification settings - Fork 4
/
tun2socks.go
207 lines (185 loc) · 5.51 KB
/
tun2socks.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
package tun2socks
import (
"errors"
"fmt"
"github.com/txthinking/brook"
"io"
"net"
"os"
"strings"
"time"
"github.com/eycorsican/go-tun2socks/common/dns/cache"
"github.com/eycorsican/go-tun2socks/common/dns/fakedns"
"github.com/eycorsican/go-tun2socks/common/log"
"github.com/eycorsican/go-tun2socks/common/log/simpleandroidlog" // Register a simple android logger.
"github.com/eycorsican/go-tun2socks/component/pool"
"github.com/eycorsican/go-tun2socks/component/runner"
"github.com/eycorsican/go-tun2socks/core"
"github.com/eycorsican/go-tun2socks/proxy/socks"
"github.com/songgao/water"
)
var client *brook.WSClient = nil
func StartClient(socks string, serverAddress string, password string) {
c, err := brook.NewWSClient(socks, "127.0.0.1", serverAddress, password, 60, 60)
if err != nil {
fmt.Println(err)
}
client = c
client.WithoutBrook = false
client.TLSConfig.InsecureSkipVerify = true
client.ListenAndServe()
}
func StopClient() {
client.Shutdown()
}
type Tun2socksStartOptions struct {
TunFd int
Socks5Server string
FakeIPRange string
MTU int
EnableIPv6 bool
AllowLan bool
}
var (
lwipWriter io.Writer
lwipStack core.LWIPStack
mtuUsed int
lwipTUNDataPipeTask *runner.Task
tunDev *water.Interface
)
// Stop stop it
func Stop() {
log.Infof("enter stop")
log.Infof("begin close tun")
err := tunDev.Close()
if err != nil {
log.Infof("close tun(Stop func): %v", err)
}
if lwipTUNDataPipeTask.Running() {
log.Infof("send stop lwipTUNDataPipeTask sig")
lwipTUNDataPipeTask.Stop()
log.Infof("lwipTUNDataPipeTask stop sig sent")
<-lwipTUNDataPipeTask.StopChan()
} else {
log.Infof("lwipTUNDataPipeTask already stopped")
}
log.Infof("begin close lwipStack")
lwipStack.Close(core.DELAY)
}
// hack to receive tunfd
func openTunDevice(tunFd int) (*water.Interface, error) {
file := os.NewFile(uintptr(tunFd), "tun") // dummy file path name since we already got the fd
tunDev = &water.Interface{
ReadWriteCloser: file,
}
return tunDev, nil
}
// Start sets up lwIP stack, starts a Tun2socks instance
func Start(opt *Tun2socksStartOptions) int {
mtuUsed = opt.MTU
var err error
tunDev, err = openTunDevice(opt.TunFd)
if err != nil {
log.Fatalf("failed to open tun device: %v", err)
}
// handle previous lwIP stack
if lwipStack != nil {
log.Infof("begin close previous lwipStack")
lwipStack.Close(core.INSTANT)
} else {
log.Infof("do NOT have to close previous lwipStack")
}
// Setup the lwIP stack.
lwipStack = core.NewLWIPStack(opt.EnableIPv6, opt.AllowLan)
lwipWriter = lwipStack.(io.Writer)
// Register tun2socks connection handlers.
proxyAddr, err := net.ResolveTCPAddr("tcp", opt.Socks5Server)
proxyHost := proxyAddr.IP.String()
proxyPort := uint16(proxyAddr.Port)
if err != nil {
log.Infof("invalid proxy server address: %v", err)
return -1
}
cacheDNS := cache.NewSimpleDnsCache()
if opt.FakeIPRange != "" {
_, ipnet, err := net.ParseCIDR(opt.FakeIPRange)
if err != nil {
log.Fatalf("failed to parse fake ip range %v", opt.FakeIPRange)
}
fakeDNS := fakedns.NewFakeDNS(ipnet, 3000)
core.RegisterTCPConnHandler(socks.NewTCPHandler(proxyHost, proxyPort, fakeDNS))
core.RegisterUDPConnHandler(socks.NewUDPHandler(proxyHost, proxyPort, 30*time.Second, cacheDNS, fakeDNS))
} else {
core.RegisterTCPConnHandler(socks.NewTCPHandler(proxyHost, proxyPort, nil))
core.RegisterUDPConnHandler(socks.NewUDPHandler(proxyHost, proxyPort, 30*time.Second, cacheDNS, nil))
}
// Register an output callback to write packets output from lwip stack to tun
// device, output function should be set before input any packets.
core.RegisterOutputFn(func(data []byte) (int, error) {
// lwip -> tun
return tunDev.Write(data)
})
if lwipTUNDataPipeTask != nil && lwipTUNDataPipeTask.Running() {
log.Infof("stop previous lwipTUNDataPipeTask sig")
lwipTUNDataPipeTask.Stop()
log.Infof("previous lwipTUNDataPipeTask stop sig sent")
<-lwipTUNDataPipeTask.StopChan()
} else {
log.Infof("previous lwipTUNDataPipeTask already stopped or never being started")
}
lwipTUNDataPipeTask = runner.Go(func(shouldStop runner.S) error {
// do setup
// defer func(){
// // do teardown
// }()
zeroErr := errors.New("no error")
maxErrorTimes := 20
for {
// NOTE: the for-loop here will retry when we find errors,
// it gives up when we reach exceeded error times.
// do some work here
// tun -> lwip
buf := pool.NewBytes(pool.BufSize)
// NOTE: In general, when transfering the data, it blocks here until either end becomes invalid
_, err := io.CopyBuffer(lwipWriter, tunDev, buf)
pool.FreeBytes(buf)
if err != nil {
maxErrorTimes--
log.Infof("copying data failed: %v", err)
}
if shouldStop() {
log.Infof("got DataPipe stop signal")
break
}
if maxErrorTimes <= 0 {
log.Infof("lwipTUNDataPipeTask returns due to exceeded error times")
return err
}
}
log.Infof("exit DataPipe loop")
return zeroErr // any errors?
})
log.Infof("Running tun2socks")
return 0
}
// SetLoglevel set tun2socks log level
// possible input: debug/info/warn/error/none
func SetLoglevel(logLevel string) {
// Set log level.
switch strings.ToLower(logLevel) {
case "debug":
log.SetLevel(log.DEBUG)
case "info":
log.SetLevel(log.INFO)
case "warn":
log.SetLevel(log.WARN)
case "error":
log.SetLevel(log.ERROR)
case "none":
log.SetLevel(log.NONE)
default:
panic("unsupport logging level")
}
logger := simpleandroidlog.GetLogger()
log.Infof("LogLevel: %v", logger.GetLevel())
}