add more tests
This commit is contained in:
parent
d3b03e4231
commit
bb1afcc437
21
Dockerfile.mod
Normal file
21
Dockerfile.mod
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
FROM golang:1-alpine as builder
|
||||||
|
|
||||||
|
RUN apk add --no-cache musl-dev git gcc
|
||||||
|
|
||||||
|
ADD . /data
|
||||||
|
|
||||||
|
WORKDIR /data
|
||||||
|
|
||||||
|
ENV GO111MODULE=on
|
||||||
|
|
||||||
|
RUN cd cmd/gost && go build
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
|
||||||
|
WORKDIR /bin/
|
||||||
|
|
||||||
|
COPY --from=builder /data/cmd/gost/gost .
|
||||||
|
|
||||||
|
RUN /bin/gost -V
|
||||||
|
|
||||||
|
ENTRYPOINT ["/bin/gost"]
|
@ -110,6 +110,8 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
|||||||
wsOpts.WriteBufferSize = node.GetInt("wbuf")
|
wsOpts.WriteBufferSize = node.GetInt("wbuf")
|
||||||
wsOpts.UserAgent = node.Get("agent")
|
wsOpts.UserAgent = node.Get("agent")
|
||||||
|
|
||||||
|
var host string
|
||||||
|
|
||||||
var tr gost.Transporter
|
var tr gost.Transporter
|
||||||
switch node.Transport {
|
switch node.Transport {
|
||||||
case "tls":
|
case "tls":
|
||||||
@ -160,6 +162,7 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
|||||||
case "obfs4":
|
case "obfs4":
|
||||||
tr = gost.Obfs4Transporter()
|
tr = gost.Obfs4Transporter()
|
||||||
case "ohttp":
|
case "ohttp":
|
||||||
|
host = node.Get("host")
|
||||||
tr = gost.ObfsHTTPTransporter()
|
tr = gost.ObfsHTTPTransporter()
|
||||||
default:
|
default:
|
||||||
tr = gost.TCPTransporter()
|
tr = gost.TCPTransporter()
|
||||||
@ -197,9 +200,12 @@ func parseChainNode(ns string) (nodes []gost.Node, err error) {
|
|||||||
gost.TimeoutDialOption(time.Duration(timeout)*time.Second),
|
gost.TimeoutDialOption(time.Duration(timeout)*time.Second),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if host == "" {
|
||||||
|
host = node.Host
|
||||||
|
}
|
||||||
handshakeOptions := []gost.HandshakeOption{
|
handshakeOptions := []gost.HandshakeOption{
|
||||||
gost.AddrHandshakeOption(node.Addr),
|
gost.AddrHandshakeOption(node.Addr),
|
||||||
gost.HostHandshakeOption(node.Host),
|
gost.HostHandshakeOption(host),
|
||||||
gost.UserHandshakeOption(node.User),
|
gost.UserHandshakeOption(node.User),
|
||||||
gost.TLSConfigHandshakeOption(tlsCfg),
|
gost.TLSConfigHandshakeOption(tlsCfg),
|
||||||
gost.IntervalHandshakeOption(time.Duration(node.GetInt("ping")) * time.Second),
|
gost.IntervalHandshakeOption(time.Duration(node.GetInt("ping")) * time.Second),
|
||||||
|
9
http2.go
9
http2.go
@ -34,6 +34,11 @@ func HTTP2Connector(user *url.Userinfo) Connector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *http2Connector) Connect(conn net.Conn, addr string, options ...ConnectOption) (net.Conn, error) {
|
func (c *http2Connector) Connect(conn net.Conn, addr string, options ...ConnectOption) (net.Conn, error) {
|
||||||
|
opts := &ConnectOptions{}
|
||||||
|
for _, option := range options {
|
||||||
|
option(opts)
|
||||||
|
}
|
||||||
|
|
||||||
cc, ok := conn.(*http2ClientConn)
|
cc, ok := conn.(*http2ClientConn)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, errors.New("wrong connection type")
|
return nil, errors.New("wrong connection type")
|
||||||
@ -142,7 +147,7 @@ func (tr *http2Transporter) Dial(addr string, options ...DialOption) (net.Conn,
|
|||||||
}
|
}
|
||||||
client = &http.Client{
|
client = &http.Client{
|
||||||
Transport: &transport,
|
Transport: &transport,
|
||||||
Timeout: timeout,
|
// Timeout: timeout,
|
||||||
}
|
}
|
||||||
tr.clients[addr] = client
|
tr.clients[addr] = client
|
||||||
}
|
}
|
||||||
@ -214,7 +219,7 @@ func (tr *h2Transporter) Dial(addr string, options ...DialOption) (net.Conn, err
|
|||||||
}
|
}
|
||||||
client = &http.Client{
|
client = &http.Client{
|
||||||
Transport: &transport,
|
Transport: &transport,
|
||||||
Timeout: timeout,
|
// Timeout: timeout,
|
||||||
}
|
}
|
||||||
tr.clients[addr] = client
|
tr.clients[addr] = client
|
||||||
}
|
}
|
||||||
|
61
obfs.go
61
obfs.go
@ -67,10 +67,7 @@ func (l *obfsHTTPListener) Accept() (net.Conn, error) {
|
|||||||
type obfsHTTPConn struct {
|
type obfsHTTPConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
host string
|
host string
|
||||||
request *http.Request
|
buf []byte
|
||||||
response *http.Response
|
|
||||||
rbuf []byte
|
|
||||||
wbuf []byte
|
|
||||||
isServer bool
|
isServer bool
|
||||||
handshaked bool
|
handshaked bool
|
||||||
handshakeMutex sync.Mutex
|
handshakeMutex sync.Mutex
|
||||||
@ -99,19 +96,19 @@ func (c *obfsHTTPConn) Handshake() (err error) {
|
|||||||
|
|
||||||
func (c *obfsHTTPConn) serverHandshake() (err error) {
|
func (c *obfsHTTPConn) serverHandshake() (err error) {
|
||||||
br := bufio.NewReader(c.Conn)
|
br := bufio.NewReader(c.Conn)
|
||||||
c.request, err = http.ReadRequest(br)
|
r, err := http.ReadRequest(br)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if Debug {
|
if Debug {
|
||||||
dump, _ := httputil.DumpRequest(c.request, false)
|
dump, _ := httputil.DumpRequest(r, false)
|
||||||
log.Logf("[ohttp] %s -> %s\n%s", c.Conn.RemoteAddr(), c.Conn.LocalAddr(), string(dump))
|
log.Logf("[ohttp] %s -> %s\n%s", c.Conn.RemoteAddr(), c.Conn.LocalAddr(), string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
if br.Buffered() > 0 {
|
if r.ContentLength > 0 {
|
||||||
c.rbuf, err = br.Peek(br.Buffered())
|
c.buf, err = ioutil.ReadAll(r.Body)
|
||||||
} else {
|
} else {
|
||||||
c.rbuf, err = ioutil.ReadAll(c.request.Body)
|
c.buf, err = br.Peek(br.Buffered())
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -120,13 +117,13 @@ func (c *obfsHTTPConn) serverHandshake() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
b := bytes.Buffer{}
|
b := bytes.Buffer{}
|
||||||
if c.request.Header.Get("Upgrade") == "websocket" {
|
if r.Header.Get("Upgrade") == "websocket" {
|
||||||
b.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
|
b.WriteString("HTTP/1.1 101 Switching Protocols\r\n")
|
||||||
b.WriteString("Server: nginx/1.10.0\r\n")
|
b.WriteString("Server: nginx/1.10.0\r\n")
|
||||||
b.WriteString("Date: " + time.Now().Format(time.RFC1123) + "\r\n")
|
b.WriteString("Date: " + time.Now().Format(time.RFC1123) + "\r\n")
|
||||||
b.WriteString("Connection: Upgrade\r\n")
|
b.WriteString("Connection: Upgrade\r\n")
|
||||||
b.WriteString("Upgrade: websocket\r\n")
|
b.WriteString("Upgrade: websocket\r\n")
|
||||||
b.WriteString(fmt.Sprintf("Sec-WebSocket-Accept: %s\r\n", computeAcceptKey(c.request.Header.Get("Sec-WebSocket-Key"))))
|
b.WriteString(fmt.Sprintf("Sec-WebSocket-Accept: %s\r\n", computeAcceptKey(r.Header.Get("Sec-WebSocket-Key"))))
|
||||||
b.WriteString("\r\n")
|
b.WriteString("\r\n")
|
||||||
} else {
|
} else {
|
||||||
b.WriteString("HTTP/1.1 200 OK\r\n")
|
b.WriteString("HTTP/1.1 200 OK\r\n")
|
||||||
@ -146,24 +143,19 @@ func (c *obfsHTTPConn) serverHandshake() (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *obfsHTTPConn) clientHandshake() (err error) {
|
func (c *obfsHTTPConn) clientHandshake() (err error) {
|
||||||
r := c.request
|
r := &http.Request{
|
||||||
if r == nil {
|
Method: http.MethodGet,
|
||||||
r = &http.Request{
|
ProtoMajor: 1,
|
||||||
Method: http.MethodGet,
|
ProtoMinor: 1,
|
||||||
ProtoMajor: 1,
|
URL: &url.URL{Scheme: "http", Host: c.host},
|
||||||
ProtoMinor: 1,
|
Header: make(http.Header),
|
||||||
URL: &url.URL{Scheme: "http", Host: c.host},
|
|
||||||
Header: make(http.Header),
|
|
||||||
}
|
|
||||||
r.Header.Set("Connection", "keep-alive")
|
|
||||||
r.Header.Set("Upgrade", "websocket")
|
|
||||||
r.Header.Set("User-Agent", DefaultUserAgent)
|
|
||||||
if len(c.wbuf) > 0 {
|
|
||||||
log.Log("write buf", len(c.wbuf))
|
|
||||||
r.Body = ioutil.NopCloser(bytes.NewReader(c.wbuf))
|
|
||||||
r.ContentLength = int64(len(c.wbuf))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
r.Header.Set("User-Agent", "curl/7.49.1")
|
||||||
|
r.Header.Set("Connection", "Upgrade")
|
||||||
|
r.Header.Set("Upgrade", "websocket")
|
||||||
|
key, _ := generateChallengeKey()
|
||||||
|
r.Header.Set("Sec-WebSocket-Key", key)
|
||||||
|
|
||||||
if err = r.Write(c.Conn); err != nil {
|
if err = r.Write(c.Conn); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -182,6 +174,7 @@ func (c *obfsHTTPConn) clientHandshake() (err error) {
|
|||||||
dump, _ := httputil.DumpResponse(resp, false)
|
dump, _ := httputil.DumpResponse(resp, false)
|
||||||
log.Logf("[ohttp] %s <- %s\n%s", c.Conn.LocalAddr(), c.Conn.RemoteAddr(), string(dump))
|
log.Logf("[ohttp] %s <- %s\n%s", c.Conn.LocalAddr(), c.Conn.RemoteAddr(), string(dump))
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,24 +182,18 @@ func (c *obfsHTTPConn) Read(b []byte) (n int, err error) {
|
|||||||
if err = c.Handshake(); err != nil {
|
if err = c.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(c.rbuf) > 0 {
|
if len(c.buf) > 0 {
|
||||||
n = copy(b, c.rbuf)
|
n = copy(b, c.buf)
|
||||||
c.rbuf = c.rbuf[n:]
|
c.buf = c.buf[n:]
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
return c.Conn.Read(b)
|
return c.Conn.Read(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *obfsHTTPConn) Write(b []byte) (n int, err error) {
|
func (c *obfsHTTPConn) Write(b []byte) (n int, err error) {
|
||||||
handshaked := c.handshaked
|
|
||||||
c.wbuf = b
|
|
||||||
if err = c.Handshake(); err != nil {
|
if err = c.Handshake(); err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !handshaked {
|
|
||||||
n = len(c.wbuf)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
return c.Conn.Write(b)
|
return c.Conn.Write(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
371
obfs_test.go
Normal file
371
obfs_test.go
Normal file
@ -0,0 +1,371 @@
|
|||||||
|
package gost
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rand"
|
||||||
|
"fmt"
|
||||||
|
"net/http/httptest"
|
||||||
|
"net/url"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func httpOverObfsHTTPRoundtrip(targetURL string, data []byte,
|
||||||
|
clientInfo *url.Userinfo, serverInfo []*url.Userinfo) error {
|
||||||
|
|
||||||
|
ln, err := ObfsHTTPListener("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: HTTPConnector(clientInfo),
|
||||||
|
Transporter: ObfsHTTPTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: HTTPHandler(
|
||||||
|
UsersHandlerOption(serverInfo...),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
return proxyRoundtrip(client, server, targetURL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestHTTPOverObfsHTTP(t *testing.T) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
for i, tc := range httpProxyTests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
|
||||||
|
err := httpOverObfsHTTPRoundtrip(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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHTTPOverObfsHTTP(b *testing.B) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
ln, err := ObfsHTTPListener("")
|
||||||
|
if err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
}
|
||||||
|
// b.Log(ln.Addr())
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: HTTPConnector(url.UserPassword("admin", "123456")),
|
||||||
|
Transporter: ObfsHTTPTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: HTTPHandler(
|
||||||
|
UsersHandlerOption(url.UserPassword("admin", "123456")),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if err := proxyRoundtrip(client, server, httpSrv.URL, sendData); err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkHTTPOverObfsHTTPParallel(b *testing.B) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
ln, err := ObfsHTTPListener("")
|
||||||
|
if err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: HTTPConnector(url.UserPassword("admin", "123456")),
|
||||||
|
Transporter: ObfsHTTPTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: HTTPHandler(
|
||||||
|
UsersHandlerOption(url.UserPassword("admin", "123456")),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
if err := proxyRoundtrip(client, server, httpSrv.URL, sendData); err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func socks5OverObfsHTTPRoundtrip(targetURL string, data []byte,
|
||||||
|
clientInfo *url.Userinfo, serverInfo []*url.Userinfo) error {
|
||||||
|
|
||||||
|
ln, err := ObfsHTTPListener("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: SOCKS5Connector(clientInfo),
|
||||||
|
Transporter: ObfsHTTPTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: SOCKS5Handler(
|
||||||
|
UsersHandlerOption(serverInfo...),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
return proxyRoundtrip(client, server, targetURL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSOCKS5OverObfsHTTP(t *testing.T) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
for i, tc := range socks5ProxyTests {
|
||||||
|
err := socks5OverObfsHTTPRoundtrip(httpSrv.URL, sendData,
|
||||||
|
tc.cliUser,
|
||||||
|
tc.srvUsers,
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
if !tc.pass {
|
||||||
|
t.Errorf("#%d should failed", i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// t.Logf("#%d %v", i, err)
|
||||||
|
if tc.pass {
|
||||||
|
t.Errorf("#%d got error: %v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func socks4OverObfsHTTPRoundtrip(targetURL string, data []byte) error {
|
||||||
|
ln, err := ObfsHTTPListener("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: SOCKS4Connector(),
|
||||||
|
Transporter: ObfsHTTPTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: SOCKS4Handler(),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
return proxyRoundtrip(client, server, targetURL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSOCKS4OverObfsHTTP(t *testing.T) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
err := socks4OverObfsHTTPRoundtrip(httpSrv.URL, sendData)
|
||||||
|
// t.Logf("#%d %v", i, err)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("got error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func socks4aOverObfsHTTPRoundtrip(targetURL string, data []byte) error {
|
||||||
|
ln, err := ObfsHTTPListener("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: SOCKS4AConnector(),
|
||||||
|
Transporter: ObfsHTTPTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: SOCKS4Handler(),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
return proxyRoundtrip(client, server, targetURL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSOCKS4AOverObfsHTTP(t *testing.T) {
|
||||||
|
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
err := socks4aOverObfsHTTPRoundtrip(httpSrv.URL, sendData)
|
||||||
|
// t.Logf("#%d %v", i, err)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("got error: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ssOverObfsHTTPRoundtrip(targetURL string, data []byte,
|
||||||
|
clientInfo, serverInfo *url.Userinfo) error {
|
||||||
|
|
||||||
|
ln, err := ObfsHTTPListener("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: ShadowConnector(clientInfo),
|
||||||
|
Transporter: ObfsHTTPTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: ShadowHandler(
|
||||||
|
UsersHandlerOption(serverInfo),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
return proxyRoundtrip(client, server, targetURL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSSOverObfsHTTP(t *testing.T) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
for i, tc := range ssProxyTests {
|
||||||
|
err := ssOverObfsHTTPRoundtrip(httpSrv.URL, sendData,
|
||||||
|
tc.clientCipher,
|
||||||
|
tc.serverCipher,
|
||||||
|
)
|
||||||
|
if err == nil {
|
||||||
|
if !tc.pass {
|
||||||
|
t.Errorf("#%d should failed", i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// t.Logf("#%d %v", i, err)
|
||||||
|
if tc.pass {
|
||||||
|
t.Errorf("#%d got error: %v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func sniOverObfsHTTPRoundtrip(targetURL string, data []byte, host string) error {
|
||||||
|
ln, err := ObfsHTTPListener("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := url.Parse(targetURL)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: SNIConnector(host),
|
||||||
|
Transporter: ObfsHTTPTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: SNIHandler(HostHandlerOption(u.Host)),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
return sniRoundtrip(client, server, targetURL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSNIOverObfsHTTP(t *testing.T) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
httpsSrv := httptest.NewTLSServer(httpTestHandler)
|
||||||
|
defer httpsSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
var sniProxyTests = []struct {
|
||||||
|
targetURL string
|
||||||
|
host string
|
||||||
|
pass bool
|
||||||
|
}{
|
||||||
|
{httpSrv.URL, "", true},
|
||||||
|
{httpSrv.URL, "example.com", true},
|
||||||
|
{httpsSrv.URL, "", true},
|
||||||
|
{httpsSrv.URL, "example.com", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tc := range sniProxyTests {
|
||||||
|
tc := tc
|
||||||
|
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
|
||||||
|
err := sniOverObfsHTTPRoundtrip(tc.targetURL, sendData, tc.host)
|
||||||
|
if err == nil {
|
||||||
|
if !tc.pass {
|
||||||
|
t.Errorf("#%d should failed", i)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// t.Logf("#%d %v", i, err)
|
||||||
|
if tc.pass {
|
||||||
|
t.Errorf("#%d got error: %v", i, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
13
ssh.go
13
ssh.go
@ -95,13 +95,15 @@ func (c *sshRemoteForwardConnector) Connect(conn net.Conn, addr string, options
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
log.Log("[ssh-rtcp] listening on", ln.Addr())
|
||||||
|
|
||||||
for {
|
for {
|
||||||
rc, err := ln.Accept()
|
rc, err := ln.Accept()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[ssh-rtcp] %s <-> %s accpet : %s", ln.Addr(), addr, err)
|
log.Logf("[ssh-rtcp] %s <-> %s accpet : %s", ln.Addr(), addr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
// log.Log("[ssh-rtcp] accept", rc.LocalAddr(), rc.RemoteAddr())
|
||||||
select {
|
select {
|
||||||
case cc.session.connChan <- rc:
|
case cc.session.connChan <- rc:
|
||||||
default:
|
default:
|
||||||
@ -593,7 +595,6 @@ func (h *sshForwardHandler) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Reque
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Log("[ssh-rtcp] listening on tcp", addr)
|
|
||||||
ln, err := net.Listen("tcp", addr) //tie to the client connection
|
ln, err := net.Listen("tcp", addr) //tie to the client connection
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Log("[ssh-rtcp]", err)
|
log.Log("[ssh-rtcp]", err)
|
||||||
@ -602,6 +603,8 @@ func (h *sshForwardHandler) tcpipForwardRequest(sshConn ssh.Conn, req *ssh.Reque
|
|||||||
}
|
}
|
||||||
defer ln.Close()
|
defer ln.Close()
|
||||||
|
|
||||||
|
log.Log("[ssh-rtcp] listening on tcp", ln.Addr())
|
||||||
|
|
||||||
replyFunc := func() error {
|
replyFunc := func() error {
|
||||||
if t.Port == 0 && req.WantReply { // Client sent port 0. let them know which port is actually being used
|
if t.Port == 0 && req.WantReply { // Client sent port 0. let them know which port is actually being used
|
||||||
_, port, err := getHostPortFromAddr(ln.Addr())
|
_, port, err := getHostPortFromAddr(ln.Addr())
|
||||||
@ -850,15 +853,15 @@ func (c *sshNopConn) RemoteAddr() net.Addr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *sshNopConn) SetDeadline(t time.Time) error {
|
func (c *sshNopConn) SetDeadline(t time.Time) error {
|
||||||
return &net.OpError{Op: "set", Net: "http2", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
return &net.OpError{Op: "set", Net: "ssh", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *sshNopConn) SetReadDeadline(t time.Time) error {
|
func (c *sshNopConn) SetReadDeadline(t time.Time) error {
|
||||||
return &net.OpError{Op: "set", Net: "http2", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
return &net.OpError{Op: "set", Net: "ssh", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *sshNopConn) SetWriteDeadline(t time.Time) error {
|
func (c *sshNopConn) SetWriteDeadline(t time.Time) error {
|
||||||
return &net.OpError{Op: "set", Net: "http2", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
return &net.OpError{Op: "set", Net: "ssh", Source: nil, Addr: nil, Err: errors.New("deadline not supported")}
|
||||||
}
|
}
|
||||||
|
|
||||||
type sshConn struct {
|
type sshConn struct {
|
||||||
|
170
ssh_test.go
170
ssh_test.go
@ -4,11 +4,181 @@ import (
|
|||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"net"
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func sshDirectForwardRoundtrip(targetURL string, data []byte) error {
|
||||||
|
ln, err := TCPListener("")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: SSHDirectForwardConnector(),
|
||||||
|
Transporter: SSHForwardTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: SSHForwardHandler(),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
return proxyRoundtrip(client, server, targetURL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSSHDirectForward(t *testing.T) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
err := sshDirectForwardRoundtrip(httpSrv.URL, sendData)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSSHDirectForward(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: SSHDirectForwardConnector(),
|
||||||
|
Transporter: SSHForwardTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: SSHForwardHandler(),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
if err := proxyRoundtrip(client, server, httpSrv.URL, sendData); err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSSHDirectForwardParallel(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)
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: SSHDirectForwardConnector(),
|
||||||
|
Transporter: SSHForwardTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: SSHForwardHandler(),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
b.RunParallel(func(pb *testing.PB) {
|
||||||
|
for pb.Next() {
|
||||||
|
if err := proxyRoundtrip(client, server, httpSrv.URL, sendData); err != nil {
|
||||||
|
b.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func sshRemoteForwardRoundtrip(t *testing.T, targetURL string, data []byte) (err error) {
|
||||||
|
ln, err := TCPListener("")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
client := &Client{
|
||||||
|
Connector: SSHRemoteForwardConnector(),
|
||||||
|
Transporter: SSHForwardTransporter(),
|
||||||
|
}
|
||||||
|
|
||||||
|
server := &Server{
|
||||||
|
Listener: ln,
|
||||||
|
Handler: SSHForwardHandler(),
|
||||||
|
}
|
||||||
|
|
||||||
|
go server.Run()
|
||||||
|
defer server.Close()
|
||||||
|
|
||||||
|
conn, err := proxyConn(client, server)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
conn, err = client.Connect(conn, ":0")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
c, err := net.Dial("tcp", conn.LocalAddr().String())
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
u, err := url.Parse(targetURL)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cc, err := net.Dial("tcp", u.Host)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
go transport(conn, cc)
|
||||||
|
|
||||||
|
t.Log("httpRoundtrip")
|
||||||
|
return httpRoundtrip(c, targetURL, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _TestSSHRemoteForward(t *testing.T) {
|
||||||
|
httpSrv := httptest.NewServer(httpTestHandler)
|
||||||
|
defer httpSrv.Close()
|
||||||
|
|
||||||
|
sendData := make([]byte, 128)
|
||||||
|
rand.Read(sendData)
|
||||||
|
|
||||||
|
err := sshRemoteForwardRoundtrip(t, httpSrv.URL, sendData)
|
||||||
|
if err != nil {
|
||||||
|
t.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func httpOverSSHTunnelRoundtrip(targetURL string, data []byte, tlsConfig *tls.Config,
|
func httpOverSSHTunnelRoundtrip(targetURL string, data []byte, tlsConfig *tls.Config,
|
||||||
clientInfo *url.Userinfo, serverInfo []*url.Userinfo) error {
|
clientInfo *url.Userinfo, serverInfo []*url.Userinfo) error {
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user