Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
G
gost
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
0
Issues
0
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nanahira
gost
Commits
445889c4
Commit
445889c4
authored
Dec 31, 2018
by
ginuerzh
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add more test cases for socks5
parent
72d7850c
Changes
23
Show whitespace changes
Inline
Side-by-side
Showing
23 changed files
with
1168 additions
and
417 deletions
+1168
-417
.travis.yml
.travis.yml
+2
-2
bypass_test.go
bypass_test.go
+11
-4
cmd/gost/.config/dns.txt
cmd/gost/.config/dns.txt
+5
-3
cmd/gost/cfg.go
cmd/gost/cfg.go
+2
-5
common_test.go
common_test.go
+126
-8
forward.go
forward.go
+0
-11
forward_test.go
forward_test.go
+0
-34
gost.go
gost.go
+47
-0
handler_test.go
handler_test.go
+16
-11
hosts_test.go
hosts_test.go
+10
-1
http2.go
http2.go
+3
-33
http_test.go
http_test.go
+0
-81
kcp.go
kcp.go
+5
-0
mux.go
mux.go
+6
-0
obfs.go
obfs.go
+1
-1
quic_test.go
quic_test.go
+55
-0
resolver.go
resolver.go
+33
-33
resolver_test.go
resolver_test.go
+8
-14
socks.go
socks.go
+344
-43
socks_test.go
socks_test.go
+348
-0
ss_test.go
ss_test.go
+18
-14
tls.go
tls.go
+12
-11
ws.go
ws.go
+116
-108
No files found.
.travis.yml
View file @
445889c4
...
...
@@ -5,8 +5,8 @@ go:
install
:
true
script
:
-
env GO111MODULE=on
go test -race -v -coverprofile=coverage.txt -covermode=atomic
-
cd cmd/gost &&
env GO111MODULE=on
go build
-
go test -race -v -coverprofile=coverage.txt -covermode=atomic
-
cd cmd/gost && go build
after_success
:
-
bash <(curl -s https://codecov.io/bash)
bypass_test.go
View file @
445889c4
...
...
@@ -2,6 +2,7 @@ package gost
import
(
"bytes"
"fmt"
"io"
"testing"
"time"
...
...
@@ -158,10 +159,13 @@ var bypassContainTests = []struct {
func
TestBypassContains
(
t
*
testing
.
T
)
{
for
i
,
tc
:=
range
bypassContainTests
{
tc
:=
tc
t
.
Run
(
fmt
.
Sprintf
(
"#%d"
,
i
),
func
(
t
*
testing
.
T
)
{
bp
:=
NewBypassPatterns
(
tc
.
reversed
,
tc
.
patterns
...
)
if
bp
.
Contains
(
tc
.
addr
)
!=
tc
.
bypassed
{
t
.
Errorf
(
"#%d test failed: %v, %s"
,
i
,
tc
.
patterns
,
tc
.
addr
)
}
})
}
}
...
...
@@ -244,6 +248,9 @@ func TestByapssReload(t *testing.T) {
}
if
tc
.
stopped
{
bp
.
Stop
()
if
bp
.
Period
()
>=
0
{
t
.
Errorf
(
"period of the stopped reloader should be minus value"
)
}
}
if
bp
.
Stopped
()
!=
tc
.
stopped
{
t
.
Errorf
(
"#%d test failed: stopped value should be %v, got %v"
,
...
...
cmd/gost/.config/dns.txt
View file @
445889c4
# resolver timeout, default 30s.
timeout 10s
# resolver cache TTL, default 60s, minus value means that cache is disabled.
ttl 300s
# resolver cache TTL,
# minus value means that cache is disabled,
# default to the TTL in DNS server response.
# ttl 300s
# period for live reloading
reload 10s
# ip[:port] [protocol] [hostname]
https://1.0.0.1/dns-query
1.1.1.1:853 tls cloudflare-dns.com
https://1.0.0.1/dns-query https
8.8.8.8
8.8.8.8 tcp
1.1.1.1 udp
...
...
cmd/gost/cfg.go
View file @
445889c4
...
...
@@ -10,7 +10,6 @@ import (
"net/url"
"os"
"strings"
"time"
"github.com/ginuerzh/gost"
)
...
...
@@ -196,8 +195,6 @@ func parseResolver(cfg string) gost.Resolver {
if
cfg
==
""
{
return
nil
}
timeout
:=
30
*
time
.
Second
ttl
:=
60
*
time
.
Second
var
nss
[]
gost
.
NameServer
f
,
err
:=
os
.
Open
(
cfg
)
...
...
@@ -237,11 +234,11 @@ func parseResolver(cfg string) gost.Resolver {
}
}
}
return
gost
.
NewResolver
(
timeout
,
ttl
,
nss
...
)
return
gost
.
NewResolver
(
0
,
nss
...
)
}
defer
f
.
Close
()
resolver
:=
gost
.
NewResolver
(
timeout
,
ttl
)
resolver
:=
gost
.
NewResolver
(
0
)
resolver
.
Reload
(
f
)
go
gost
.
PeriodReload
(
resolver
,
cfg
)
...
...
common_test.go
View file @
445889c4
package
gost
import
(
"bufio"
"bytes"
"crypto/tls"
"errors"
"fmt"
"io"
"io/ioutil"
"net"
"net/http"
"net/url"
"sync"
"time"
)
...
...
@@ -37,6 +41,110 @@ var (
})
)
// proxyConn obtains a connection to the proxy server.
func
proxyConn
(
client
*
Client
,
server
*
Server
)
(
net
.
Conn
,
error
)
{
conn
,
err
:=
client
.
Dial
(
server
.
Addr
()
.
String
())
if
err
!=
nil
{
return
nil
,
err
}
cc
,
err
:=
client
.
Handshake
(
conn
,
AddrHandshakeOption
(
server
.
Addr
()
.
String
()))
if
err
!=
nil
{
conn
.
Close
()
return
nil
,
err
}
return
cc
,
nil
}
// httpRoundtrip does a HTTP request-response roundtrip, and checks the data received.
func
httpRoundtrip
(
conn
net
.
Conn
,
targetURL
string
,
data
[]
byte
)
(
err
error
)
{
req
,
err
:=
http
.
NewRequest
(
http
.
MethodGet
,
targetURL
,
bytes
.
NewReader
(
data
),
)
if
err
!=
nil
{
return
}
if
err
=
req
.
Write
(
conn
);
err
!=
nil
{
return
}
resp
,
err
:=
http
.
ReadResponse
(
bufio
.
NewReader
(
conn
),
req
)
if
err
!=
nil
{
return
}
defer
resp
.
Body
.
Close
()
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
errors
.
New
(
resp
.
Status
)
}
recv
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
}
if
!
bytes
.
Equal
(
data
,
recv
)
{
return
fmt
.
Errorf
(
"data not equal"
)
}
return
}
func
udpRoundtrip
(
client
*
Client
,
server
*
Server
,
host
string
,
data
[]
byte
)
(
err
error
)
{
conn
,
err
:=
proxyConn
(
client
,
server
)
if
err
!=
nil
{
return
}
defer
conn
.
Close
()
conn
,
err
=
client
.
Connect
(
conn
,
host
)
if
err
!=
nil
{
return
}
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
3
*
time
.
Second
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
if
_
,
err
=
conn
.
Write
(
data
);
err
!=
nil
{
return
}
recv
:=
make
([]
byte
,
len
(
data
))
if
_
,
err
=
conn
.
Read
(
recv
);
err
!=
nil
{
return
}
if
!
bytes
.
Equal
(
data
,
recv
)
{
return
fmt
.
Errorf
(
"data not equal"
)
}
return
}
func
proxyRoundtrip
(
client
*
Client
,
server
*
Server
,
targetURL
string
,
data
[]
byte
)
(
err
error
)
{
conn
,
err
:=
proxyConn
(
client
,
server
)
if
err
!=
nil
{
return
err
}
defer
conn
.
Close
()
u
,
err
:=
url
.
Parse
(
targetURL
)
if
err
!=
nil
{
return
}
conn
,
err
=
client
.
Connect
(
conn
,
u
.
Host
)
if
err
!=
nil
{
return
}
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
500
*
time
.
Millisecond
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
return
httpRoundtrip
(
conn
,
targetURL
,
data
)
}
type
udpRequest
struct
{
Body
io
.
Reader
RemoteAddr
string
...
...
@@ -60,6 +168,7 @@ type udpTestServer struct {
wg
sync
.
WaitGroup
mu
sync
.
Mutex
// guards closed and conns
closed
bool
exitChan
chan
struct
{}
}
func
newUDPTestServer
(
handler
udpHandlerFunc
)
*
udpTestServer
{
...
...
@@ -68,9 +177,13 @@ func newUDPTestServer(handler udpHandlerFunc) *udpTestServer {
if
err
!=
nil
{
panic
(
fmt
.
Sprintf
(
"udptest: failed to listen on a port: %v"
,
err
))
}
ln
.
SetReadBuffer
(
1024
*
1024
)
ln
.
SetWriteBuffer
(
1024
*
1024
)
return
&
udpTestServer
{
ln
:
ln
,
handler
:
handler
,
exitChan
:
make
(
chan
struct
{}),
}
}
...
...
@@ -83,7 +196,7 @@ func (s *udpTestServer) serve() {
data
:=
make
([]
byte
,
1024
)
n
,
raddr
,
err
:=
s
.
ln
.
ReadFrom
(
data
)
if
err
!=
nil
{
return
break
}
if
s
.
handler
!=
nil
{
s
.
wg
.
Add
(
1
)
...
...
@@ -101,6 +214,9 @@ func (s *udpTestServer) serve() {
}()
}
}
// signal the listener has been exited.
close
(
s
.
exitChan
)
}
func
(
s
*
udpTestServer
)
Addr
()
string
{
...
...
@@ -119,6 +235,8 @@ func (s *udpTestServer) Close() error {
s
.
closed
=
true
s
.
mu
.
Unlock
()
<-
s
.
exitChan
s
.
wg
.
Wait
()
return
err
...
...
forward.go
View file @
445889c4
...
...
@@ -662,10 +662,6 @@ func TCPRemoteForwardListener(addr string, chain *Chain) (Listener, error) {
go
ln
.
listenLoop
()
// if err = <-ln.errChan; err != nil {
// ln.Close()
// }
return
ln
,
err
}
...
...
@@ -680,17 +676,10 @@ func (l *tcpRemoteForwardListener) isChainValid() bool {
func
(
l
*
tcpRemoteForwardListener
)
listenLoop
()
{
var
tempDelay
time
.
Duration
// var once sync.Once
for
{
conn
,
err
:=
l
.
accept
()
// once.Do(func() {
// l.errChan <- err
// log.Log("once.Do error:", err)
// close(l.errChan)
// })
select
{
case
<-
l
.
closed
:
if
conn
!=
nil
{
...
...
forward_test.go
View file @
445889c4
package
gost
import
(
"bytes"
"crypto/rand"
"fmt"
"net/http/httptest"
"net/url"
"testing"
"time"
)
func
tcpDirectForwardRoundtrip
(
targetURL
string
,
data
[]
byte
)
error
{
...
...
@@ -122,37 +119,6 @@ func BenchmarkTCPDirectForwardParallel(b *testing.B) {
})
}
func
udpRoundtrip
(
client
*
Client
,
server
*
Server
,
host
string
,
data
[]
byte
)
(
err
error
)
{
conn
,
err
:=
proxyConn
(
client
,
server
)
if
err
!=
nil
{
return
}
defer
conn
.
Close
()
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
1
*
time
.
Second
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
conn
,
err
=
client
.
Connect
(
conn
,
host
)
if
err
!=
nil
{
return
}
if
_
,
err
=
conn
.
Write
(
data
);
err
!=
nil
{
return
}
recv
:=
make
([]
byte
,
len
(
data
))
if
_
,
err
=
conn
.
Read
(
recv
);
err
!=
nil
{
return
}
if
!
bytes
.
Equal
(
data
,
recv
)
{
return
fmt
.
Errorf
(
"data not equal"
)
}
return
}
func
udpDirectForwardRoundtrip
(
host
string
,
data
[]
byte
)
error
{
ln
,
err
:=
UDPDirectForwardListener
(
"localhost:0"
,
0
)
if
err
!=
nil
{
...
...
gost.go
View file @
445889c4
...
...
@@ -7,8 +7,10 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"io"
"math/big"
"net"
"sync"
"time"
...
...
@@ -137,3 +139,48 @@ func (rw *readWriter) Read(p []byte) (n int, err error) {
func
(
rw
*
readWriter
)
Write
(
p
[]
byte
)
(
n
int
,
err
error
)
{
return
rw
.
w
.
Write
(
p
)
}
var
(
nopClientConn
=
&
nopConn
{}
)
// a nop connection implements net.Conn,
// it does nothing.
type
nopConn
struct
{}
func
(
c
*
nopConn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
0
,
&
net
.
OpError
{
Op
:
"read"
,
Net
:
"nop"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"read not supported"
)}
}
func
(
c
*
nopConn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
0
,
&
net
.
OpError
{
Op
:
"write"
,
Net
:
"nop"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"write not supported"
)}
}
func
(
c
*
nopConn
)
Close
()
error
{
return
nil
}
func
(
c
*
nopConn
)
LocalAddr
()
net
.
Addr
{
return
nil
}
func
(
c
*
nopConn
)
RemoteAddr
()
net
.
Addr
{
return
nil
}
func
(
c
*
nopConn
)
SetDeadline
(
t
time
.
Time
)
error
{
return
&
net
.
OpError
{
Op
:
"set"
,
Net
:
"nop"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"deadline not supported"
)}
}
func
(
c
*
nopConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
&
net
.
OpError
{
Op
:
"set"
,
Net
:
"nop"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"deadline not supported"
)}
}
func
(
c
*
nopConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
&
net
.
OpError
{
Op
:
"set"
,
Net
:
"nop"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"deadline not supported"
)}
}
// Accepter represents a network endpoint that can accept connection from peer.
type
Accepter
interface
{
Accept
()
(
net
.
Conn
,
error
)
}
handler_test.go
View file @
445889c4
...
...
@@ -18,7 +18,6 @@ func autoHTTPProxyRoundtrip(targetURL string, data []byte, clientInfo *url.Useri
Connector
:
HTTPConnector
(
clientInfo
),
Transporter
:
TCPTransporter
(),
}
server
:=
&
Server
{
Listener
:
ln
,
Handler
:
AutoHandler
(
...
...
@@ -111,7 +110,7 @@ func TestAutoSOCKS5Proxy(t *testing.T) {
}
}
func
autoSOCKS4ProxyRoundtrip
(
targetURL
string
,
data
[]
byte
)
error
{
func
autoSOCKS4ProxyRoundtrip
(
targetURL
string
,
data
[]
byte
,
options
...
HandlerOption
)
error
{
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
return
err
...
...
@@ -124,7 +123,7 @@ func autoSOCKS4ProxyRoundtrip(targetURL string, data []byte) error {
server
:=
&
Server
{
Listener
:
ln
,
Handler
:
AutoHandler
(),
Handler
:
AutoHandler
(
options
...
),
}
go
server
.
Run
()
defer
server
.
Close
()
...
...
@@ -139,14 +138,17 @@ func TestAutoSOCKS4Proxy(t *testing.T) {
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
err
:=
autoSOCKS4ProxyRoundtrip
(
httpSrv
.
URL
,
sendData
)
// t.Logf("#%d %v", i, err)
if
err
!=
nil
{
if
err
:=
autoSOCKS4ProxyRoundtrip
(
httpSrv
.
URL
,
sendData
);
err
!=
nil
{
t
.
Errorf
(
"got error: %v"
,
err
)
}
if
err
:=
autoSOCKS4ProxyRoundtrip
(
httpSrv
.
URL
,
sendData
,
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
)));
err
==
nil
{
t
.
Errorf
(
"authentication required auto handler for SOCKS4 should failed"
)
}
}
func
autoSocks4aProxyRoundtrip
(
targetURL
string
,
data
[]
byte
)
error
{
func
autoSocks4aProxyRoundtrip
(
targetURL
string
,
data
[]
byte
,
options
...
HandlerOption
)
error
{
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
return
err
...
...
@@ -159,7 +161,7 @@ func autoSocks4aProxyRoundtrip(targetURL string, data []byte) error {
server
:=
&
Server
{
Listener
:
ln
,
Handler
:
AutoHandler
(),
Handler
:
AutoHandler
(
options
...
),
}
go
server
.
Run
()
...
...
@@ -175,11 +177,14 @@ func TestAutoSOCKS4AProxy(t *testing.T) {
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
err
:=
autoSocks4aProxyRoundtrip
(
httpSrv
.
URL
,
sendData
)
// t.Logf("#%d %v", i, err)
if
err
!=
nil
{
if
err
:=
autoSocks4aProxyRoundtrip
(
httpSrv
.
URL
,
sendData
);
err
!=
nil
{
t
.
Errorf
(
"got error: %v"
,
err
)
}
if
err
:=
autoSocks4aProxyRoundtrip
(
httpSrv
.
URL
,
sendData
,
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
)));
err
==
nil
{
t
.
Errorf
(
"authentication required auto handler for SOCKS4A should failed"
)
}
}
func
autoSSProxyRoundtrip
(
targetURL
string
,
data
[]
byte
,
clientInfo
*
url
.
Userinfo
,
serverInfo
*
url
.
Userinfo
)
error
{
...
...
hosts_test.go
View file @
445889c4
...
...
@@ -28,7 +28,8 @@ var hostsLookupTests = []struct {
func
TestHostsLookup
(
t
*
testing
.
T
)
{
for
i
,
tc
:=
range
hostsLookupTests
{
hosts
:=
NewHosts
(
tc
.
hosts
...
)
hosts
:=
NewHosts
()
hosts
.
AddHost
(
tc
.
hosts
...
)
ip
:=
hosts
.
Lookup
(
tc
.
host
)
if
!
ip
.
Equal
(
tc
.
ip
)
{
t
.
Errorf
(
"#%d test failed: lookup should be %s, got %s"
,
i
,
tc
.
ip
,
ip
)
...
...
@@ -61,6 +62,11 @@ var HostsReloadTests = []struct {
host
:
"example.com"
,
ip
:
nil
,
},
{
r
:
bytes
.
NewBufferString
(
"#reload 10s
\n
invalid.ip.addr example.com"
),
period
:
0
,
ip
:
nil
,
},
{
r
:
bytes
.
NewBufferString
(
"reload 10s
\n
192.168.1.1"
),
period
:
10
*
time
.
Second
,
...
...
@@ -112,6 +118,9 @@ func TestHostsReload(t *testing.T) {
}
if
tc
.
stopped
{
hosts
.
Stop
()
if
hosts
.
Period
()
>=
0
{
t
.
Errorf
(
"period of the stopped reloader should be minus value"
)
}
}
if
hosts
.
Stopped
()
!=
tc
.
stopped
{
t
.
Errorf
(
"#%d test failed: stopped value should be %v, got %v"
,
...
...
http2.go
View file @
445889c4
...
...
@@ -569,12 +569,13 @@ func HTTP2Listener(addr string, config *tls.Config) (Listener, error) {
}
l
.
server
=
server
ln
,
err
:=
tls
.
Listen
(
"tcp"
,
addr
,
config
)
ln
,
err
:=
net
.
Listen
(
"tcp"
,
addr
)
if
err
!=
nil
{
return
nil
,
err
}
l
.
addr
=
ln
.
Addr
()
ln
=
tls
.
NewListener
(
tcpKeepAliveListener
{
ln
.
(
*
net
.
TCPListener
)},
config
)
go
func
()
{
err
:=
server
.
Serve
(
ln
)
if
err
!=
nil
{
...
...
@@ -875,42 +876,11 @@ func (c *http2ServerConn) SetWriteDeadline(t time.Time) error {
// a dummy HTTP2 client conn used by HTTP2 client connector
type
http2ClientConn
struct
{
nopConn
addr
string
client
*
http
.
Client
}
func
(
c
*
http2ClientConn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
0
,
&
net
.
OpError
{
Op
:
"read"
,
Net
:
"http2"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"read not supported"
)}
}
func
(
c
*
http2ClientConn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
return
0
,
&
net
.
OpError
{
Op
:
"write"
,
Net
:
"http2"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"write not supported"
)}
}
func
(
c
*
http2ClientConn
)
Close
()
error
{
return
nil
}
func
(
c
*
http2ClientConn
)
LocalAddr
()
net
.
Addr
{
return
nil
}
func
(
c
*
http2ClientConn
)
RemoteAddr
()
net
.
Addr
{
return
nil
}
func
(
c
*
http2ClientConn
)
SetDeadline
(
t
time
.
Time
)
error
{
return
&
net
.
OpError
{
Op
:
"set"
,
Net
:
"http2"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"deadline not supported"
)}
}
func
(
c
*
http2ClientConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
&
net
.
OpError
{
Op
:
"set"
,
Net
:
"http2"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"deadline not supported"
)}
}
func
(
c
*
http2ClientConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
&
net
.
OpError
{
Op
:
"set"
,
Net
:
"http2"
,
Source
:
nil
,
Addr
:
nil
,
Err
:
errors
.
New
(
"deadline not supported"
)}
}
type
flushWriter
struct
{
w
io
.
Writer
}
...
...
http_test.go
View file @
445889c4
package
gost
import
(
"bufio"
"bytes"
"crypto/rand"
"errors"
"fmt"
"io/ioutil"
"net"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"
)
// proxyConn obtains a connection to the proxy server.
func
proxyConn
(
client
*
Client
,
server
*
Server
)
(
net
.
Conn
,
error
)
{
conn
,
err
:=
client
.
Dial
(
server
.
Addr
()
.
String
())
if
err
!=
nil
{
return
nil
,
err
}
cc
,
err
:=
client
.
Handshake
(
conn
,
AddrHandshakeOption
(
server
.
Addr
()
.
String
()))
if
err
!=
nil
{
conn
.
Close
()
return
nil
,
err
}
return
cc
,
nil
}
// httpRoundtrip does a HTTP request-response roundtrip, and checks the data received.
func
httpRoundtrip
(
conn
net
.
Conn
,
targetURL
string
,
data
[]
byte
)
(
err
error
)
{
req
,
err
:=
http
.
NewRequest
(
http
.
MethodGet
,
targetURL
,
bytes
.
NewReader
(
data
),
)
if
err
!=
nil
{
return
}
if
err
=
req
.
Write
(
conn
);
err
!=
nil
{
return
}
resp
,
err
:=
http
.
ReadResponse
(
bufio
.
NewReader
(
conn
),
req
)
if
err
!=
nil
{
return
}
defer
resp
.
Body
.
Close
()
if
resp
.
StatusCode
!=
http
.
StatusOK
{
return
errors
.
New
(
resp
.
Status
)
}
recv
,
err
:=
ioutil
.
ReadAll
(
resp
.
Body
)
if
err
!=
nil
{
return
}
if
!
bytes
.
Equal
(
data
,
recv
)
{
return
fmt
.
Errorf
(
"data not equal"
)
}
return
}
func
proxyRoundtrip
(
client
*
Client
,
server
*
Server
,
targetURL
string
,
data
[]
byte
)
(
err
error
)
{
conn
,
err
:=
proxyConn
(
client
,
server
)
if
err
!=
nil
{
return
err
}
defer
conn
.
Close
()
u
,
err
:=
url
.
Parse
(
targetURL
)
if
err
!=
nil
{
return
}
conn
,
err
=
client
.
Connect
(
conn
,
u
.
Host
)
if
err
!=
nil
{
return
}
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
500
*
time
.
Millisecond
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
return
httpRoundtrip
(
conn
,
targetURL
,
data
)
}
var
httpProxyTests
=
[]
struct
{
cliUser
*
url
.
Userinfo
srvUsers
[]
*
url
.
Userinfo
...
...
kcp.go
View file @
445889c4
...
...
@@ -123,6 +123,11 @@ func (tr *kcpTransporter) Dial(addr string, options ...DialOption) (conn net.Con
defer
tr
.
sessionMutex
.
Unlock
()
session
,
ok
:=
tr
.
sessions
[
addr
]
if
session
!=
nil
&&
session
.
session
!=
nil
&&
session
.
session
.
IsClosed
()
{
session
.
Close
()
delete
(
tr
.
sessions
,
addr
)
// session is dead
ok
=
false
}
if
!
ok
{
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
...
...
mux.go
View file @
445889c4
...
...
@@ -45,10 +45,16 @@ func (session *muxSession) Accept() (net.Conn, error) {
}
func
(
session
*
muxSession
)
Close
()
error
{
if
session
.
session
==
nil
{
return
nil
}
return
session
.
session
.
Close
()
}
func
(
session
*
muxSession
)
IsClosed
()
bool
{
if
session
.
session
==
nil
{
return
true
}
return
session
.
session
.
IsClosed
()
}
...
...
obfs.go
View file @
445889c4
...
...
@@ -331,7 +331,7 @@ func Obfs4Listener(addr string) (Listener, error) {
}
l
:=
&
obfs4Listener
{
addr
:
addr
,
Listener
:
ln
,
Listener
:
tcpKeepAliveListener
{
ln
.
(
*
net
.
TCPListener
)}
,
}
return
l
,
nil
}
...
...
quic_test.go
View file @
445889c4
...
...
@@ -2,6 +2,7 @@ package gost
import
(
"crypto/rand"
"crypto/sha256"
"fmt"
"net/http/httptest"
"net/url"
...
...
@@ -405,3 +406,57 @@ func TestQUICForwardTunnel(t *testing.T) {
t
.
Error
(
err
)
}
}
func
httpOverCipherQUICRoundtrip
(
targetURL
string
,
data
[]
byte
,
clientInfo
*
url
.
Userinfo
,
serverInfo
[]
*
url
.
Userinfo
)
error
{
sum
:=
sha256
.
Sum256
([]
byte
(
"12345678"
))
cfg
:=
&
QUICConfig
{
Key
:
sum
[
:
],
}
ln
,
err
:=
QUICListener
(
"localhost:0"
,
cfg
)
if
err
!=
nil
{
return
err
}
client
:=
&
Client
{
Connector
:
HTTPConnector
(
clientInfo
),
Transporter
:
QUICTransporter
(
cfg
),
}
server
:=
&
Server
{
Listener
:
ln
,
Handler
:
HTTPHandler
(
UsersHandlerOption
(
serverInfo
...
),
),
}
go
server
.
Run
()
defer
server
.
Close
()
return
proxyRoundtrip
(
client
,
server
,
targetURL
,
data
)
}
func
TestHTTPOverCipherQUIC
(
t
*
testing
.
T
)
{
httpSrv
:=
httptest
.
NewServer
(
httpTestHandler
)
defer
httpSrv
.
Close
()
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
for
i
,
tc
:=
range
httpProxyTests
{
err
:=
httpOverCipherQUICRoundtrip
(
httpSrv
.
URL
,
sendData
,
tc
.
cliUser
,
tc
.
srvUsers
)
if
err
==
nil
{
if
tc
.
errStr
!=
""
{
t
.
Errorf
(
"#%d should failed with error %s"
,
i
,
tc
.
errStr
)
}
}
else
{
if
tc
.
errStr
==
""
{
t
.
Errorf
(
"#%d got error %v"
,
i
,
err
)
}
if
err
.
Error
()
!=
tc
.
errStr
{
t
.
Errorf
(
"#%d got error %v, want %v"
,
i
,
err
,
tc
.
errStr
)
}
}
}
}
resolver.go
View file @
445889c4
...
...
@@ -23,8 +23,6 @@ import (
var
(
// DefaultResolverTimeout is the default timeout for name resolution.
DefaultResolverTimeout
=
5
*
time
.
Second
// DefaultResolverTTL is the default cache TTL for name resolution.
DefaultResolverTTL
=
1
*
time
.
Hour
)
// Resolver is a name resolver for domain name.
...
...
@@ -53,13 +51,18 @@ type NameServer struct {
// Init initializes the name server.
func
(
ns
*
NameServer
)
Init
()
error
{
timeout
:=
ns
.
Timeout
if
timeout
<=
0
{
timeout
=
DefaultResolverTimeout
}
switch
strings
.
ToLower
(
ns
.
Protocol
)
{
case
"tcp"
:
ns
.
exchanger
=
&
dnsExchanger
{
endpoint
:
ns
.
Addr
,
client
:
&
dns
.
Client
{
Net
:
"tcp"
,
Timeout
:
ns
.
T
imeout
,
Timeout
:
t
imeout
,
},
}
case
"tls"
:
...
...
@@ -74,7 +77,7 @@ func (ns *NameServer) Init() error {
endpoint
:
ns
.
Addr
,
client
:
&
dns
.
Client
{
Net
:
"tcp-tls"
,
Timeout
:
ns
.
T
imeout
,
Timeout
:
t
imeout
,
TLSConfig
:
cfg
,
},
}
...
...
@@ -95,7 +98,7 @@ func (ns *NameServer) Init() error {
endpoint
:
u
,
client
:
&
http
.
Client
{
Transport
:
transport
,
Timeout
:
ns
.
T
imeout
,
Timeout
:
t
imeout
,
},
}
case
"udp"
:
...
...
@@ -105,7 +108,7 @@ func (ns *NameServer) Init() error {
endpoint
:
ns
.
Addr
,
client
:
&
dns
.
Client
{
Net
:
"udp"
,
Timeout
:
ns
.
T
imeout
,
Timeout
:
t
imeout
,
},
}
}
...
...
@@ -125,15 +128,9 @@ func (ns NameServer) String() string {
return
fmt
.
Sprintf
(
"%s/%s"
,
addr
,
prot
)
}
type
resolverCacheItem
struct
{
IPs
[]
net
.
IP
ts
int64
}
type
resolver
struct
{
Servers
[]
NameServer
mCache
*
sync
.
Map
Timeout
time
.
Duration
TTL
time
.
Duration
period
time
.
Duration
domain
string
...
...
@@ -142,22 +139,14 @@ type resolver struct {
}
// NewResolver create a new Resolver with the given name servers and resolution timeout.
func
NewResolver
(
timeout
,
ttl
time
.
Duration
,
servers
...
NameServer
)
ReloadResolver
{
r
:=
newResolver
(
timeout
,
ttl
,
servers
...
)
if
r
.
Timeout
<=
0
{
r
.
Timeout
=
DefaultResolverTimeout
}
if
r
.
TTL
==
0
{
r
.
TTL
=
DefaultResolverTTL
}
func
NewResolver
(
ttl
time
.
Duration
,
servers
...
NameServer
)
ReloadResolver
{
r
:=
newResolver
(
ttl
,
servers
...
)
return
r
}
func
newResolver
(
t
imeout
,
t
tl
time
.
Duration
,
servers
...
NameServer
)
*
resolver
{
func
newResolver
(
ttl
time
.
Duration
,
servers
...
NameServer
)
*
resolver
{
return
&
resolver
{
Servers
:
servers
,
Timeout
:
timeout
,
TTL
:
ttl
,
mCache
:
&
sync
.
Map
{},
stopped
:
make
(
chan
struct
{}),
...
...
@@ -204,25 +193,25 @@ func (r *resolver) Resolve(host string) (ips []net.IP, err error) {
}
for
_
,
ns
:=
range
servers
{
ips
,
err
=
r
.
resolve
(
ns
.
exchanger
,
host
)
ips
,
ttl
,
err
=
r
.
resolve
(
ns
.
exchanger
,
host
)
if
err
!=
nil
{
log
.
Logf
(
"[resolver] %s via %s : %s"
,
host
,
ns
,
err
)
continue
}
if
Debug
{
log
.
Logf
(
"[resolver] %s via %s %v
"
,
host
,
ns
,
ips
)
log
.
Logf
(
"[resolver] %s via %s %v
(ttl: %v)"
,
host
,
ns
,
ips
,
ttl
)
}
if
len
(
ips
)
>
0
{
break
}
}
r
.
storeCache
(
host
,
ips
)
r
.
storeCache
(
host
,
ips
,
ttl
)
return
}
func
(
*
resolver
)
resolve
(
ex
Exchanger
,
host
string
)
(
ips
[]
net
.
IP
,
err
error
)
{
func
(
*
resolver
)
resolve
(
ex
Exchanger
,
host
string
)
(
ips
[]
net
.
IP
,
ttl
time
.
Duration
,
err
error
)
{
if
ex
==
nil
{
return
}
...
...
@@ -236,11 +225,18 @@ func (*resolver) resolve(ex Exchanger, host string) (ips []net.IP, err error) {
for
_
,
ans
:=
range
mr
.
Answer
{
if
ar
,
_
:=
ans
.
(
*
dns
.
A
);
ar
!=
nil
{
ips
=
append
(
ips
,
ar
.
A
)
ttl
=
time
.
Duration
(
ar
.
Header
()
.
Ttl
)
*
time
.
Second
}
}
return
}
type
resolverCacheItem
struct
{
IPs
[]
net
.
IP
ts
int64
ttl
time
.
Duration
}
func
(
r
*
resolver
)
loadCache
(
name
string
,
ttl
time
.
Duration
)
[]
net
.
IP
{
if
ttl
<
0
{
return
nil
...
...
@@ -248,6 +244,10 @@ func (r *resolver) loadCache(name string, ttl time.Duration) []net.IP {
if
v
,
ok
:=
r
.
mCache
.
Load
(
name
);
ok
{
item
,
_
:=
v
.
(
*
resolverCacheItem
)
if
ttl
==
0
{
ttl
=
item
.
ttl
}
if
item
==
nil
||
time
.
Since
(
time
.
Unix
(
item
.
ts
,
0
))
>
ttl
{
return
nil
}
...
...
@@ -257,13 +257,14 @@ func (r *resolver) loadCache(name string, ttl time.Duration) []net.IP {
return
nil
}
func
(
r
*
resolver
)
storeCache
(
name
string
,
ips
[]
net
.
IP
)
{
func
(
r
*
resolver
)
storeCache
(
name
string
,
ips
[]
net
.
IP
,
ttl
time
.
Duration
)
{
if
name
==
""
||
len
(
ips
)
==
0
{
return
}
r
.
mCache
.
Store
(
name
,
&
resolverCacheItem
{
IPs
:
ips
,
ts
:
time
.
Now
()
.
Unix
(),
ttl
:
ttl
,
})
}
...
...
@@ -343,10 +344,10 @@ func (r *resolver) Reload(rd io.Reader) error {
ns
.
Hostname
=
ss
[
2
]
}
ns
.
Timeout
=
timeout
if
timeout
<=
0
{
ns
.
Timeout
=
DefaultResolverTimeout
if
strings
.
HasPrefix
(
ns
.
Addr
,
"https"
)
{
ns
.
Protocol
=
"https"
}
ns
.
Timeout
=
timeout
if
err
:=
ns
.
Init
();
err
==
nil
{
nss
=
append
(
nss
,
ns
)
...
...
@@ -359,7 +360,6 @@ func (r *resolver) Reload(rd io.Reader) error {
}
r
.
mux
.
Lock
()
r
.
Timeout
=
timeout
r
.
TTL
=
ttl
r
.
domain
=
domain
r
.
period
=
period
...
...
@@ -408,9 +408,9 @@ func (r *resolver) String() string {
defer
r
.
mux
.
RUnlock
()
b
:=
&
bytes
.
Buffer
{}
fmt
.
Fprintf
(
b
,
"Timeout %v
\n
"
,
r
.
Timeout
)
fmt
.
Fprintf
(
b
,
"TTL %v
\n
"
,
r
.
TTL
)
fmt
.
Fprintf
(
b
,
"Reload %v
\n
"
,
r
.
period
)
fmt
.
Fprintf
(
b
,
"Domain %v
\n
"
,
r
.
domain
)
for
i
:=
range
r
.
Servers
{
fmt
.
Fprintln
(
b
,
r
.
Servers
[
i
])
}
...
...
resolver_test.go
View file @
445889c4
...
...
@@ -46,7 +46,7 @@ func TestDNSResolver(t *testing.T) {
t
.
Error
(
err
)
}
t
.
Log
(
ns
)
r
:=
NewResolver
(
0
,
0
,
ns
)
r
:=
NewResolver
(
0
,
ns
)
err
:=
dnsResolverRoundtrip
(
t
,
r
,
tc
.
host
)
if
err
!=
nil
{
if
tc
.
pass
{
...
...
@@ -104,12 +104,11 @@ var resolverReloadTests = []struct {
r
:
bytes
.
NewBufferString
(
"1.1.1.1"
),
ns
:
&
NameServer
{
Addr
:
"1.1.1.1"
,
Timeout
:
DefaultResolverTimeout
,
},
stopped
:
true
,
},
{
r
:
bytes
.
NewBufferString
(
"timeout 10s
\n
search
\n
nameserver
\n
nameserver 1.1.1.1 udp"
),
r
:
bytes
.
NewBufferString
(
"
\n
# comment
\n
timeout 10s
\n
search
\n
nameserver
\n
nameserver 1.1.1.1 udp"
),
ns
:
&
NameServer
{
Protocol
:
"udp"
,
Addr
:
"1.1.1.1"
,
...
...
@@ -123,7 +122,6 @@ var resolverReloadTests = []struct {
ns
:
&
NameServer
{
Addr
:
"1.1.1.1"
,
Protocol
:
"tcp"
,
Timeout
:
DefaultResolverTimeout
,
},
stopped
:
true
,
},
...
...
@@ -133,7 +131,6 @@ var resolverReloadTests = []struct {
Addr
:
"1.1.1.1:853"
,
Protocol
:
"tls"
,
Hostname
:
"cloudflare-dns.com"
,
Timeout
:
DefaultResolverTimeout
,
},
stopped
:
true
,
},
...
...
@@ -142,7 +139,6 @@ var resolverReloadTests = []struct {
ns
:
&
NameServer
{
Addr
:
"1.1.1.1:853"
,
Protocol
:
"tls"
,
Timeout
:
DefaultResolverTimeout
,
},
stopped
:
true
,
},
...
...
@@ -151,11 +147,10 @@ var resolverReloadTests = []struct {
stopped
:
true
,
},
{
r
:
bytes
.
NewBufferString
(
"https://1.0.0.1/dns-query
https
"
),
r
:
bytes
.
NewBufferString
(
"https://1.0.0.1/dns-query"
),
ns
:
&
NameServer
{
Addr
:
"https://1.0.0.1/dns-query"
,
Protocol
:
"https"
,
Timeout
:
DefaultResolverTimeout
,
},
stopped
:
true
,
},
...
...
@@ -164,15 +159,11 @@ var resolverReloadTests = []struct {
func
TestResolverReload
(
t
*
testing
.
T
)
{
for
i
,
tc
:=
range
resolverReloadTests
{
t
.
Run
(
fmt
.
Sprintf
(
"#%d"
,
i
),
func
(
t
*
testing
.
T
)
{
r
:=
newResolver
(
0
,
0
)
r
:=
newResolver
(
0
)
if
err
:=
r
.
Reload
(
tc
.
r
);
err
!=
nil
{
t
.
Error
(
err
)
}
t
.
Log
(
r
.
String
())
if
r
.
Timeout
!=
tc
.
timeout
{
t
.
Errorf
(
"timeout value should be %v, got %v"
,
tc
.
timeout
,
r
.
Timeout
)
}
if
r
.
TTL
!=
tc
.
ttl
{
t
.
Errorf
(
"ttl value should be %v, got %v"
,
tc
.
ttl
,
r
.
TTL
)
...
...
@@ -198,6 +189,9 @@ func TestResolverReload(t *testing.T) {
if
tc
.
stopped
{
r
.
Stop
()
if
r
.
Period
()
>=
0
{
t
.
Errorf
(
"period of the stopped reloader should be minus value"
)
}
}
if
r
.
Stopped
()
!=
tc
.
stopped
{
t
.
Errorf
(
"stopped value should be %v, got %v"
,
...
...
socks.go
View file @
445889c4
...
...
@@ -340,6 +340,164 @@ func (c *socks5BindConnector) Connect(conn net.Conn, addr string, options ...Con
return
&
socks5BindConn
{
Conn
:
conn
,
laddr
:
baddr
},
nil
}
type
socks5MuxBindConnector
struct
{}
// Socks5MuxBindConnector creates a Connector for SOCKS5 multiplex bind client.
func
Socks5MuxBindConnector
()
Connector
{
return
&
socks5MuxBindConnector
{}
}
// NOTE: the conn must be *muxBindClientConn.
func
(
c
*
socks5MuxBindConnector
)
Connect
(
conn
net
.
Conn
,
addr
string
,
options
...
ConnectOption
)
(
net
.
Conn
,
error
)
{
accepter
,
ok
:=
conn
.
(
Accepter
)
if
!
ok
{
return
nil
,
errors
.
New
(
"wrong connection type"
)
}
return
accepter
.
Accept
()
}
type
socks5MuxBindTransporter
struct
{
bindAddr
string
sessions
map
[
string
]
*
muxSession
// server addr to session mapping
sessionMutex
sync
.
Mutex
}
// SOCKS5MuxBindTransporter creates a Transporter for SOCKS5 multiplex bind client.
func
SOCKS5MuxBindTransporter
(
bindAddr
string
)
Transporter
{
return
&
socks5MuxBindTransporter
{
bindAddr
:
bindAddr
,
sessions
:
make
(
map
[
string
]
*
muxSession
),
}
}
func
(
tr
*
socks5MuxBindTransporter
)
Dial
(
addr
string
,
options
...
DialOption
)
(
conn
net
.
Conn
,
err
error
)
{
opts
:=
&
DialOptions
{}
for
_
,
option
:=
range
options
{
option
(
opts
)
}
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
DialTimeout
}
tr
.
sessionMutex
.
Lock
()
defer
tr
.
sessionMutex
.
Unlock
()
session
,
ok
:=
tr
.
sessions
[
addr
]
if
session
!=
nil
&&
session
.
IsClosed
()
{
delete
(
tr
.
sessions
,
addr
)
ok
=
false
}
if
!
ok
{
if
opts
.
Chain
==
nil
{
conn
,
err
=
net
.
DialTimeout
(
"tcp"
,
addr
,
timeout
)
}
else
{
conn
,
err
=
opts
.
Chain
.
Dial
(
addr
)
}
if
err
!=
nil
{
return
}
session
=
&
muxSession
{
conn
:
conn
}
tr
.
sessions
[
addr
]
=
session
}
return
session
.
conn
,
nil
}
func
(
tr
*
socks5MuxBindTransporter
)
Handshake
(
conn
net
.
Conn
,
options
...
HandshakeOption
)
(
net
.
Conn
,
error
)
{
opts
:=
&
HandshakeOptions
{}
for
_
,
option
:=
range
options
{
option
(
opts
)
}
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
HandshakeTimeout
}
tr
.
sessionMutex
.
Lock
()
defer
tr
.
sessionMutex
.
Unlock
()
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
timeout
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
session
,
ok
:=
tr
.
sessions
[
opts
.
Addr
]
if
!
ok
||
session
.
session
==
nil
{
s
,
err
:=
tr
.
initSession
(
conn
,
tr
.
bindAddr
,
opts
)
if
err
!=
nil
{
conn
.
Close
()
delete
(
tr
.
sessions
,
opts
.
Addr
)
return
nil
,
err
}
session
=
s
tr
.
sessions
[
opts
.
Addr
]
=
session
}
return
&
muxBindClientConn
{
session
:
session
},
nil
}
func
(
tr
*
socks5MuxBindTransporter
)
initSession
(
conn
net
.
Conn
,
addr
string
,
opts
*
HandshakeOptions
)
(
*
muxSession
,
error
)
{
if
opts
==
nil
{
opts
=
&
HandshakeOptions
{}
}
cc
,
err
:=
socks5Handshake
(
conn
,
opts
.
User
)
if
err
!=
nil
{
return
nil
,
err
}
conn
=
cc
bindAddr
,
err
:=
net
.
ResolveTCPAddr
(
"tcp"
,
addr
)
if
err
!=
nil
{
return
nil
,
err
}
req
:=
gosocks5
.
NewRequest
(
CmdMuxBind
,
&
gosocks5
.
Addr
{
Type
:
gosocks5
.
AddrIPv4
,
Host
:
bindAddr
.
IP
.
String
(),
Port
:
uint16
(
bindAddr
.
Port
),
})
if
err
=
req
.
Write
(
conn
);
err
!=
nil
{
return
nil
,
err
}
if
Debug
{
log
.
Log
(
"[socks5] mbind
\n
"
,
req
)
}
reply
,
err
:=
gosocks5
.
ReadReply
(
conn
)
if
err
!=
nil
{
return
nil
,
err
}
if
Debug
{
log
.
Log
(
"[socks5] mbind
\n
"
,
reply
)
}
if
reply
.
Rep
!=
gosocks5
.
Succeeded
{
log
.
Logf
(
"[socks5] mbind on %s failure"
,
addr
)
return
nil
,
fmt
.
Errorf
(
"SOCKS5 mbind on %s failure"
,
addr
)
}
baddr
,
err
:=
net
.
ResolveTCPAddr
(
"tcp"
,
reply
.
Addr
.
String
())
if
err
!=
nil
{
return
nil
,
err
}
log
.
Logf
(
"[socks5] mbind on %s OK"
,
baddr
)
// Upgrade connection to multiplex stream.
session
,
err
:=
smux
.
Server
(
conn
,
smux
.
DefaultConfig
())
if
err
!=
nil
{
return
nil
,
err
}
return
&
muxSession
{
conn
:
conn
,
session
:
session
},
nil
}
func
(
tr
*
socks5MuxBindTransporter
)
Multiplex
()
bool
{
return
true
}
type
socks5UDPConnector
struct
{
User
*
url
.
Userinfo
}
...
...
@@ -387,12 +545,10 @@ func (c *socks5UDPConnector) Connect(conn net.Conn, addr string, options ...Conn
log
.
Log
(
"[socks5] udp
\n
"
,
req
)
}
conn
.
SetReadDeadline
(
time
.
Now
()
.
Add
(
ReadTimeout
))
reply
,
err
:=
gosocks5
.
ReadReply
(
conn
)
if
err
!=
nil
{
return
nil
,
err
}
conn
.
SetReadDeadline
(
time
.
Time
{})
if
Debug
{
log
.
Log
(
"[socks5] udp
\n
"
,
reply
)
...
...
@@ -412,11 +568,142 @@ func (c *socks5UDPConnector) Connect(conn net.Conn, addr string, options ...Conn
if
err
!=
nil
{
return
nil
,
err
}
log
.
Logf
(
"udp laddr:%s, raddr:%s"
,
uc
.
LocalAddr
(),
uc
.
RemoteAddr
())
//
log.Logf("udp laddr:%s, raddr:%s", uc.LocalAddr(), uc.RemoteAddr())
return
&
socks5UDPConn
{
UDPConn
:
uc
,
taddr
:
taddr
},
nil
}
type
socks5UDPTunConnector
struct
{
User
*
url
.
Userinfo
}
// SOCKS5UDPTunConnector creates a connector for SOCKS5 UDP-over-TCP relay.
// It accepts an optional auth info for SOCKS5 Username/Password Authentication.
func
SOCKS5UDPTunConnector
(
user
*
url
.
Userinfo
)
Connector
{
return
&
socks5UDPTunConnector
{
User
:
user
}
}
func
(
c
*
socks5UDPTunConnector
)
Connect
(
conn
net
.
Conn
,
addr
string
,
options
...
ConnectOption
)
(
net
.
Conn
,
error
)
{
opts
:=
&
ConnectOptions
{}
for
_
,
option
:=
range
options
{
option
(
opts
)
}
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
ConnectTimeout
}
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
timeout
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
cc
,
err
:=
socks5Handshake
(
conn
,
c
.
User
)
if
err
!=
nil
{
return
nil
,
err
}
conn
=
cc
taddr
,
err
:=
net
.
ResolveUDPAddr
(
"udp"
,
addr
)
if
err
!=
nil
{
return
nil
,
err
}
req
:=
gosocks5
.
NewRequest
(
CmdUDPTun
,
&
gosocks5
.
Addr
{
Type
:
gosocks5
.
AddrIPv4
,
})
if
err
:=
req
.
Write
(
conn
);
err
!=
nil
{
return
nil
,
err
}
if
Debug
{
log
.
Log
(
"[socks5] udp
\n
"
,
req
)
}
reply
,
err
:=
gosocks5
.
ReadReply
(
conn
)
if
err
!=
nil
{
return
nil
,
err
}
if
Debug
{
log
.
Log
(
"[socks5] udp
\n
"
,
reply
)
}
if
reply
.
Rep
!=
gosocks5
.
Succeeded
{
log
.
Logf
(
"[socks5] udp relay failure"
)
return
nil
,
fmt
.
Errorf
(
"SOCKS5 udp relay failure"
)
}
baddr
,
err
:=
net
.
ResolveUDPAddr
(
"udp"
,
reply
.
Addr
.
String
())
if
err
!=
nil
{
return
nil
,
err
}
log
.
Logf
(
"[socks5] udp-tun associate on %s OK"
,
baddr
)
return
&
udpTunnelConn
{
Conn
:
conn
,
raddr
:
taddr
.
String
()},
nil
}
func
(
c
*
socks5UDPTunConnector
)
tunnelClientUDP
(
pc
net
.
PacketConn
,
cc
net
.
Conn
)
(
err
error
)
{
errc
:=
make
(
chan
error
,
2
)
go
func
()
{
b
:=
mPool
.
Get
()
.
([]
byte
)
defer
mPool
.
Put
(
b
)
for
{
n
,
addr
,
err
:=
pc
.
ReadFrom
(
b
)
if
err
!=
nil
{
log
.
Logf
(
"[udp-tun] %s <- %s : %s"
,
cc
.
RemoteAddr
(),
addr
,
err
)
errc
<-
err
return
}
// pipe from peer to tunnel
dgram
:=
gosocks5
.
NewUDPDatagram
(
gosocks5
.
NewUDPHeader
(
uint16
(
n
),
0
,
toSocksAddr
(
addr
)),
b
[
:
n
])
if
err
:=
dgram
.
Write
(
cc
);
err
!=
nil
{
log
.
Logf
(
"[udp-tun] %s <- %s : %s"
,
cc
.
RemoteAddr
(),
dgram
.
Header
.
Addr
,
err
)
errc
<-
err
return
}
if
Debug
{
log
.
Logf
(
"[udp-tun] %s <<< %s length: %d"
,
cc
.
RemoteAddr
(),
dgram
.
Header
.
Addr
,
len
(
dgram
.
Data
))
}
}
}()
go
func
()
{
for
{
dgram
,
err
:=
gosocks5
.
ReadUDPDatagram
(
cc
)
if
err
!=
nil
{
log
.
Logf
(
"[udp-tun] %s -> 0 : %s"
,
cc
.
RemoteAddr
(),
err
)
errc
<-
err
return
}
// pipe from tunnel to peer
addr
,
err
:=
net
.
ResolveUDPAddr
(
"udp"
,
dgram
.
Header
.
Addr
.
String
())
if
err
!=
nil
{
continue
// drop silently
}
if
_
,
err
:=
pc
.
WriteTo
(
dgram
.
Data
,
addr
);
err
!=
nil
{
log
.
Logf
(
"[udp-tun] %s -> %s : %s"
,
cc
.
RemoteAddr
(),
addr
,
err
)
errc
<-
err
return
}
if
Debug
{
log
.
Logf
(
"[udp-tun] %s >>> %s length: %d"
,
cc
.
RemoteAddr
(),
addr
,
len
(
dgram
.
Data
))
}
}
}()
select
{
case
err
=
<-
errc
:
}
return
}
type
socks4Connector
struct
{}
// SOCKS4Connector creates a Connector for SOCKS4 proxy client.
...
...
@@ -850,11 +1137,11 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
relay
,
err
:=
net
.
ListenUDP
(
"udp"
,
nil
)
if
err
!=
nil
{
log
.
Logf
(
"[socks5-udp] %s -> %s : %s"
,
conn
.
RemoteAddr
(),
relay
.
LocalAddr
(),
err
)
log
.
Logf
(
"[socks5-udp] %s -> %s : %s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
(),
err
)
reply
:=
gosocks5
.
NewReply
(
gosocks5
.
Failure
,
nil
)
reply
.
Write
(
conn
)
if
Debug
{
log
.
Logf
(
"[socks5-udp] %s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
relay
.
LocalAddr
(),
reply
)
log
.
Logf
(
"[socks5-udp] %s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
(),
reply
)
}
return
}
...
...
@@ -864,39 +1151,39 @@ func (h *socks5Handler) handleUDPRelay(conn net.Conn, req *gosocks5.Request) {
socksAddr
.
Host
,
_
,
_
=
net
.
SplitHostPort
(
conn
.
LocalAddr
()
.
String
())
// replace the IP to the out-going interface's
reply
:=
gosocks5
.
NewReply
(
gosocks5
.
Succeeded
,
socksAddr
)
if
err
:=
reply
.
Write
(
conn
);
err
!=
nil
{
log
.
Logf
(
"[socks5-udp] %s <- %s : %s"
,
conn
.
RemoteAddr
(),
relay
.
LocalAddr
(),
err
)
log
.
Logf
(
"[socks5-udp] %s <- %s : %s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
(),
err
)
return
}
if
Debug
{
log
.
Logf
(
"[socks5-udp] %s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
reply
.
Addr
,
reply
)
log
.
Logf
(
"[socks5-udp] %s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
()
,
reply
)
}
log
.
Logf
(
"[socks5-udp] %s - %s BIND ON %s OK"
,
conn
.
RemoteAddr
(),
relay
.
LocalAddr
(),
socksAddr
)
log
.
Logf
(
"[socks5-udp] %s - %s BIND ON %s OK"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
(),
socksAddr
)
// serve as standard socks5 udp relay local <-> remote
if
h
.
options
.
Chain
.
IsEmpty
()
{
peer
,
er
:=
net
.
ListenUDP
(
"udp"
,
nil
)
if
er
!=
nil
{
log
.
Logf
(
"[socks5-udp] %s -> %s : %s"
,
conn
.
RemoteAddr
(),
socksAddr
,
er
)
log
.
Logf
(
"[socks5-udp] %s -> %s : %s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
()
,
er
)
return
}
defer
peer
.
Close
()
go
h
.
transportUDP
(
relay
,
peer
)
log
.
Logf
(
"[socks5-udp] %s <-> %s
"
,
conn
.
Remote
Addr
(),
socksAddr
)
log
.
Logf
(
"[socks5-udp] %s <-> %s
: associated on %s"
,
conn
.
RemoteAddr
(),
conn
.
Local
Addr
(),
socksAddr
)
if
err
:=
h
.
discardClientData
(
conn
);
err
!=
nil
{
log
.
Logf
(
"[socks5-udp] %s - %s : %s"
,
conn
.
RemoteAddr
(),
socksAddr
,
err
)
log
.
Logf
(
"[socks5-udp] %s - %s : %s"
,
conn
.
RemoteAddr
(),
conn
.
LocalAddr
()
,
err
)
}
log
.
Logf
(
"[socks5-udp] %s >-< %s
"
,
conn
.
Remote
Addr
(),
socksAddr
)
log
.
Logf
(
"[socks5-udp] %s >-< %s
: associated on %s"
,
conn
.
RemoteAddr
(),
conn
.
Local
Addr
(),
socksAddr
)
return
}
// forward udp local <-> tunnel
cc
,
err
:=
h
.
options
.
Chain
.
Conn
()
// connection error
if
err
!=
nil
{
log
.
Logf
(
"[socks5-udp] %s -> %s : %s"
,
conn
.
RemoteAddr
(),
socksAddr
,
err
)
return
}
// forward udp local <-> tunnel
defer
cc
.
Close
()
cc
,
err
=
socks5Handshake
(
cc
,
h
.
options
.
Chain
.
LastNode
()
.
User
)
...
...
@@ -956,17 +1243,17 @@ func (h *socks5Handler) discardClientData(conn net.Conn) (err error) {
return
}
func
(
h
*
socks5Handler
)
transportUDP
(
relay
,
peer
*
net
.
UDP
Conn
)
(
err
error
)
{
func
(
h
*
socks5Handler
)
transportUDP
(
relay
,
peer
net
.
Packet
Conn
)
(
err
error
)
{
errc
:=
make
(
chan
error
,
2
)
var
clientAddr
*
net
.
UDP
Addr
var
clientAddr
net
.
Addr
go
func
()
{
b
:=
mPool
.
Get
()
.
([]
byte
)
defer
mPool
.
Put
(
b
)
for
{
n
,
laddr
,
err
:=
relay
.
ReadFrom
UDP
(
b
)
n
,
laddr
,
err
:=
relay
.
ReadFrom
(
b
)
if
err
!=
nil
{
errc
<-
err
return
...
...
@@ -988,7 +1275,7 @@ func (h *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
log
.
Log
(
"[socks5-udp] [bypass] write to"
,
raddr
)
continue
// bypass
}
if
_
,
err
:=
peer
.
WriteTo
UDP
(
dgram
.
Data
,
raddr
);
err
!=
nil
{
if
_
,
err
:=
peer
.
WriteTo
(
dgram
.
Data
,
raddr
);
err
!=
nil
{
errc
<-
err
return
}
...
...
@@ -1003,7 +1290,7 @@ func (h *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
defer
mPool
.
Put
(
b
)
for
{
n
,
raddr
,
err
:=
peer
.
ReadFrom
UDP
(
b
)
n
,
raddr
,
err
:=
peer
.
ReadFrom
(
b
)
if
err
!=
nil
{
errc
<-
err
return
...
...
@@ -1018,7 +1305,7 @@ func (h *socks5Handler) transportUDP(relay, peer *net.UDPConn) (err error) {
buf
:=
bytes
.
Buffer
{}
dgram
:=
gosocks5
.
NewUDPDatagram
(
gosocks5
.
NewUDPHeader
(
0
,
0
,
toSocksAddr
(
raddr
)),
b
[
:
n
])
dgram
.
Write
(
&
buf
)
if
_
,
err
:=
relay
.
WriteTo
UDP
(
buf
.
Bytes
(),
clientAddr
);
err
!=
nil
{
if
_
,
err
:=
relay
.
WriteTo
(
buf
.
Bytes
(),
clientAddr
);
err
!=
nil
{
errc
<-
err
return
}
...
...
@@ -1178,7 +1465,7 @@ func (h *socks5Handler) handleUDPTunnel(conn net.Conn, req *gosocks5.Request) {
log
.
Logf
(
"[socks5-udp] %s >-< %s [tun]"
,
conn
.
RemoteAddr
(),
cc
.
RemoteAddr
())
}
func
(
h
*
socks5Handler
)
tunnelServerUDP
(
cc
net
.
Conn
,
uc
*
net
.
UDP
Conn
)
(
err
error
)
{
func
(
h
*
socks5Handler
)
tunnelServerUDP
(
cc
net
.
Conn
,
pc
net
.
Packet
Conn
)
(
err
error
)
{
errc
:=
make
(
chan
error
,
2
)
go
func
()
{
...
...
@@ -1186,9 +1473,9 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error
defer
mPool
.
Put
(
b
)
for
{
n
,
addr
,
err
:=
uc
.
ReadFromUDP
(
b
)
n
,
addr
,
err
:=
pc
.
ReadFrom
(
b
)
if
err
!=
nil
{
log
.
Logf
(
"[udp-tun] %s <- %s : %s"
,
cc
.
RemoteAddr
(),
addr
,
err
)
// log.Logf("[udp-tun] %s : %s", cc.RemoteAddr()
, err)
errc
<-
err
return
}
...
...
@@ -1215,7 +1502,7 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error
for
{
dgram
,
err
:=
gosocks5
.
ReadUDPDatagram
(
cc
)
if
err
!=
nil
{
log
.
Logf
(
"[udp-tun] %s -> 0 : %s"
,
cc
.
RemoteAddr
(),
err
)
//
log.Logf("[udp-tun] %s -> 0 : %s", cc.RemoteAddr(), err)
errc
<-
err
return
}
...
...
@@ -1229,7 +1516,7 @@ func (h *socks5Handler) tunnelServerUDP(cc net.Conn, uc *net.UDPConn) (err error
log
.
Log
(
"[udp-tun] [bypass] write to"
,
addr
)
continue
// bypass
}
if
_
,
err
:=
uc
.
WriteToUDP
(
dgram
.
Data
,
addr
);
err
!=
nil
{
if
_
,
err
:=
pc
.
WriteTo
(
dgram
.
Data
,
addr
);
err
!=
nil
{
log
.
Logf
(
"[udp-tun] %s -> %s : %s"
,
cc
.
RemoteAddr
(),
addr
,
err
)
errc
<-
err
return
...
...
@@ -1260,11 +1547,11 @@ func (h *socks5Handler) handleMuxBind(conn net.Conn, req *gosocks5.Request) {
cc
,
err
:=
h
.
options
.
Chain
.
Conn
()
if
err
!=
nil
{
log
.
Logf
(
"[socks5
-mbind]
%s <- %s : %s"
,
conn
.
RemoteAddr
(),
req
.
Addr
,
err
)
log
.
Logf
(
"[socks5
] mbind
%s <- %s : %s"
,
conn
.
RemoteAddr
(),
req
.
Addr
,
err
)
reply
:=
gosocks5
.
NewReply
(
gosocks5
.
Failure
,
nil
)
reply
.
Write
(
conn
)
if
Debug
{
log
.
Logf
(
"[socks5
-mbind]
%s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
req
.
Addr
,
reply
)
log
.
Logf
(
"[socks5
] mbind
%s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
req
.
Addr
,
reply
)
}
return
}
...
...
@@ -1274,16 +1561,16 @@ func (h *socks5Handler) handleMuxBind(conn net.Conn, req *gosocks5.Request) {
// so we don't need to authenticate it, as it's as explicit as whitelisting.
defer
cc
.
Close
()
req
.
Write
(
cc
)
log
.
Logf
(
"[socks5
-mbind]
%s <-> %s"
,
conn
.
RemoteAddr
(),
cc
.
RemoteAddr
())
log
.
Logf
(
"[socks5
] mbind
%s <-> %s"
,
conn
.
RemoteAddr
(),
cc
.
RemoteAddr
())
transport
(
conn
,
cc
)
log
.
Logf
(
"[socks5
-mbind]
%s >-< %s"
,
conn
.
RemoteAddr
(),
cc
.
RemoteAddr
())
log
.
Logf
(
"[socks5
] mbind
%s >-< %s"
,
conn
.
RemoteAddr
(),
cc
.
RemoteAddr
())
}
func
(
h
*
socks5Handler
)
muxBindOn
(
conn
net
.
Conn
,
addr
string
)
{
bindAddr
,
_
:=
net
.
ResolveTCPAddr
(
"tcp"
,
addr
)
ln
,
err
:=
net
.
ListenTCP
(
"tcp"
,
bindAddr
)
// strict mode: if the port already in use, it will return error
if
err
!=
nil
{
log
.
Logf
(
"[socks5
-mbind]
%s -> %s : %s"
,
conn
.
RemoteAddr
(),
addr
,
err
)
log
.
Logf
(
"[socks5
] mbind
%s -> %s : %s"
,
conn
.
RemoteAddr
(),
addr
,
err
)
gosocks5
.
NewReply
(
gosocks5
.
Failure
,
nil
)
.
Write
(
conn
)
return
}
...
...
@@ -1294,23 +1581,23 @@ func (h *socks5Handler) muxBindOn(conn net.Conn, addr string) {
socksAddr
.
Host
,
_
,
_
=
net
.
SplitHostPort
(
conn
.
LocalAddr
()
.
String
())
reply
:=
gosocks5
.
NewReply
(
gosocks5
.
Succeeded
,
socksAddr
)
if
err
:=
reply
.
Write
(
conn
);
err
!=
nil
{
log
.
Logf
(
"[socks5
-mbind]
%s <- %s : %s"
,
conn
.
RemoteAddr
(),
addr
,
err
)
log
.
Logf
(
"[socks5
] mbind
%s <- %s : %s"
,
conn
.
RemoteAddr
(),
addr
,
err
)
return
}
if
Debug
{
log
.
Logf
(
"[socks5
-mbind]
%s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
addr
,
reply
)
log
.
Logf
(
"[socks5
] mbind
%s <- %s
\n
%s"
,
conn
.
RemoteAddr
(),
addr
,
reply
)
}
log
.
Logf
(
"[socks5
-mbind]
%s - %s BIND ON %s OK"
,
conn
.
RemoteAddr
(),
addr
,
socksAddr
)
log
.
Logf
(
"[socks5
] mbind
%s - %s BIND ON %s OK"
,
conn
.
RemoteAddr
(),
addr
,
socksAddr
)
// Upgrade connection to multiplex stream.
s
,
err
:=
smux
.
Client
(
conn
,
smux
.
DefaultConfig
())
if
err
!=
nil
{
log
.
Logf
(
"[socks5
-mbind]
%s - %s : %s"
,
conn
.
RemoteAddr
(),
socksAddr
,
err
)
log
.
Logf
(
"[socks5
] mbind
%s - %s : %s"
,
conn
.
RemoteAddr
(),
socksAddr
,
err
)
return
}
log
.
Logf
(
"[socks5
-mbind]
%s <-> %s"
,
conn
.
RemoteAddr
(),
socksAddr
)
defer
log
.
Logf
(
"[socks5
-mbind]
%s >-< %s"
,
conn
.
RemoteAddr
(),
socksAddr
)
log
.
Logf
(
"[socks5
] mbind
%s <-> %s"
,
conn
.
RemoteAddr
(),
socksAddr
)
defer
log
.
Logf
(
"[socks5
] mbind
%s >-< %s"
,
conn
.
RemoteAddr
(),
socksAddr
)
session
:=
&
muxSession
{
conn
:
conn
,
...
...
@@ -1322,6 +1609,7 @@ func (h *socks5Handler) muxBindOn(conn net.Conn, addr string) {
for
{
conn
,
err
:=
session
.
Accept
()
if
err
!=
nil
{
log
.
Logf
(
"[socks5] mbind accept : %v"
,
err
)
ln
.
Close
()
return
}
...
...
@@ -1332,10 +1620,10 @@ func (h *socks5Handler) muxBindOn(conn net.Conn, addr string) {
for
{
cc
,
err
:=
ln
.
Accept
()
if
err
!=
nil
{
// log.Logf("[socks5-mbind]
%s <- %s : %v", conn.RemoteAddr(), socksAddr, err)
log
.
Logf
(
"[socks5] mbind
%s <- %s : %v"
,
conn
.
RemoteAddr
(),
socksAddr
,
err
)
return
}
log
.
Logf
(
"[socks5
-mbind]
%s <- %s : ACCEPT peer %s"
,
log
.
Logf
(
"[socks5
] mbind
%s <- %s : ACCEPT peer %s"
,
conn
.
RemoteAddr
(),
socksAddr
,
cc
.
RemoteAddr
())
go
func
(
c
net
.
Conn
)
{
...
...
@@ -1343,9 +1631,11 @@ func (h *socks5Handler) muxBindOn(conn net.Conn, addr string) {
sc
,
err
:=
session
.
GetConn
()
if
err
!=
nil
{
log
.
Logf
(
"[socks5
-mbind]
%s <- %s : %s"
,
conn
.
RemoteAddr
(),
socksAddr
,
err
)
log
.
Logf
(
"[socks5
] mbind
%s <- %s : %s"
,
conn
.
RemoteAddr
(),
socksAddr
,
err
)
return
}
defer
sc
.
Close
()
transport
(
sc
,
c
)
}(
cc
)
}
...
...
@@ -1550,6 +1840,10 @@ func getSOCKS5UDPTunnel(chain *Chain, addr net.Addr) (net.Conn, error) {
if
err
!=
nil
{
return
nil
,
err
}
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
HandshakeTimeout
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
cc
,
err
:=
socks5Handshake
(
conn
,
chain
.
LastNode
()
.
User
)
if
err
!=
nil
{
conn
.
Close
()
...
...
@@ -1557,7 +1851,6 @@ func getSOCKS5UDPTunnel(chain *Chain, addr net.Addr) (net.Conn, error) {
}
conn
=
cc
conn
.
SetWriteDeadline
(
time
.
Now
()
.
Add
(
WriteTimeout
))
req
:=
gosocks5
.
NewRequest
(
CmdUDPTun
,
toSocksAddr
(
addr
))
if
err
:=
req
.
Write
(
conn
);
err
!=
nil
{
conn
.
Close
()
...
...
@@ -1566,15 +1859,13 @@ func getSOCKS5UDPTunnel(chain *Chain, addr net.Addr) (net.Conn, error) {
if
Debug
{
log
.
Log
(
"[socks5]"
,
req
)
}
conn
.
SetWriteDeadline
(
time
.
Time
{})
conn
.
SetReadDeadline
(
time
.
Now
()
.
Add
(
ReadTimeout
))
reply
,
err
:=
gosocks5
.
ReadReply
(
conn
)
if
err
!=
nil
{
conn
.
Close
()
return
nil
,
err
}
conn
.
SetReadDeadline
(
time
.
Time
{})
if
Debug
{
log
.
Log
(
"[socks5]"
,
reply
)
}
...
...
@@ -1647,7 +1938,7 @@ func (c *udpTunnelConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
return
len
(
b
),
nil
}
// socks5BindConn is a connection for SOCKS5 bind
reques
t.
// socks5BindConn is a connection for SOCKS5 bind
clien
t.
type
socks5BindConn
struct
{
raddr
net
.
Addr
laddr
net
.
Addr
...
...
@@ -1758,3 +2049,13 @@ func (c *socks5UDPConn) WriteTo(b []byte, addr net.Addr) (int, error) {
}
return
len
(
b
),
nil
}
// a dummy client conn for multiplex bind used by SOCKS5 multiplex bind client connector
type
muxBindClientConn
struct
{
nopConn
session
*
muxSession
}
func
(
c
*
muxBindClientConn
)
Accept
()
(
net
.
Conn
,
error
)
{
return
c
.
session
.
Accept
()
}
socks_test.go
View file @
445889c4
package
gost
import
(
"bytes"
"crypto/rand"
"fmt"
"net"
"net/http/httptest"
"net/url"
"testing"
"time"
)
var
socks5ProxyTests
=
[]
struct
{
...
...
@@ -407,6 +410,128 @@ func TestSOCKS5Bind(t *testing.T) {
}
}
func
socks5MuxBindRoundtrip
(
t
*
testing
.
T
,
targetURL
string
,
data
[]
byte
)
(
err
error
)
{
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
return
}
l
,
err
:=
net
.
Listen
(
"tcp"
,
""
)
if
err
!=
nil
{
return
err
}
bindAddr
:=
l
.
Addr
()
.
String
()
l
.
Close
()
client
:=
&
Client
{
Connector
:
Socks5MuxBindConnector
(),
Transporter
:
SOCKS5MuxBindTransporter
(
bindAddr
),
}
server
:=
&
Server
{
Handler
:
SOCKS5Handler
(
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
))),
Listener
:
ln
,
}
go
server
.
Run
()
defer
server
.
Close
()
return
muxBindRoundtrip
(
client
,
server
,
bindAddr
,
targetURL
,
data
)
}
func
muxBindRoundtrip
(
client
*
Client
,
server
*
Server
,
bindAddr
,
targetURL
string
,
data
[]
byte
)
(
err
error
)
{
cn
,
err
:=
client
.
Dial
(
server
.
Addr
()
.
String
())
if
err
!=
nil
{
return
err
}
conn
,
err
:=
client
.
Handshake
(
cn
,
AddrHandshakeOption
(
server
.
Addr
()
.
String
()),
UserHandshakeOption
(
url
.
UserPassword
(
"admin"
,
"123456"
)),
)
if
err
!=
nil
{
cn
.
Close
()
return
err
}
defer
conn
.
Close
()
cc
,
err
:=
net
.
Dial
(
"tcp"
,
bindAddr
)
if
err
!=
nil
{
return
}
defer
cc
.
Close
()
conn
,
err
=
client
.
Connect
(
conn
,
""
)
if
err
!=
nil
{
return
}
u
,
err
:=
url
.
Parse
(
targetURL
)
if
err
!=
nil
{
return
}
hc
,
err
:=
net
.
Dial
(
"tcp"
,
u
.
Host
)
if
err
!=
nil
{
return
}
defer
hc
.
Close
()
go
transport
(
hc
,
conn
)
return
httpRoundtrip
(
cc
,
targetURL
,
data
)
}
func
TestSOCKS5MuxBind
(
t
*
testing
.
T
)
{
httpSrv
:=
httptest
.
NewServer
(
httpTestHandler
)
defer
httpSrv
.
Close
()
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
if
err
:=
socks5MuxBindRoundtrip
(
t
,
httpSrv
.
URL
,
sendData
);
err
!=
nil
{
t
.
Errorf
(
"got error: %v"
,
err
)
}
}
func
BenchmarkSOCKS5MuxBind
(
b
*
testing
.
B
)
{
httpSrv
:=
httptest
.
NewServer
(
httpTestHandler
)
defer
httpSrv
.
Close
()
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
b
.
Error
(
err
)
}
l
,
err
:=
net
.
Listen
(
"tcp"
,
""
)
if
err
!=
nil
{
b
.
Error
(
err
)
}
bindAddr
:=
l
.
Addr
()
.
String
()
l
.
Close
()
client
:=
&
Client
{
Connector
:
Socks5MuxBindConnector
(),
Transporter
:
SOCKS5MuxBindTransporter
(
bindAddr
),
}
server
:=
&
Server
{
Handler
:
SOCKS5Handler
(
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
))),
Listener
:
ln
,
}
go
server
.
Run
()
defer
server
.
Close
()
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
if
err
:=
muxBindRoundtrip
(
client
,
server
,
bindAddr
,
httpSrv
.
URL
,
sendData
);
err
!=
nil
{
b
.
Error
(
err
)
}
}
}
func
socks5UDPRoundtrip
(
t
*
testing
.
T
,
host
string
,
data
[]
byte
)
(
err
error
)
{
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
...
...
@@ -440,3 +565,226 @@ func TestSOCKS5UDP(t *testing.T) {
t
.
Errorf
(
"got error: %v"
,
err
)
}
}
// TODO: fix a probability of timeout.
func
BenchmarkSOCKS5UDP
(
b
*
testing
.
B
)
{
udpSrv
:=
newUDPTestServer
(
udpTestHandler
)
udpSrv
.
Start
()
defer
udpSrv
.
Close
()
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
b
.
Error
(
err
)
}
client
:=
&
Client
{
Connector
:
SOCKS5UDPConnector
(
url
.
UserPassword
(
"admin"
,
"123456"
)),
Transporter
:
TCPTransporter
(),
}
server
:=
&
Server
{
Handler
:
SOCKS5Handler
(
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
))),
Listener
:
ln
,
}
go
server
.
Run
()
defer
server
.
Close
()
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
if
err
:=
udpRoundtrip
(
client
,
server
,
udpSrv
.
Addr
(),
sendData
);
err
!=
nil
{
b
.
Error
(
err
)
}
}
}
func
BenchmarkSOCKS5UDPSingleConn
(
b
*
testing
.
B
)
{
udpSrv
:=
newUDPTestServer
(
udpTestHandler
)
udpSrv
.
Start
()
defer
udpSrv
.
Close
()
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
b
.
Error
(
err
)
}
client
:=
&
Client
{
Connector
:
SOCKS5UDPConnector
(
url
.
UserPassword
(
"admin"
,
"123456"
)),
Transporter
:
TCPTransporter
(),
}
server
:=
&
Server
{
Handler
:
SOCKS5Handler
(
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
))),
Listener
:
ln
,
}
go
server
.
Run
()
defer
server
.
Close
()
conn
,
err
:=
proxyConn
(
client
,
server
)
if
err
!=
nil
{
b
.
Error
(
err
)
}
defer
conn
.
Close
()
conn
,
err
=
client
.
Connect
(
conn
,
udpSrv
.
Addr
())
if
err
!=
nil
{
b
.
Error
(
err
)
}
roundtrip
:=
func
(
conn
net
.
Conn
,
data
[]
byte
)
error
{
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
1
*
time
.
Second
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
if
_
,
err
=
conn
.
Write
(
data
);
err
!=
nil
{
return
err
}
recv
:=
make
([]
byte
,
len
(
data
))
if
_
,
err
=
conn
.
Read
(
recv
);
err
!=
nil
{
return
err
}
if
!
bytes
.
Equal
(
data
,
recv
)
{
return
fmt
.
Errorf
(
"data not equal"
)
}
return
nil
}
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
if
err
:=
roundtrip
(
conn
,
sendData
);
err
!=
nil
{
b
.
Error
(
err
)
}
}
}
func
socks5UDPTunRoundtrip
(
t
*
testing
.
T
,
host
string
,
data
[]
byte
)
(
err
error
)
{
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
return
}
client
:=
&
Client
{
Connector
:
SOCKS5UDPTunConnector
(
url
.
UserPassword
(
"admin"
,
"123456"
)),
Transporter
:
TCPTransporter
(),
}
server
:=
&
Server
{
Handler
:
SOCKS5Handler
(
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
))),
Listener
:
ln
,
}
go
server
.
Run
()
defer
server
.
Close
()
return
udpRoundtrip
(
client
,
server
,
host
,
data
)
}
func
TestSOCKS5UDPTun
(
t
*
testing
.
T
)
{
udpSrv
:=
newUDPTestServer
(
udpTestHandler
)
udpSrv
.
Start
()
defer
udpSrv
.
Close
()
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
if
err
:=
socks5UDPTunRoundtrip
(
t
,
udpSrv
.
Addr
(),
sendData
);
err
!=
nil
{
t
.
Errorf
(
"got error: %v"
,
err
)
}
}
func
BenchmarkSOCKS5UDPTun
(
b
*
testing
.
B
)
{
udpSrv
:=
newUDPTestServer
(
udpTestHandler
)
udpSrv
.
Start
()
defer
udpSrv
.
Close
()
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
b
.
Error
(
err
)
}
client
:=
&
Client
{
Connector
:
SOCKS5UDPTunConnector
(
url
.
UserPassword
(
"admin"
,
"123456"
)),
Transporter
:
TCPTransporter
(),
}
server
:=
&
Server
{
Handler
:
SOCKS5Handler
(
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
))),
Listener
:
ln
,
}
go
server
.
Run
()
defer
server
.
Close
()
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
if
err
:=
udpRoundtrip
(
client
,
server
,
udpSrv
.
Addr
(),
sendData
);
err
!=
nil
{
b
.
Error
(
err
)
}
}
}
func
BenchmarkSOCKS5UDPTunSingleConn
(
b
*
testing
.
B
)
{
udpSrv
:=
newUDPTestServer
(
udpTestHandler
)
udpSrv
.
Start
()
defer
udpSrv
.
Close
()
sendData
:=
make
([]
byte
,
128
)
rand
.
Read
(
sendData
)
ln
,
err
:=
TCPListener
(
""
)
if
err
!=
nil
{
b
.
Error
(
err
)
}
client
:=
&
Client
{
Connector
:
SOCKS5UDPTunConnector
(
url
.
UserPassword
(
"admin"
,
"123456"
)),
Transporter
:
TCPTransporter
(),
}
server
:=
&
Server
{
Handler
:
SOCKS5Handler
(
UsersHandlerOption
(
url
.
UserPassword
(
"admin"
,
"123456"
))),
Listener
:
ln
,
}
go
server
.
Run
()
defer
server
.
Close
()
conn
,
err
:=
proxyConn
(
client
,
server
)
if
err
!=
nil
{
b
.
Error
(
err
)
}
defer
conn
.
Close
()
conn
,
err
=
client
.
Connect
(
conn
,
udpSrv
.
Addr
())
if
err
!=
nil
{
b
.
Error
(
err
)
}
roundtrip
:=
func
(
conn
net
.
Conn
,
data
[]
byte
)
error
{
conn
.
SetDeadline
(
time
.
Now
()
.
Add
(
1
*
time
.
Second
))
defer
conn
.
SetDeadline
(
time
.
Time
{})
if
_
,
err
=
conn
.
Write
(
data
);
err
!=
nil
{
return
err
}
recv
:=
make
([]
byte
,
len
(
data
))
if
_
,
err
=
conn
.
Read
(
recv
);
err
!=
nil
{
return
err
}
if
!
bytes
.
Equal
(
data
,
recv
)
{
return
fmt
.
Errorf
(
"data not equal"
)
}
return
nil
}
for
i
:=
0
;
i
<
b
.
N
;
i
++
{
if
err
:=
roundtrip
(
conn
,
sendData
);
err
!=
nil
{
b
.
Error
(
err
)
}
}
}
ss_test.go
View file @
445889c4
...
...
@@ -2,6 +2,7 @@ package gost
import
(
"crypto/rand"
"fmt"
"net/http/httptest"
"net/url"
"testing"
...
...
@@ -148,6 +149,8 @@ func TestSSProxy(t *testing.T) {
rand
.
Read
(
sendData
)
for
i
,
tc
:=
range
ssTests
{
tc
:=
tc
t
.
Run
(
fmt
.
Sprintf
(
"#%d"
,
i
),
func
(
t
*
testing
.
T
)
{
err
:=
ssProxyRoundtrip
(
httpSrv
.
URL
,
sendData
,
tc
.
clientCipher
,
tc
.
serverCipher
,
...
...
@@ -162,6 +165,7 @@ func TestSSProxy(t *testing.T) {
t
.
Errorf
(
"#%d got error: %v"
,
i
,
err
)
}
}
})
}
}
...
...
@@ -317,7 +321,7 @@ func shadowUDPRoundtrip(t *testing.T, host string, data []byte) error {
return
udpRoundtrip
(
client
,
server
,
host
,
data
)
}
func
TestShadowUDP
(
t
*
testing
.
T
)
{
func
_
TestShadowUDP
(
t
*
testing
.
T
)
{
udpSrv
:=
newUDPTestServer
(
udpTestHandler
)
udpSrv
.
Start
()
defer
udpSrv
.
Close
()
...
...
tls.go
View file @
445889c4
...
...
@@ -58,21 +58,20 @@ func (tr *mtlsTransporter) Dial(addr string, options ...DialOption) (conn net.Co
option
(
opts
)
}
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
DialTimeout
}
tr
.
sessionMutex
.
Lock
()
defer
tr
.
sessionMutex
.
Unlock
()
session
,
ok
:=
tr
.
sessions
[
addr
]
if
session
!=
nil
&&
session
.
session
!=
nil
&&
session
.
session
.
IsClosed
()
{
session
.
Close
()
if
session
!=
nil
&&
session
.
IsClosed
()
{
delete
(
tr
.
sessions
,
addr
)
ok
=
false
ok
=
false
// session is dead
}
if
!
ok
{
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
DialTimeout
}
if
opts
.
Chain
==
nil
{
conn
,
err
=
net
.
DialTimeout
(
"tcp"
,
addr
,
timeout
)
}
else
{
...
...
@@ -159,10 +158,12 @@ func TLSListener(addr string, config *tls.Config) (Listener, error) {
if
config
==
nil
{
config
=
DefaultTLSConfig
}
ln
,
err
:=
tls
.
Listen
(
"tcp"
,
addr
,
config
)
ln
,
err
:=
net
.
Listen
(
"tcp"
,
addr
)
if
err
!=
nil
{
return
nil
,
err
}
ln
=
tls
.
NewListener
(
tcpKeepAliveListener
{
ln
.
(
*
net
.
TCPListener
)},
config
)
return
&
tlsListener
{
ln
},
nil
}
...
...
@@ -177,13 +178,13 @@ func MTLSListener(addr string, config *tls.Config) (Listener, error) {
if
config
==
nil
{
config
=
DefaultTLSConfig
}
ln
,
err
:=
tls
.
Listen
(
"tcp"
,
addr
,
config
)
ln
,
err
:=
net
.
Listen
(
"tcp"
,
addr
)
if
err
!=
nil
{
return
nil
,
err
}
l
:=
&
mtlsListener
{
ln
:
ln
,
ln
:
tls
.
NewListener
(
tcpKeepAliveListener
{
ln
.
(
*
net
.
TCPListener
)},
config
)
,
connChan
:
make
(
chan
net
.
Conn
,
1024
),
errChan
:
make
(
chan
error
,
1
),
}
...
...
ws.go
View file @
445889c4
...
...
@@ -28,92 +28,6 @@ type WSOptions struct {
UserAgent
string
}
type
websocketConn
struct
{
conn
*
websocket
.
Conn
rb
[]
byte
}
func
websocketClientConn
(
url
string
,
conn
net
.
Conn
,
tlsConfig
*
tls
.
Config
,
options
*
WSOptions
)
(
net
.
Conn
,
error
)
{
if
options
==
nil
{
options
=
&
WSOptions
{}
}
timeout
:=
options
.
HandshakeTimeout
if
timeout
<=
0
{
timeout
=
HandshakeTimeout
}
dialer
:=
websocket
.
Dialer
{
ReadBufferSize
:
options
.
ReadBufferSize
,
WriteBufferSize
:
options
.
WriteBufferSize
,
TLSClientConfig
:
tlsConfig
,
HandshakeTimeout
:
timeout
,
EnableCompression
:
options
.
EnableCompression
,
NetDial
:
func
(
net
,
addr
string
)
(
net
.
Conn
,
error
)
{
return
conn
,
nil
},
}
header
:=
http
.
Header
{}
header
.
Set
(
"User-Agent"
,
DefaultUserAgent
)
if
options
.
UserAgent
!=
""
{
header
.
Set
(
"User-Agent"
,
options
.
UserAgent
)
}
c
,
resp
,
err
:=
dialer
.
Dial
(
url
,
header
)
if
err
!=
nil
{
return
nil
,
err
}
resp
.
Body
.
Close
()
return
&
websocketConn
{
conn
:
c
},
nil
}
func
websocketServerConn
(
conn
*
websocket
.
Conn
)
net
.
Conn
{
// conn.EnableWriteCompression(true)
return
&
websocketConn
{
conn
:
conn
,
}
}
func
(
c
*
websocketConn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
if
len
(
c
.
rb
)
==
0
{
_
,
c
.
rb
,
err
=
c
.
conn
.
ReadMessage
()
}
n
=
copy
(
b
,
c
.
rb
)
c
.
rb
=
c
.
rb
[
n
:
]
return
}
func
(
c
*
websocketConn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
err
=
c
.
conn
.
WriteMessage
(
websocket
.
BinaryMessage
,
b
)
n
=
len
(
b
)
return
}
func
(
c
*
websocketConn
)
Close
()
error
{
return
c
.
conn
.
Close
()
}
func
(
c
*
websocketConn
)
LocalAddr
()
net
.
Addr
{
return
c
.
conn
.
LocalAddr
()
}
func
(
c
*
websocketConn
)
RemoteAddr
()
net
.
Addr
{
return
c
.
conn
.
RemoteAddr
()
}
func
(
c
*
websocketConn
)
SetDeadline
(
t
time
.
Time
)
error
{
if
err
:=
c
.
SetReadDeadline
(
t
);
err
!=
nil
{
return
err
}
return
c
.
SetWriteDeadline
(
t
)
}
func
(
c
*
websocketConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetReadDeadline
(
t
)
}
func
(
c
*
websocketConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetWriteDeadline
(
t
)
}
type
wsTransporter
struct
{
tcpTransporter
options
*
WSOptions
...
...
@@ -160,21 +74,20 @@ func (tr *mwsTransporter) Dial(addr string, options ...DialOption) (conn net.Con
option
(
opts
)
}
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
DialTimeout
}
tr
.
sessionMutex
.
Lock
()
defer
tr
.
sessionMutex
.
Unlock
()
session
,
ok
:=
tr
.
sessions
[
addr
]
if
session
!=
nil
&&
session
.
session
!=
nil
&&
session
.
session
.
IsClosed
()
{
session
.
Close
()
if
session
!=
nil
&&
session
.
IsClosed
()
{
delete
(
tr
.
sessions
,
addr
)
ok
=
false
}
if
!
ok
{
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
DialTimeout
}
if
opts
.
Chain
==
nil
{
conn
,
err
=
net
.
DialTimeout
(
"tcp"
,
addr
,
timeout
)
}
else
{
...
...
@@ -302,21 +215,20 @@ func (tr *mwssTransporter) Dial(addr string, options ...DialOption) (conn net.Co
option
(
opts
)
}
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
DialTimeout
}
tr
.
sessionMutex
.
Lock
()
defer
tr
.
sessionMutex
.
Unlock
()
session
,
ok
:=
tr
.
sessions
[
addr
]
if
session
!=
nil
&&
session
.
session
!=
nil
&&
session
.
session
.
IsClosed
()
{
session
.
Close
()
if
session
!=
nil
&&
session
.
IsClosed
()
{
delete
(
tr
.
sessions
,
addr
)
ok
=
false
}
if
!
ok
{
timeout
:=
opts
.
Timeout
if
timeout
<=
0
{
timeout
=
DialTimeout
}
if
opts
.
Chain
==
nil
{
conn
,
err
=
net
.
DialTimeout
(
"tcp"
,
addr
,
timeout
)
}
else
{
...
...
@@ -428,7 +340,11 @@ func WSListener(addr string, options *WSOptions) (Listener, error) {
mux
:=
http
.
NewServeMux
()
mux
.
Handle
(
"/ws"
,
http
.
HandlerFunc
(
l
.
upgrade
))
l
.
srv
=
&
http
.
Server
{
Addr
:
addr
,
Handler
:
mux
}
l
.
srv
=
&
http
.
Server
{
Addr
:
addr
,
Handler
:
mux
,
ReadHeaderTimeout
:
30
*
time
.
Second
,
}
ln
,
err
:=
net
.
ListenTCP
(
"tcp"
,
tcpAddr
)
if
err
!=
nil
{
...
...
@@ -517,7 +433,11 @@ func MWSListener(addr string, options *WSOptions) (Listener, error) {
mux
:=
http
.
NewServeMux
()
mux
.
Handle
(
"/ws"
,
http
.
HandlerFunc
(
l
.
upgrade
))
l
.
srv
=
&
http
.
Server
{
Addr
:
addr
,
Handler
:
mux
}
l
.
srv
=
&
http
.
Server
{
Addr
:
addr
,
Handler
:
mux
,
ReadHeaderTimeout
:
30
*
time
.
Second
,
}
ln
,
err
:=
net
.
ListenTCP
(
"tcp"
,
tcpAddr
)
if
err
!=
nil
{
...
...
@@ -637,6 +557,7 @@ func WSSListener(addr string, tlsConfig *tls.Config, options *WSOptions) (Listen
Addr
:
addr
,
TLSConfig
:
tlsConfig
,
Handler
:
mux
,
ReadHeaderTimeout
:
30
*
time
.
Second
,
}
ln
,
err
:=
net
.
ListenTCP
(
"tcp"
,
tcpAddr
)
...
...
@@ -697,6 +618,7 @@ func MWSSListener(addr string, tlsConfig *tls.Config, options *WSOptions) (Liste
Addr
:
addr
,
TLSConfig
:
tlsConfig
,
Handler
:
mux
,
ReadHeaderTimeout
:
30
*
time
.
Second
,
}
ln
,
err
:=
net
.
ListenTCP
(
"tcp"
,
tcpAddr
)
...
...
@@ -737,3 +659,89 @@ func generateChallengeKey() (string, error) {
}
return
base64
.
StdEncoding
.
EncodeToString
(
p
),
nil
}
type
websocketConn
struct
{
conn
*
websocket
.
Conn
rb
[]
byte
}
func
websocketClientConn
(
url
string
,
conn
net
.
Conn
,
tlsConfig
*
tls
.
Config
,
options
*
WSOptions
)
(
net
.
Conn
,
error
)
{
if
options
==
nil
{
options
=
&
WSOptions
{}
}
timeout
:=
options
.
HandshakeTimeout
if
timeout
<=
0
{
timeout
=
HandshakeTimeout
}
dialer
:=
websocket
.
Dialer
{
ReadBufferSize
:
options
.
ReadBufferSize
,
WriteBufferSize
:
options
.
WriteBufferSize
,
TLSClientConfig
:
tlsConfig
,
HandshakeTimeout
:
timeout
,
EnableCompression
:
options
.
EnableCompression
,
NetDial
:
func
(
net
,
addr
string
)
(
net
.
Conn
,
error
)
{
return
conn
,
nil
},
}
header
:=
http
.
Header
{}
header
.
Set
(
"User-Agent"
,
DefaultUserAgent
)
if
options
.
UserAgent
!=
""
{
header
.
Set
(
"User-Agent"
,
options
.
UserAgent
)
}
c
,
resp
,
err
:=
dialer
.
Dial
(
url
,
header
)
if
err
!=
nil
{
return
nil
,
err
}
resp
.
Body
.
Close
()
return
&
websocketConn
{
conn
:
c
},
nil
}
func
websocketServerConn
(
conn
*
websocket
.
Conn
)
net
.
Conn
{
// conn.EnableWriteCompression(true)
return
&
websocketConn
{
conn
:
conn
,
}
}
func
(
c
*
websocketConn
)
Read
(
b
[]
byte
)
(
n
int
,
err
error
)
{
if
len
(
c
.
rb
)
==
0
{
_
,
c
.
rb
,
err
=
c
.
conn
.
ReadMessage
()
}
n
=
copy
(
b
,
c
.
rb
)
c
.
rb
=
c
.
rb
[
n
:
]
return
}
func
(
c
*
websocketConn
)
Write
(
b
[]
byte
)
(
n
int
,
err
error
)
{
err
=
c
.
conn
.
WriteMessage
(
websocket
.
BinaryMessage
,
b
)
n
=
len
(
b
)
return
}
func
(
c
*
websocketConn
)
Close
()
error
{
return
c
.
conn
.
Close
()
}
func
(
c
*
websocketConn
)
LocalAddr
()
net
.
Addr
{
return
c
.
conn
.
LocalAddr
()
}
func
(
c
*
websocketConn
)
RemoteAddr
()
net
.
Addr
{
return
c
.
conn
.
RemoteAddr
()
}
func
(
c
*
websocketConn
)
SetDeadline
(
t
time
.
Time
)
error
{
if
err
:=
c
.
SetReadDeadline
(
t
);
err
!=
nil
{
return
err
}
return
c
.
SetWriteDeadline
(
t
)
}
func
(
c
*
websocketConn
)
SetReadDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetReadDeadline
(
t
)
}
func
(
c
*
websocketConn
)
SetWriteDeadline
(
t
time
.
Time
)
error
{
return
c
.
conn
.
SetWriteDeadline
(
t
)
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment