add tests

This commit is contained in:
ginuerzh 2018-12-08 18:00:08 +08:00
parent d1cad3eb5b
commit 52a8626d4a
7 changed files with 1333 additions and 67 deletions

View File

@ -4,56 +4,56 @@ import (
"bufio" "bufio"
"bytes" "bytes"
"crypto/rand" "crypto/rand"
"crypto/tls"
"errors"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/http/httptest" "net/http/httptest"
"net/url" "net/url"
"testing" "testing"
"time"
) )
var httpTestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { var httpTestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.Copy(w, r.Body) io.Copy(w, r.Body)
}) })
func httpProxyRoundtrip(urlStr string, cliUser *url.Userinfo, srvUsers []*url.Userinfo, body io.Reader) (statusCode int, recv []byte, err error) { func proxyRoundtrip(client *Client, server *Server, targetURL string, data []byte) (err error) {
ln, err := TCPListener("") conn, err := client.Dial(server.Addr().String())
if err != nil {
return
}
h := HTTPHandler(UsersHandlerOption(srvUsers...))
server := &Server{Listener: ln}
go server.Serve(h)
exitChan := make(chan struct{})
defer close(exitChan)
go func() {
defer server.Close()
<-exitChan
}()
client := &Client{
Connector: HTTPConnector(cliUser),
Transporter: TCPTransporter(),
}
conn, err := client.Dial(ln.Addr().String())
if err != nil { if err != nil {
return return
} }
defer conn.Close() defer conn.Close()
conn.SetDeadline(time.Now().Add(1 * time.Second))
conn, err = client.Handshake(conn) conn, err = client.Handshake(conn)
if err != nil { if err != nil {
return return
} }
url, err := url.Parse(urlStr) u, err := url.Parse(targetURL)
if err != nil { if err != nil {
return return
} }
conn, err = client.Connect(conn, url.Host) conn, err = client.Connect(conn, u.Host)
if err != nil { if err != nil {
return return
} }
req, err := http.NewRequest(http.MethodGet, urlStr, body)
if u.Scheme == "https" {
conn = tls.Client(conn,
&tls.Config{
InsecureSkipVerify: true,
})
u.Scheme = "http"
}
req, err := http.NewRequest(
http.MethodGet,
u.String(),
bytes.NewReader(data),
)
if err != nil { if err != nil {
return return
} }
@ -65,63 +65,158 @@ func httpProxyRoundtrip(urlStr string, cliUser *url.Userinfo, srvUsers []*url.Us
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
statusCode = resp.StatusCode
recv, err = ioutil.ReadAll(resp.Body) 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 return
} }
var httpProxyTests = []struct { var httpProxyTests = []struct {
url string
cliUser *url.Userinfo cliUser *url.Userinfo
srvUsers []*url.Userinfo srvUsers []*url.Userinfo
errStr string errStr string
}{ }{
{"", nil, nil, ""}, {nil, nil, ""},
{"", nil, []*url.Userinfo{url.User("admin")}, "407 Proxy Authentication Required"}, {nil, []*url.Userinfo{url.User("admin")}, "407 Proxy Authentication Required"},
{"", nil, []*url.Userinfo{url.UserPassword("", "123456")}, "407 Proxy Authentication Required"}, {nil, []*url.Userinfo{url.UserPassword("", "123456")}, "407 Proxy Authentication Required"},
{"", url.User("admin"), []*url.Userinfo{url.User("test")}, "407 Proxy Authentication Required"}, {url.User("admin"), []*url.Userinfo{url.User("test")}, "407 Proxy Authentication Required"},
{"", url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "123456")}, "407 Proxy Authentication Required"}, {url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "123456")}, "407 Proxy Authentication Required"},
{"", url.User("admin"), []*url.Userinfo{url.User("admin")}, ""}, {url.User("admin"), []*url.Userinfo{url.User("admin")}, ""},
{"", url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "")}, ""}, {url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "")}, ""},
{"", url.UserPassword("admin", "123456"), nil, ""}, {url.UserPassword("admin", "123456"), nil, ""},
{"", url.UserPassword("admin", "123456"), []*url.Userinfo{url.User("admin")}, ""}, {url.UserPassword("admin", "123456"), []*url.Userinfo{url.User("admin")}, ""},
{"", url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, ""}, {url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, ""},
{"", url.UserPassword("", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, ""}, {url.UserPassword("", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, ""},
{"", url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("admin", "123456")}, ""}, {url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("admin", "123456")}, ""},
{"", url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("user", "pass"), url.UserPassword("admin", "123456")}, ""}, {url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("user", "pass"), url.UserPassword("admin", "123456")}, ""},
{"http://:0", nil, nil, "503 Service Unavailable"}, }
func httpProxyRoundtrip(targetURL string, data []byte, clientInfo *url.Userinfo, serverInfo []*url.Userinfo) error {
ln, err := TCPListener("")
if err != nil {
return err
}
client := &Client{
Connector: HTTPConnector(clientInfo),
Transporter: TCPTransporter(),
}
server := &Server{
Listener: ln,
Handler: HTTPHandler(
UsersHandlerOption(serverInfo...),
),
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
} }
func TestHTTPProxy(t *testing.T) { func TestHTTPProxy(t *testing.T) {
Debug = true
httpSrv := httptest.NewServer(httpTestHandler) httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close() defer httpSrv.Close()
for _, test := range httpProxyTests { sendData := make([]byte, 128)
send := make([]byte, 16) rand.Read(sendData)
rand.Read(send)
urlStr := test.url for i, tc := range httpProxyTests {
if urlStr == "" { tc := tc
urlStr = httpSrv.URL t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
} err := httpProxyRoundtrip(httpSrv.URL, sendData, tc.cliUser, tc.srvUsers)
_, recv, err := httpProxyRoundtrip(urlStr, test.cliUser, test.srvUsers, bytes.NewReader(send)) if err == nil {
if err == nil { if tc.errStr != "" {
if test.errStr != "" { t.Errorf("#%d should failed with error %s", i, tc.errStr)
t.Errorf("HTTP proxy response should failed with error %s", test.errStr) }
continue } 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)
}
} }
} else { })
if test.errStr == "" { }
t.Errorf("HTTP proxy got error %v", err) }
}
if err.Error() != test.errStr { func BenchmarkHTTPProxy(b *testing.B) {
t.Errorf("HTTP proxy got error %v, want %v", err, test.errStr) httpSrv := httptest.NewServer(httpTestHandler)
} defer httpSrv.Close()
continue
} sendData := make([]byte, 128)
if !bytes.Equal(send, recv) { rand.Read(sendData)
t.Errorf("got %v, want %v", recv, send)
continue ln, err := TCPListener("")
if err != nil {
b.Error(err)
}
client := &Client{
Connector: HTTPConnector(url.UserPassword("admin", "123456")),
Transporter: TCPTransporter(),
}
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 BenchmarkHTTPProxyParallel(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: HTTPConnector(url.UserPassword("admin", "123456")),
Transporter: TCPTransporter(),
}
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)
}
}
})
}

View File

@ -12,6 +12,7 @@ import (
// Server is a proxy server. // Server is a proxy server.
type Server struct { type Server struct {
Listener Listener Listener Listener
Handler Handler
options *ServerOptions options *ServerOptions
} }
@ -46,6 +47,10 @@ func (s *Server) Serve(h Handler, opts ...ServerOption) error {
} }
s.Listener = ln s.Listener = ln
} }
if h == nil {
h = s.Handler
}
if h == nil { if h == nil {
h = HTTPHandler() h = HTTPHandler()
} }
@ -84,6 +89,11 @@ func (s *Server) Serve(h Handler, opts ...ServerOption) error {
} }
} }
// Run starts to serve.
func (s *Server) Run() error {
return s.Serve(s.Handler)
}
// ServerOptions holds the options for Server. // ServerOptions holds the options for Server.
type ServerOptions struct { type ServerOptions struct {
} }

2
sni.go
View File

@ -93,7 +93,7 @@ func (h *sniHandler) Handle(conn net.Conn) {
host = net.JoinHostPort(host, "443") host = net.JoinHostPort(host, "443")
log.Logf("[ss] %s -> %s -> %s", log.Logf("[sni] %s -> %s -> %s",
conn.RemoteAddr(), h.options.Node.String(), host) conn.RemoteAddr(), h.options.Node.String(), host)
if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) { if !Can("tcp", host, h.options.Whitelist, h.options.Blacklist) {

105
sni_test.go Normal file
View File

@ -0,0 +1,105 @@
package gost
import (
"bufio"
"bytes"
"crypto/rand"
"crypto/tls"
"errors"
"net/http"
"net/http/httptest"
"net/url"
"testing"
"time"
)
func sniRoundtrip(client *Client, server *Server, targetURL string, data []byte) (err error) {
conn, err := client.Dial(server.Addr().String())
if err != nil {
return
}
defer conn.Close()
conn.SetDeadline(time.Now().Add(3 * time.Second))
conn, err = client.Handshake(conn)
if err != nil {
return
}
u, err := url.Parse(targetURL)
if err != nil {
return
}
conn, err = client.Connect(conn, u.Host)
if err != nil {
return
}
if u.Scheme == "https" {
conn = tls.Client(conn,
&tls.Config{
InsecureSkipVerify: false,
ServerName: u.Hostname(),
})
u.Scheme = "http"
}
req, err := http.NewRequest(
http.MethodGet,
u.String(),
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)
}
return
}
func sniProxyRoundtrip(targetURL string, data []byte, host string) error {
ln, err := TCPListener("")
if err != nil {
return err
}
client := &Client{
Connector: SNIConnector(host),
Transporter: TCPTransporter(),
}
server := &Server{
Listener: ln,
Handler: SNIHandler(),
}
go server.Run()
defer server.Close()
return sniRoundtrip(client, server, targetURL, data)
}
func TestSNIProxy(t *testing.T) {
// SetLogger(&LogLogger{})
// Debug = true
httpSrv := httptest.NewTLSServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
err := sniProxyRoundtrip("https://github.com", sendData, "google.com")
if err != nil {
t.Errorf("got error: %v", err)
}
}

371
socks_test.go Normal file
View File

@ -0,0 +1,371 @@
package gost
import (
"crypto/rand"
"crypto/tls"
"fmt"
"net/http/httptest"
"net/url"
"testing"
)
var socks5ProxyTests = []struct {
cliUser *url.Userinfo
srvUsers []*url.Userinfo
pass bool
}{
{nil, nil, true},
{nil, []*url.Userinfo{url.User("admin")}, false},
{nil, []*url.Userinfo{url.UserPassword("", "123456")}, false},
{url.User("admin"), []*url.Userinfo{url.User("test")}, false},
{url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "123456")}, false},
{url.User("admin"), []*url.Userinfo{url.User("admin")}, true},
{url.User("admin"), []*url.Userinfo{url.UserPassword("admin", "")}, true},
{url.UserPassword("admin", "123456"), nil, true},
{url.UserPassword("admin", "123456"), []*url.Userinfo{url.User("admin")}, true},
{url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, true},
{url.UserPassword("", "123456"), []*url.Userinfo{url.UserPassword("", "123456")}, true},
{url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("admin", "123456")}, true},
{url.UserPassword("admin", "123456"), []*url.Userinfo{url.UserPassword("user", "pass"), url.UserPassword("admin", "123456")}, true},
}
func socks5ProxyRoundtrip(targetURL string, data []byte, clientInfo *url.Userinfo, serverInfo []*url.Userinfo) error {
ln, err := TCPListener("")
if err != nil {
return err
}
client := &Client{
Connector: SOCKS5Connector(clientInfo),
Transporter: TCPTransporter(),
}
server := &Server{
Handler: SOCKS5Handler(UsersHandlerOption(serverInfo...)),
Listener: ln,
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestSOCKS5Proxy(t *testing.T) {
cert, err := GenCertificate()
if err != nil {
panic(err)
}
DefaultTLSConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
}
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
for i, tc := range socks5ProxyTests {
tc := tc
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
err := socks5ProxyRoundtrip(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 BenchmarkSOCKS5Proxy(b *testing.B) {
cert, err := GenCertificate()
if err != nil {
panic(err)
}
DefaultTLSConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
}
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: SOCKS5Connector(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 := proxyRoundtrip(client, server, httpSrv.URL, sendData); err != nil {
b.Error(err)
}
}
}
func BenchmarkSOCKS5ProxyParallel(b *testing.B) {
cert, err := GenCertificate()
if err != nil {
panic(err)
}
DefaultTLSConfig = &tls.Config{
Certificates: []tls.Certificate{cert},
}
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: SOCKS5Connector(url.UserPassword("admin", "123456")),
Transporter: TCPTransporter(),
}
server := &Server{
Handler: SOCKS5Handler(UsersHandlerOption(url.UserPassword("admin", "123456"))),
Listener: ln,
}
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 socks4ProxyRoundtrip(targetURL string, data []byte) error {
ln, err := TCPListener("")
if err != nil {
return err
}
client := &Client{
Connector: SOCKS4Connector(),
Transporter: TCPTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS4Handler(),
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestSOCKS4Proxy(t *testing.T) {
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
err := socks4ProxyRoundtrip(httpSrv.URL, sendData)
// t.Logf("#%d %v", i, err)
if err != nil {
t.Errorf("got error: %v", err)
}
}
func BenchmarkSOCKS4Proxy(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: SOCKS4Connector(),
Transporter: TCPTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS4Handler(),
}
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 BenchmarkSOCKS4ProxyParallel(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: SOCKS4Connector(),
Transporter: TCPTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS4Handler(),
}
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 socks4aProxyRoundtrip(targetURL string, data []byte) error {
ln, err := TCPListener("")
if err != nil {
return err
}
client := &Client{
Connector: SOCKS4AConnector(),
Transporter: TCPTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS4Handler(),
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestSOCKS4AProxy(t *testing.T) {
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
err := socks4aProxyRoundtrip(httpSrv.URL, sendData)
// t.Logf("#%d %v", i, err)
if err != nil {
t.Errorf("got error: %v", err)
}
}
func BenchmarkSOCKS4AProxy(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: SOCKS4AConnector(),
Transporter: TCPTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS4Handler(),
}
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 BenchmarkSOCKS4AProxyParallel(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: SOCKS4AConnector(),
Transporter: TCPTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS4Handler(),
}
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)
}
}
})
}

314
ss_test.go Normal file
View File

@ -0,0 +1,314 @@
package gost
import (
"crypto/rand"
"fmt"
"net/http/httptest"
"net/url"
"testing"
)
var ssProxyTests = []struct {
clientCipher *url.Userinfo
serverCipher *url.Userinfo
pass bool
}{
{nil, nil, false},
{&url.Userinfo{}, &url.Userinfo{}, false},
{url.User("abc"), url.User("abc"), false},
{url.UserPassword("abc", "def"), url.UserPassword("abc", "def"), false},
{url.User("aes-128-cfb"), url.User("aes-128-cfb"), false},
{url.User("aes-128-cfb"), url.UserPassword("aes-128-cfb", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.User("aes-128-cfb"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("aes-128-cfb", "abc"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("aes-128-cfb", "123456"), true},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("aes-192-cfb", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("aes-256-cfb", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("aes-128-ctr", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("aes-192-ctr", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("aes-256-ctr", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("des-cfb", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("bf-cfb", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("cast5-cfb", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("rc4-md5", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("chacha20", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("chacha20-ietf", "123456"), false},
{url.UserPassword("aes-128-cfb", "123456"), url.UserPassword("salsa20", "123456"), false},
{url.User("aes-192-cfb"), url.User("aes-192-cfb"), false},
{url.User("aes-192-cfb"), url.UserPassword("aes-192-cfb", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.User("aes-192-cfb"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("aes-192-cfb", "abc"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("aes-192-cfb", "123456"), true},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("aes-128-cfb", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("aes-256-cfb", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("aes-128-ctr", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("aes-192-ctr", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("aes-256-ctr", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("des-cfb", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("bf-cfb", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("cast5-cfb", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("rc4-md5", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("chacha20", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("chacha20-ietf", "123456"), false},
{url.UserPassword("aes-192-cfb", "123456"), url.UserPassword("salsa20", "123456"), false},
{url.User("aes-256-cfb"), url.User("aes-256-cfb"), false},
{url.User("aes-256-cfb"), url.UserPassword("aes-256-cfb", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.User("aes-256-cfb"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("aes-256-cfb", "abc"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("aes-256-cfb", "123456"), true},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("aes-128-cfb", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("aes-192-cfb", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("aes-128-ctr", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("aes-192-ctr", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("aes-256-ctr", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("des-cfb", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("bf-cfb", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("cast5-cfb", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("rc4-md5", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("chacha20", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("chacha20-ietf", "123456"), false},
{url.UserPassword("aes-256-cfb", "123456"), url.UserPassword("salsa20", "123456"), false},
{url.User("aes-128-ctr"), url.User("aes-128-ctr"), false},
{url.User("aes-128-ctr"), url.UserPassword("aes-128-ctr", "123456"), false},
{url.UserPassword("aes-128-ctr", "123456"), url.User("aes-128-ctr"), false},
{url.UserPassword("aes-128-ctr", "123456"), url.UserPassword("aes-128-ctr", "abc"), false},
{url.UserPassword("aes-128-ctr", "123456"), url.UserPassword("aes-128-ctr", "123456"), true},
{url.User("aes-192-ctr"), url.User("aes-192-ctr"), false},
{url.User("aes-192-ctr"), url.UserPassword("aes-192-ctr", "123456"), false},
{url.UserPassword("aes-192-ctr", "123456"), url.User("aes-192-ctr"), false},
{url.UserPassword("aes-192-ctr", "123456"), url.UserPassword("aes-192-ctr", "abc"), false},
{url.UserPassword("aes-192-ctr", "123456"), url.UserPassword("aes-192-ctr", "123456"), true},
{url.User("aes-256-ctr"), url.User("aes-256-ctr"), false},
{url.User("aes-256-ctr"), url.UserPassword("aes-256-ctr", "123456"), false},
{url.UserPassword("aes-256-ctr", "123456"), url.User("aes-256-ctr"), false},
{url.UserPassword("aes-256-ctr", "123456"), url.UserPassword("aes-256-ctr", "abc"), false},
{url.UserPassword("aes-256-ctr", "123456"), url.UserPassword("aes-256-ctr", "123456"), true},
{url.User("des-cfb"), url.User("des-cfb"), false},
{url.User("des-cfb"), url.UserPassword("des-cfb", "123456"), false},
{url.UserPassword("des-cfb", "123456"), url.User("des-cfb"), false},
{url.UserPassword("des-cfb", "123456"), url.UserPassword("des-cfb", "abc"), false},
{url.UserPassword("des-cfb", "123456"), url.UserPassword("des-cfb", "123456"), true},
{url.User("bf-cfb"), url.User("bf-cfb"), false},
{url.User("bf-cfb"), url.UserPassword("bf-cfb", "123456"), false},
{url.UserPassword("bf-cfb", "123456"), url.User("bf-cfb"), false},
{url.UserPassword("bf-cfb", "123456"), url.UserPassword("bf-cfb", "abc"), false},
{url.UserPassword("bf-cfb", "123456"), url.UserPassword("bf-cfb", "123456"), true},
{url.User("cast5-cfb"), url.User("cast5-cfb"), false},
{url.User("cast5-cfb"), url.UserPassword("cast5-cfb", "123456"), false},
{url.UserPassword("cast5-cfb", "123456"), url.User("cast5-cfb"), false},
{url.UserPassword("cast5-cfb", "123456"), url.UserPassword("cast5-cfb", "abc"), false},
{url.UserPassword("cast5-cfb", "123456"), url.UserPassword("cast5-cfb", "123456"), true},
{url.User("rc4-md5"), url.User("rc4-md5"), false},
{url.User("rc4-md5"), url.UserPassword("rc4-md5", "123456"), false},
{url.UserPassword("rc4-md5", "123456"), url.User("rc4-md5"), false},
{url.UserPassword("rc4-md5", "123456"), url.UserPassword("rc4-md5", "abc"), false},
{url.UserPassword("rc4-md5", "123456"), url.UserPassword("rc4-md5", "123456"), true},
{url.User("chacha20"), url.User("chacha20"), false},
{url.User("chacha20"), url.UserPassword("chacha20", "123456"), false},
{url.UserPassword("chacha20", "123456"), url.User("chacha20"), false},
{url.UserPassword("chacha20", "123456"), url.UserPassword("chacha20", "abc"), false},
{url.UserPassword("chacha20", "123456"), url.UserPassword("chacha20", "123456"), true},
{url.User("chacha20-ietf"), url.User("chacha20-ietf"), false},
{url.User("chacha20-ietf"), url.UserPassword("chacha20-ietf", "123456"), false},
{url.UserPassword("chacha20-ietf", "123456"), url.User("chacha20-ietf"), false},
{url.UserPassword("chacha20-ietf", "123456"), url.UserPassword("chacha20-ietf", "abc"), false},
{url.UserPassword("chacha20-ietf", "123456"), url.UserPassword("chacha20-ietf", "123456"), true},
{url.User("salsa20"), url.User("salsa20"), false},
{url.User("salsa20"), url.UserPassword("salsa20", "123456"), false},
{url.UserPassword("salsa20", "123456"), url.User("salsa20"), false},
{url.UserPassword("salsa20", "123456"), url.UserPassword("salsa20", "abc"), false},
{url.UserPassword("salsa20", "123456"), url.UserPassword("salsa20", "123456"), true},
}
func ssProxyRoundtrip(targetURL string, data []byte, clientInfo *url.Userinfo, serverInfo *url.Userinfo) error {
ln, err := TCPListener("")
if err != nil {
return err
}
client := &Client{
Connector: ShadowConnector(clientInfo),
Transporter: TCPTransporter(),
}
server := &Server{
Handler: ShadowHandler(UsersHandlerOption(serverInfo)),
Listener: ln,
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestSSProxy(t *testing.T) {
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
for i, tc := range ssProxyTests {
tc := tc
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
err := ssProxyRoundtrip(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 BenchmarkSSProxy_AES256(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: ShadowConnector(url.UserPassword("aes-256-cfb", "123456")),
Transporter: TCPTransporter(),
}
server := &Server{
Handler: ShadowHandler(UsersHandlerOption(url.UserPassword("aes-256-cfb", "123456"))),
Listener: ln,
}
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 BenchmarkSSProxy_Chacha20(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: ShadowConnector(url.UserPassword("chacha20", "123456")),
Transporter: TCPTransporter(),
}
server := &Server{
Handler: ShadowHandler(UsersHandlerOption(url.UserPassword("chacha20", "123456"))),
Listener: ln,
}
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 BenchmarkSSProxy_Chacha20_ietf(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: ShadowConnector(url.UserPassword("chacha20-ietf", "123456")),
Transporter: TCPTransporter(),
}
server := &Server{
Handler: ShadowHandler(UsersHandlerOption(url.UserPassword("chacha20-ietf", "123456"))),
Listener: ln,
}
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 BenchmarkSSProxyParallel(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: ShadowConnector(url.UserPassword("chacha20-ietf", "123456")),
Transporter: TCPTransporter(),
}
server := &Server{
Handler: ShadowHandler(UsersHandlerOption(url.UserPassword("chacha20-ietf", "123456"))),
Listener: ln,
}
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)
}
}
})
}

371
tls_test.go Normal file
View File

@ -0,0 +1,371 @@
package gost
import (
"crypto/rand"
"crypto/tls"
"fmt"
"net/http/httptest"
"net/url"
"testing"
)
func httpOverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls.Config,
clientInfo *url.Userinfo, serverInfo []*url.Userinfo) error {
ln, err := TLSListener("", tlsConfig)
if err != nil {
return err
}
client := &Client{
Connector: HTTPConnector(clientInfo),
Transporter: TLSTransporter(),
}
server := &Server{
Listener: ln,
Handler: HTTPHandler(
UsersHandlerOption(serverInfo...),
),
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestHTTPOverTLS(t *testing.T) {
cert, err := GenCertificate()
if err != nil {
t.Error(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
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 := httpOverTLSRoundtrip(httpSrv.URL, sendData, tlsConfig, 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 BenchmarkHTTPOverTLS(b *testing.B) {
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
cert, err := GenCertificate()
if err != nil {
b.Error(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
ln, err := TLSListener("", tlsConfig)
if err != nil {
b.Error(err)
}
client := &Client{
Connector: HTTPConnector(url.UserPassword("admin", "123456")),
Transporter: TLSTransporter(),
}
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 BenchmarkHTTPOverTLSParallel(b *testing.B) {
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
cert, err := GenCertificate()
if err != nil {
b.Error(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
ln, err := TLSListener("", tlsConfig)
if err != nil {
b.Error(err)
}
client := &Client{
Connector: HTTPConnector(url.UserPassword("admin", "123456")),
Transporter: TLSTransporter(),
}
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 socks5OverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls.Config,
clientInfo *url.Userinfo, serverInfo []*url.Userinfo) error {
ln, err := TLSListener("", tlsConfig)
if err != nil {
return err
}
client := &Client{
Connector: SOCKS5Connector(clientInfo),
Transporter: TLSTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS5Handler(
UsersHandlerOption(serverInfo...),
),
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestSOCKS5OverTLS(t *testing.T) {
cert, err := GenCertificate()
if err != nil {
t.Error(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
DefaultTLSConfig = tlsConfig
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
for i, tc := range socks5ProxyTests {
tc := tc
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
err := socks5OverTLSRoundtrip(httpSrv.URL, sendData,
tlsConfig,
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 socks4OverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls.Config) error {
ln, err := TLSListener("", tlsConfig)
if err != nil {
return err
}
client := &Client{
Connector: SOCKS4Connector(),
Transporter: TLSTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS4Handler(),
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestSOCKS4OverTLS(t *testing.T) {
cert, err := GenCertificate()
if err != nil {
t.Error(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
err = socks4OverTLSRoundtrip(httpSrv.URL, sendData, tlsConfig)
// t.Logf("#%d %v", i, err)
if err != nil {
t.Errorf("got error: %v", err)
}
}
func socks4aOverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls.Config) error {
ln, err := TLSListener("", tlsConfig)
if err != nil {
return err
}
client := &Client{
Connector: SOCKS4AConnector(),
Transporter: TLSTransporter(),
}
server := &Server{
Listener: ln,
Handler: SOCKS4Handler(),
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestSOCKS4AOverTLS(t *testing.T) {
cert, err := GenCertificate()
if err != nil {
t.Error(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
err = socks4aOverTLSRoundtrip(httpSrv.URL, sendData, tlsConfig)
// t.Logf("#%d %v", i, err)
if err != nil {
t.Errorf("got error: %v", err)
}
}
func ssOverTLSRoundtrip(targetURL string, data []byte, tlsConfig *tls.Config,
clientInfo, serverInfo *url.Userinfo) error {
ln, err := TLSListener("", tlsConfig)
if err != nil {
return err
}
client := &Client{
Connector: ShadowConnector(clientInfo),
Transporter: TLSTransporter(),
}
server := &Server{
Listener: ln,
Handler: ShadowHandler(
UsersHandlerOption(serverInfo),
),
}
go server.Run()
defer server.Close()
return proxyRoundtrip(client, server, targetURL, data)
}
func TestSSOverTLS(t *testing.T) {
cert, err := GenCertificate()
if err != nil {
t.Error(err)
}
tlsConfig := &tls.Config{
Certificates: []tls.Certificate{cert},
}
DefaultTLSConfig = tlsConfig
httpSrv := httptest.NewServer(httpTestHandler)
defer httpSrv.Close()
sendData := make([]byte, 128)
rand.Read(sendData)
for i, tc := range ssProxyTests {
tc := tc
t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
err := ssOverTLSRoundtrip(httpSrv.URL, sendData,
tlsConfig,
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)
}
}
})
}
}