2ch commited on
Commit
d2f89dd
·
verified ·
1 Parent(s): ddc158d
go.mod ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ module gotunnelme/go_localt
2
+
3
+ go 1.22.1
4
+
5
+ require github.com/NoahShen/gotunnelme v0.0.0-20180106044115-fbc9b0b77df8 // indirect
go.sum ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ github.com/NoahShen/gotunnelme v0.0.0-20180106044115-fbc9b0b77df8 h1:9PnWTGpbxbF4rwTL7q+5ozPyG/pr1NfXXaFTmLXkb5s=
2
+ github.com/NoahShen/gotunnelme v0.0.0-20180106044115-fbc9b0b77df8/go.mod h1:4/5P3Xn6TPHLWG1iHNwvob7WPT3+kr8wBcW/xueIqe4=
main.go ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package main
2
+
3
+ import (
4
+ "fmt"
5
+ "github.com/NoahShen/gotunnelme/src/gotunnelme"
6
+ "io/ioutil"
7
+ "net/http"
8
+ "os"
9
+ "strconv"
10
+ )
11
+
12
+ func getExternalIP() (string, error) {
13
+ resp, err := http.Get("http://ipinfo.io/ip")
14
+ if err != nil {
15
+ return "", err
16
+ }
17
+ defer resp.Body.Close()
18
+ ip, err := ioutil.ReadAll(resp.Body)
19
+ if err != nil {
20
+ return "", err
21
+ }
22
+ return string(ip), nil
23
+ }
24
+
25
+ func main() {
26
+ if len(os.Args) == 1 {
27
+ fmt.Fprintln(os.Stderr, "Usage: go_localt <local port>")
28
+ os.Exit(1)
29
+ }
30
+ localPort, err := strconv.Atoi(os.Args[1])
31
+ if err != nil {
32
+ fmt.Fprintln(os.Stderr, err)
33
+ os.Exit(1)
34
+ }
35
+
36
+ t := gotunnelme.NewTunnel()
37
+ url, err := t.GetUrl("")
38
+ if err != nil {
39
+ panic(err)
40
+ }
41
+ fmt.Println(url)
42
+
43
+ extIP, err := getExternalIP()
44
+ if err != nil {
45
+ panic(err)
46
+ }
47
+ fmt.Println(extIP)
48
+
49
+ err = t.CreateTunnel(localPort)
50
+ if err != nil {
51
+ panic(err)
52
+ }
53
+ t.StopTunnel()
54
+ }
src/gotunnelme/get_assigned_url.go ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package gotunnelme
2
+
3
+ import (
4
+ "encoding/json"
5
+ "fmt"
6
+ "io/ioutil"
7
+ "net/http"
8
+ )
9
+
10
+ const (
11
+ localtunnelServer = "http://localtunnel.me/"
12
+ )
13
+
14
+ type AssignedUrlInfo struct {
15
+ Id string `json:"id,omitempty"`
16
+ Url string `json:"url,omitempty"`
17
+ Port int `json:"port,omitempty"`
18
+ MaxConnCount int `json:"max_conn_count,omitempty"`
19
+ }
20
+
21
+ func GetAssignedUrl(assignedDomain string) (*AssignedUrlInfo, error) {
22
+ if len(assignedDomain) == 0 {
23
+ assignedDomain = "?new"
24
+ }
25
+ url := fmt.Sprintf(localtunnelServer+"%s", assignedDomain)
26
+ request, _ := http.NewRequest("GET", url, nil)
27
+ response, httpErr := http.DefaultClient.Do(request)
28
+ if httpErr != nil {
29
+ return nil, httpErr
30
+ }
31
+ defer response.Body.Close()
32
+ bytes, readErr := ioutil.ReadAll(response.Body)
33
+ if readErr != nil {
34
+ return nil, readErr
35
+ }
36
+ if Debug {
37
+ fmt.Printf("***GetAssignedUrl: %s\n", string(bytes))
38
+ }
39
+
40
+ assignedUrlInfo := &AssignedUrlInfo{}
41
+ if unmarshalErr := json.Unmarshal(bytes, assignedUrlInfo); unmarshalErr != nil {
42
+ return nil, unmarshalErr
43
+ }
44
+ return assignedUrlInfo, nil
45
+ }
src/gotunnelme/get_assigned_url_test.go ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package gotunnelme
2
+
3
+ import (
4
+ "fmt"
5
+ "testing"
6
+ )
7
+
8
+ func _TestGetAssignedUrl(t *testing.T) {
9
+ Debug = false
10
+ assignedUrlInfo, err := GetAssignedUrl("noah")
11
+ if err != nil {
12
+ t.Fatal(err)
13
+ }
14
+ fmt.Printf("assignedUrlInfo: %+v\n", assignedUrlInfo)
15
+ }
src/gotunnelme/tunnel.go ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package gotunnelme
2
+
3
+ import (
4
+ "bufio"
5
+ "errors"
6
+ "fmt"
7
+ "io"
8
+ "net"
9
+ "net/http"
10
+ "net/url"
11
+ "os"
12
+ "strings"
13
+ )
14
+
15
+ var Debug = false
16
+
17
+ type TunnelConn struct {
18
+ remoteHost string
19
+ remotePort int
20
+ localPort int
21
+ remoteConn net.Conn
22
+ localConn net.Conn
23
+ errorChannel chan error
24
+ }
25
+
26
+ func NewTunnelConn(remoteHost string, remotePort, localPort int) *TunnelConn {
27
+ tunnelConn := &TunnelConn{}
28
+ tunnelConn.remoteHost = remoteHost
29
+ tunnelConn.remotePort = remotePort
30
+ tunnelConn.localPort = localPort
31
+ return tunnelConn
32
+ }
33
+
34
+ func (self *TunnelConn) Tunnel(replyCh chan<- int) error {
35
+ self.errorChannel = make(chan error, 1) // clear previous channel's message
36
+ remoteConn, remoteErr := self.connectRemote()
37
+ if remoteErr != nil {
38
+ if Debug {
39
+ fmt.Printf("Connect remote error[%s]!\n", remoteErr.Error())
40
+ }
41
+ replyCh <- -1
42
+ return remoteErr
43
+ }
44
+
45
+ if Debug {
46
+ fmt.Printf("Connect remote[%s:%d] successful!\n", self.remoteHost, self.remotePort)
47
+ }
48
+
49
+ localConn, localErr := self.connectLocal()
50
+ if localErr != nil {
51
+ if Debug {
52
+ fmt.Printf("Connect local error[%s]!\n", localErr.Error())
53
+ }
54
+ replyCh <- -1
55
+ return localErr
56
+ }
57
+ if Debug {
58
+ fmt.Printf("Connect local[:%d] successful!\n", self.localPort)
59
+ }
60
+
61
+ self.remoteConn = remoteConn
62
+ self.localConn = localConn
63
+ go func() {
64
+ var err error
65
+ for {
66
+ _, err = io.Copy(remoteConn, localConn)
67
+ if err != nil {
68
+ if Debug {
69
+ fmt.Printf("Stop copy form local to remote! error=[%v]\n", err)
70
+ }
71
+ break
72
+ }
73
+ }
74
+ self.errorChannel <- err
75
+ }()
76
+ go func() {
77
+ var err error
78
+ for {
79
+ _, err = io.Copy(localConn, remoteConn)
80
+ if err != nil {
81
+ if Debug {
82
+ fmt.Printf("Stop copy form remote to local! error=[%v]\n", err)
83
+ }
84
+ break
85
+ }
86
+
87
+ }
88
+ self.errorChannel <- err
89
+ }()
90
+ err := <-self.errorChannel
91
+ replyCh <- 1
92
+ return err
93
+ }
94
+
95
+ func (self *TunnelConn) StopTunnel() error {
96
+ if self.remoteConn != nil {
97
+ self.remoteConn.Close()
98
+ }
99
+ if self.localConn != nil {
100
+ self.localConn.Close()
101
+ }
102
+ return nil
103
+ }
104
+
105
+ func (self *TunnelConn) connectRemote() (net.Conn, error) {
106
+ remoteAddr := fmt.Sprintf("%s:%d", self.remoteHost, self.remotePort)
107
+ addr := remoteAddr
108
+ proxy := os.Getenv("HTTP_PROXY")
109
+ if proxy == "" {
110
+ proxy = os.Getenv("http_proxy")
111
+ }
112
+ if len(proxy) > 0 {
113
+ url, err := url.Parse(proxy)
114
+ if err == nil {
115
+ addr = url.Host
116
+ }
117
+ }
118
+ remoteConn, remoteErr := net.Dial("tcp", addr)
119
+ if remoteErr != nil {
120
+ return nil, remoteErr
121
+ }
122
+
123
+ if len(proxy) > 0 {
124
+ fmt.Fprintf(remoteConn, "CONNECT %s HTTP/1.1\r\n", remoteAddr)
125
+ fmt.Fprintf(remoteConn, "Host: %s\r\n", remoteAddr)
126
+ fmt.Fprintf(remoteConn, "\r\n")
127
+ br := bufio.NewReader(remoteConn)
128
+ req, _ := http.NewRequest("CONNECT", remoteAddr, nil)
129
+ resp, readRespErr := http.ReadResponse(br, req)
130
+ if readRespErr != nil {
131
+ return nil, readRespErr
132
+ }
133
+ if resp.StatusCode != 200 {
134
+ f := strings.SplitN(resp.Status, " ", 2)
135
+ return nil, errors.New(f[1])
136
+ }
137
+
138
+ if Debug {
139
+ fmt.Printf("Connect %s by proxy[%s].\n", remoteAddr, proxy)
140
+ }
141
+ }
142
+ return remoteConn, nil
143
+ }
144
+
145
+ func (self *TunnelConn) connectLocal() (net.Conn, error) {
146
+ localAddr := fmt.Sprintf("%s:%d", "localhost", self.localPort)
147
+ return net.Dial("tcp", localAddr)
148
+ }
149
+
150
+ type TunnelCommand int
151
+
152
+ const (
153
+ stopTunnelCmd TunnelCommand = 1
154
+ )
155
+
156
+ type Tunnel struct {
157
+ assignedUrlInfo *AssignedUrlInfo
158
+ localPort int
159
+ tunnelConns []*TunnelConn
160
+ cmdChan chan TunnelCommand
161
+ }
162
+
163
+ func NewTunnel() *Tunnel {
164
+ tunnel := &Tunnel{}
165
+ tunnel.cmdChan = make(chan TunnelCommand, 1)
166
+ return tunnel
167
+ }
168
+
169
+ func (self *Tunnel) startTunnel() error {
170
+ if err := self.checkLocalPort(); err != nil {
171
+ return err
172
+ }
173
+ url, parseErr := url.Parse(localtunnelServer)
174
+ if parseErr != nil {
175
+ return parseErr
176
+ }
177
+ replyCh := make(chan int, self.assignedUrlInfo.MaxConnCount)
178
+ remoteHost := url.Host
179
+ for i := 0; i < self.assignedUrlInfo.MaxConnCount; i++ {
180
+ tunnelConn := NewTunnelConn(remoteHost, self.assignedUrlInfo.Port, self.localPort)
181
+ self.tunnelConns[i] = tunnelConn
182
+ go tunnelConn.Tunnel(replyCh)
183
+ }
184
+ L:
185
+ for i := 0; i < self.assignedUrlInfo.MaxConnCount; i++ {
186
+ select {
187
+ case <-replyCh:
188
+ case cmd := <-self.cmdChan:
189
+ switch cmd {
190
+ case stopTunnelCmd:
191
+ break L
192
+ }
193
+ }
194
+ }
195
+
196
+ return nil
197
+ }
198
+
199
+ func (self *Tunnel) checkLocalPort() error {
200
+ localAddr := fmt.Sprintf("%s:%d", "localhost", self.localPort)
201
+ c, err := net.Dial("tcp", localAddr)
202
+ if err != nil {
203
+ return errors.New("can't connect local port!")
204
+ }
205
+ c.Close()
206
+ return nil
207
+ }
208
+
209
+ func (self *Tunnel) StopTunnel() {
210
+ if Debug {
211
+ fmt.Printf("Stop tunnel for localPort[%d]!\n", self.localPort)
212
+ }
213
+ self.cmdChan <- stopTunnelCmd
214
+ for _, tunnelCon := range self.tunnelConns {
215
+ tunnelCon.StopTunnel()
216
+ }
217
+ }
218
+
219
+ func (self *Tunnel) GetUrl(assignedDomain string) (string, error) {
220
+ if len(assignedDomain) == 0 {
221
+ assignedDomain = "?new"
222
+ }
223
+ assignedUrlInfo, err := GetAssignedUrl(assignedDomain)
224
+ if err != nil {
225
+ return "", err
226
+ }
227
+ self.assignedUrlInfo = assignedUrlInfo
228
+ self.tunnelConns = make([]*TunnelConn, assignedUrlInfo.MaxConnCount)
229
+ return assignedUrlInfo.Url, nil
230
+ }
231
+
232
+ func (self *Tunnel) CreateTunnel(localPort int) error {
233
+ self.localPort = localPort
234
+ return self.startTunnel()
235
+ }
src/gotunnelme/tunnel_test.go ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ package gotunnelme
2
+
3
+ import (
4
+ "fmt"
5
+ "testing"
6
+ "time"
7
+ )
8
+
9
+ func TestTunnel(t *testing.T) {
10
+ Debug = true
11
+ tunnel := NewTunnel()
12
+ url, getUrlErr := tunnel.GetUrl("noah")
13
+ if getUrlErr != nil {
14
+ t.Fatal(getUrlErr)
15
+ }
16
+ fmt.Println("Get Url:", url)
17
+ go func() {
18
+ tunnelErr := tunnel.CreateTunnel(8787)
19
+ if tunnelErr != nil {
20
+ t.Fatal(tunnelErr)
21
+ }
22
+ }()
23
+ time.Sleep(30 * time.Second)
24
+ tunnel.StopTunnel()
25
+ }