mirror of https://github.com/ginuerzh/gost
14 changed files with 1065 additions and 71 deletions
@ -0,0 +1,121 @@ |
|||||
|
package gost |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"crypto/tls" |
||||
|
"fmt" |
||||
|
"io" |
||||
|
"net" |
||||
|
"net/http" |
||||
|
"sync" |
||||
|
) |
||||
|
|
||||
|
func init() { |
||||
|
// SetLogger(&LogLogger{})
|
||||
|
// Debug = true
|
||||
|
|
||||
|
cert, err := GenCertificate() |
||||
|
if err != nil { |
||||
|
panic(err) |
||||
|
} |
||||
|
DefaultTLSConfig = &tls.Config{ |
||||
|
Certificates: []tls.Certificate{cert}, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var ( |
||||
|
httpTestHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { |
||||
|
io.Copy(w, r.Body) |
||||
|
}) |
||||
|
|
||||
|
udpTestHandler = udpHandlerFunc(func(w io.Writer, r *udpRequest) { |
||||
|
io.Copy(w, r.Body) |
||||
|
}) |
||||
|
) |
||||
|
|
||||
|
type udpRequest struct { |
||||
|
Body io.Reader |
||||
|
RemoteAddr string |
||||
|
} |
||||
|
|
||||
|
type udpResponseWriter struct { |
||||
|
conn net.PacketConn |
||||
|
addr net.Addr |
||||
|
} |
||||
|
|
||||
|
func (w *udpResponseWriter) Write(p []byte) (int, error) { |
||||
|
return w.conn.WriteTo(p, w.addr) |
||||
|
} |
||||
|
|
||||
|
type udpHandlerFunc func(w io.Writer, r *udpRequest) |
||||
|
|
||||
|
// udpTestServer is a UDP server for test.
|
||||
|
type udpTestServer struct { |
||||
|
ln net.PacketConn |
||||
|
handler udpHandlerFunc |
||||
|
wg sync.WaitGroup |
||||
|
mu sync.Mutex // guards closed and conns
|
||||
|
closed bool |
||||
|
} |
||||
|
|
||||
|
func newUDPTestServer(handler udpHandlerFunc) *udpTestServer { |
||||
|
laddr, _ := net.ResolveUDPAddr("udp", "127.0.0.1:0") |
||||
|
ln, err := net.ListenUDP("udp", laddr) |
||||
|
if err != nil { |
||||
|
panic(fmt.Sprintf("udptest: failed to listen on a port: %v", err)) |
||||
|
} |
||||
|
return &udpTestServer{ |
||||
|
ln: ln, |
||||
|
handler: handler, |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *udpTestServer) Start() { |
||||
|
go s.serve() |
||||
|
} |
||||
|
|
||||
|
func (s *udpTestServer) serve() { |
||||
|
for { |
||||
|
data := make([]byte, 1024) |
||||
|
n, raddr, err := s.ln.ReadFrom(data) |
||||
|
if err != nil { |
||||
|
return |
||||
|
} |
||||
|
if s.handler != nil { |
||||
|
s.wg.Add(1) |
||||
|
go func() { |
||||
|
defer s.wg.Done() |
||||
|
w := &udpResponseWriter{ |
||||
|
conn: s.ln, |
||||
|
addr: raddr, |
||||
|
} |
||||
|
r := &udpRequest{ |
||||
|
Body: bytes.NewReader(data[:n]), |
||||
|
RemoteAddr: raddr.String(), |
||||
|
} |
||||
|
s.handler(w, r) |
||||
|
}() |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func (s *udpTestServer) Addr() string { |
||||
|
return s.ln.LocalAddr().String() |
||||
|
} |
||||
|
|
||||
|
func (s *udpTestServer) Close() error { |
||||
|
s.mu.Lock() |
||||
|
|
||||
|
if s.closed { |
||||
|
s.mu.Unlock() |
||||
|
return nil |
||||
|
} |
||||
|
|
||||
|
err := s.ln.Close() |
||||
|
s.closed = true |
||||
|
s.mu.Unlock() |
||||
|
|
||||
|
s.wg.Wait() |
||||
|
|
||||
|
return err |
||||
|
} |
||||
@ -0,0 +1,333 @@ |
|||||
|
package gost |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"crypto/rand" |
||||
|
"fmt" |
||||
|
"net/http/httptest" |
||||
|
"net/url" |
||||
|
"testing" |
||||
|
"time" |
||||
|
) |
||||
|
|
||||
|
func tcpDirectForwardRoundtrip(targetURL string, data []byte) error { |
||||
|
ln, err := TCPListener("") |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
u, err := url.Parse(targetURL) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
client := &Client{ |
||||
|
Connector: ForwardConnector(), |
||||
|
Transporter: TCPTransporter(), |
||||
|
} |
||||
|
|
||||
|
server := &Server{ |
||||
|
Listener: ln, |
||||
|
Handler: TCPDirectForwardHandler(u.Host), |
||||
|
} |
||||
|
|
||||
|
go server.Run() |
||||
|
defer server.Close() |
||||
|
|
||||
|
return proxyRoundtrip(client, server, targetURL, data) |
||||
|
} |
||||
|
|
||||
|
func TestTCPDirectForward(t *testing.T) { |
||||
|
httpSrv := httptest.NewServer(httpTestHandler) |
||||
|
defer httpSrv.Close() |
||||
|
|
||||
|
sendData := make([]byte, 128) |
||||
|
rand.Read(sendData) |
||||
|
|
||||
|
err := tcpDirectForwardRoundtrip(httpSrv.URL, sendData) |
||||
|
if err != nil { |
||||
|
t.Error(err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func BenchmarkTCPDirectForward(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: ForwardConnector(), |
||||
|
Transporter: TCPTransporter(), |
||||
|
} |
||||
|
|
||||
|
u, err := url.Parse(httpSrv.URL) |
||||
|
if err != nil { |
||||
|
b.Error(err) |
||||
|
} |
||||
|
server := &Server{ |
||||
|
Listener: ln, |
||||
|
Handler: TCPDirectForwardHandler(u.Host), |
||||
|
} |
||||
|
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 BenchmarkTCPDirectForwardParallel(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: ForwardConnector(), |
||||
|
Transporter: TCPTransporter(), |
||||
|
} |
||||
|
|
||||
|
u, err := url.Parse(httpSrv.URL) |
||||
|
if err != nil { |
||||
|
b.Error(err) |
||||
|
} |
||||
|
server := &Server{ |
||||
|
Listener: ln, |
||||
|
Handler: TCPDirectForwardHandler(u.Host), |
||||
|
} |
||||
|
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 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 { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
client := &Client{ |
||||
|
Connector: ForwardConnector(), |
||||
|
Transporter: UDPTransporter(), |
||||
|
} |
||||
|
|
||||
|
server := &Server{ |
||||
|
Listener: ln, |
||||
|
Handler: UDPDirectForwardHandler(host), |
||||
|
} |
||||
|
|
||||
|
go server.Run() |
||||
|
defer server.Close() |
||||
|
|
||||
|
return udpRoundtrip(client, server, host, data) |
||||
|
} |
||||
|
|
||||
|
func TestUDPDirectForward(t *testing.T) { |
||||
|
udpSrv := newUDPTestServer(udpTestHandler) |
||||
|
udpSrv.Start() |
||||
|
defer udpSrv.Close() |
||||
|
|
||||
|
sendData := make([]byte, 128) |
||||
|
rand.Read(sendData) |
||||
|
err := udpDirectForwardRoundtrip(udpSrv.Addr(), sendData) |
||||
|
if err != nil { |
||||
|
t.Error(err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func BenchmarkUDPDirectForward(b *testing.B) { |
||||
|
udpSrv := newUDPTestServer(udpTestHandler) |
||||
|
udpSrv.Start() |
||||
|
defer udpSrv.Close() |
||||
|
|
||||
|
sendData := make([]byte, 128) |
||||
|
rand.Read(sendData) |
||||
|
|
||||
|
ln, err := UDPDirectForwardListener("localhost:0", 0) |
||||
|
if err != nil { |
||||
|
b.Error(err) |
||||
|
} |
||||
|
|
||||
|
client := &Client{ |
||||
|
Connector: ForwardConnector(), |
||||
|
Transporter: UDPTransporter(), |
||||
|
} |
||||
|
|
||||
|
server := &Server{ |
||||
|
Listener: ln, |
||||
|
Handler: UDPDirectForwardHandler(udpSrv.Addr()), |
||||
|
} |
||||
|
|
||||
|
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 BenchmarkUDPDirectForwardParallel(b *testing.B) { |
||||
|
udpSrv := newUDPTestServer(udpTestHandler) |
||||
|
udpSrv.Start() |
||||
|
defer udpSrv.Close() |
||||
|
|
||||
|
sendData := make([]byte, 128) |
||||
|
rand.Read(sendData) |
||||
|
|
||||
|
ln, err := UDPDirectForwardListener("localhost:0", 0) |
||||
|
if err != nil { |
||||
|
b.Error(err) |
||||
|
} |
||||
|
|
||||
|
client := &Client{ |
||||
|
Connector: ForwardConnector(), |
||||
|
Transporter: UDPTransporter(), |
||||
|
} |
||||
|
|
||||
|
server := &Server{ |
||||
|
Listener: ln, |
||||
|
Handler: UDPDirectForwardHandler(udpSrv.Addr()), |
||||
|
} |
||||
|
|
||||
|
go server.Run() |
||||
|
defer server.Close() |
||||
|
|
||||
|
b.RunParallel(func(pb *testing.PB) { |
||||
|
for pb.Next() { |
||||
|
if err := udpRoundtrip(client, server, udpSrv.Addr(), sendData); err != nil { |
||||
|
b.Error(err) |
||||
|
} |
||||
|
} |
||||
|
}) |
||||
|
} |
||||
|
|
||||
|
func tcpRemoteForwardRoundtrip(t *testing.T, targetURL string, data []byte) error { |
||||
|
ln, err := TCPRemoteForwardListener("localhost:0", nil) // listening on localhost
|
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
u, err := url.Parse(targetURL) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
client := &Client{ |
||||
|
Connector: ForwardConnector(), |
||||
|
Transporter: TCPTransporter(), |
||||
|
} |
||||
|
|
||||
|
server := &Server{ |
||||
|
Listener: ln, |
||||
|
Handler: TCPRemoteForwardHandler(u.Host), // forward to u.Host
|
||||
|
} |
||||
|
|
||||
|
go server.Run() |
||||
|
defer server.Close() |
||||
|
|
||||
|
return proxyRoundtrip(client, server, targetURL, data) |
||||
|
} |
||||
|
|
||||
|
func TestTCPRemoteForward(t *testing.T) { |
||||
|
httpSrv := httptest.NewServer(httpTestHandler) |
||||
|
defer httpSrv.Close() |
||||
|
|
||||
|
sendData := make([]byte, 128) |
||||
|
rand.Read(sendData) |
||||
|
|
||||
|
err := tcpRemoteForwardRoundtrip(t, httpSrv.URL, sendData) |
||||
|
if err != nil { |
||||
|
t.Error(err) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
func udpRemoteForwardRoundtrip(t *testing.T, host string, data []byte) error { |
||||
|
ln, err := UDPRemoteForwardListener("localhost:0", nil, 0) |
||||
|
if err != nil { |
||||
|
return err |
||||
|
} |
||||
|
|
||||
|
client := &Client{ |
||||
|
Connector: ForwardConnector(), |
||||
|
Transporter: UDPTransporter(), |
||||
|
} |
||||
|
|
||||
|
server := &Server{ |
||||
|
Listener: ln, |
||||
|
Handler: UDPRemoteForwardHandler(host), |
||||
|
} |
||||
|
|
||||
|
go server.Run() |
||||
|
defer server.Close() |
||||
|
|
||||
|
return udpRoundtrip(client, server, host, data) |
||||
|
} |
||||
|
|
||||
|
func TestUDPRemoteForward(t *testing.T) { |
||||
|
udpSrv := newUDPTestServer(udpTestHandler) |
||||
|
udpSrv.Start() |
||||
|
defer udpSrv.Close() |
||||
|
|
||||
|
sendData := make([]byte, 128) |
||||
|
rand.Read(sendData) |
||||
|
|
||||
|
err := udpRemoteForwardRoundtrip(t, udpSrv.Addr(), sendData) |
||||
|
if err != nil { |
||||
|
t.Error(err) |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue