diff --git a/gost/chain.go b/gost/chain.go index 4ceb822..8d6b6e2 100644 --- a/gost/chain.go +++ b/gost/chain.go @@ -38,13 +38,16 @@ func (c *Chain) LastNode() Node { // AddNode appends the node(s) to the chain. func (c *Chain) AddNode(nodes ...Node) { + if c == nil { + return + } c.nodes = append(c.nodes, nodes...) } // IsEmpty checks if the chain is empty. // An empty chain means that there is no proxy node in the chain. func (c *Chain) IsEmpty() bool { - return len(c.nodes) == 0 + return c == nil || len(c.nodes) == 0 } // Dial connects to the target address addr through the chain. diff --git a/gost/client.go b/gost/client.go index fc911f2..abc7867 100644 --- a/gost/client.go +++ b/gost/client.go @@ -26,14 +26,12 @@ func (c *Client) Dial(addr string) (net.Conn, error) { return c.Transporter.Dial(addr) } -// Handshake performs a handshake with the proxy. -// The conn should be an connection to this proxy. +// Handshake performs a handshake with the proxy over connection conn. func (c *Client) Handshake(conn net.Conn) (net.Conn, error) { return c.Transporter.Handshake(conn) } -// Connect connects to the address addr via the proxy. -// The conn should be an connection to this proxy. +// Connect connects to the address addr via the proxy over connection conn. func (c *Client) Connect(conn net.Conn, addr string) (net.Conn, error) { return c.Connector.Connect(conn, addr) } diff --git a/gost/forward.go b/gost/forward.go new file mode 100644 index 0000000..fc8ce0a --- /dev/null +++ b/gost/forward.go @@ -0,0 +1,419 @@ +package gost + +import ( + "crypto/tls" + "errors" + "net" + "time" + + "fmt" + + "github.com/ginuerzh/gosocks5" + "github.com/go-log/log" +) + +type tcpForwardHandler struct { + raddr string + options *HandlerOptions +} + +// TCPForwardHandler creates a server Handler for TCP port forwarding server. +// The raddr is the remote address that the server will forward to. +func TCPForwardHandler(raddr string, opts ...HandlerOption) Handler { + h := &tcpForwardHandler{ + raddr: raddr, + options: &HandlerOptions{ + Chain: new(Chain), + }, + } + for _, opt := range opts { + opt(h.options) + } + return h +} + +func (h *tcpForwardHandler) Handle(conn net.Conn) { + defer conn.Close() + + log.Logf("[tcp] %s - %s", conn.RemoteAddr(), h.raddr) + cc, err := h.options.Chain.Dial(h.raddr) + if err != nil { + log.Logf("[tcp] %s -> %s : %s", conn.RemoteAddr(), h.raddr, err) + return + } + defer cc.Close() + + log.Logf("[tcp] %s <-> %s", conn.RemoteAddr(), h.raddr) + transport(conn, cc) + log.Logf("[tcp] %s >-< %s", conn.RemoteAddr(), h.raddr) +} + +type udpForwardHandler struct { + raddr string + ttl time.Duration + options *HandlerOptions +} + +// UDPForwardHandler creates a server Handler for UDP port forwarding server. +// The raddr is the remote address that the server will forward to. +func UDPForwardHandler(raddr string, ttl time.Duration, opts ...HandlerOption) Handler { + h := &udpForwardHandler{ + raddr: raddr, + ttl: ttl, + options: &HandlerOptions{ + Chain: new(Chain), + }, + } + for _, opt := range opts { + opt(h.options) + } + return h +} + +func (h *udpForwardHandler) Handle(conn net.Conn) { + defer conn.Close() +} + +type rtcpForwardHandler struct { + laddr string + raddr string + options *HandlerOptions +} + +// RTCPForwardHandler creates a server Handler for TCP remote port forwarding server. +// The raddr is the remote address that the server will forward to. +func RTCPForwardHandler(laddr, raddr string, opts ...HandlerOption) Handler { + h := &rtcpForwardHandler{ + laddr: laddr, + raddr: raddr, + options: &HandlerOptions{}, + } + for _, opt := range opts { + opt(h.options) + } + return h +} + +func (h *rtcpForwardHandler) Handle(conn net.Conn) { + defer conn.Close() + + cc, err := net.DialTimeout("tcp", h.raddr, DialTimeout) + if err != nil { + log.Logf("[rtcp] %s -> %s : %s", h.laddr, h.raddr, err) + return + } + defer cc.Close() + + log.Logf("[rtcp] %s <-> %s", h.laddr, h.raddr) + transport(cc, conn) + log.Logf("[rtcp] %s >-< %s", h.laddr, h.raddr) +} + +type rudpForwardHandler struct { + laddr string + raddr string + options *HandlerOptions +} + +// RUDPForwardHandler creates a server Handler for UDP remote port forwarding server. +// The raddr is the remote address that the server will forward to. +func RUDPForwardHandler(laddr, raddr string, opts ...HandlerOption) Handler { + h := &rudpForwardHandler{ + laddr: laddr, + raddr: raddr, + options: &HandlerOptions{}, + } + for _, opt := range opts { + opt(h.options) + } + return h +} + +func (h *rudpForwardHandler) Handle(conn net.Conn) { + defer conn.Close() + + // TODO: handle connection + + /* + ra, err := net.ResolveUDPAddr("udp", h.raddr) + if err != nil { + log.Logf("[rudp] %s - %s : %s", h.laddr, h.raddr, err) + return + } + + for { + dgram, err := gosocks5.ReadUDPDatagram(conn) + if err != nil { + log.Logf("[rudp] %s -> %s : %s", h.laddr, h.raddr, err) + return + } + + go func() { + b := make([]byte, mediumBufferSize) + + relay, err := net.DialUDP("udp", nil, ra) + if err != nil { + log.Logf("[rudp] %s -> %s : %s", h.laddr, h.raddr, err) + return + } + defer relay.Close() + + if _, err := relay.Write(dgram.Data); err != nil { + log.Logf("[rudp] %s -> %s : %s", h.laddr, h.raddr, err) + return + } + if Debug { + log.Logf("[rudp] %s >>> %s length: %d", h.laddr, h.raddr, len(dgram.Data)) + } + relay.SetReadDeadline(time.Now().Add(ReadTimeout)) + n, err := relay.Read(b) + if err != nil { + log.Logf("[rudp] %s <- %s : %s", h.laddr, h.raddr, err) + return + } + relay.SetReadDeadline(time.Time{}) + if Debug { + log.Logf("[rudp] %s <<< %s length: %d", h.laddr, h.raddr, n) + } + conn.SetWriteDeadline(time.Now().Add(WriteTimeout)) + if err := gosocks5.NewUDPDatagram(gosocks5.NewUDPHeader(uint16(n), 0, dgram.Header.Addr), b[:n]).Write(conn); err != nil { + log.Logf("[rudp] %s <- %s : %s", h.laddr, h.raddr, err) + return + } + conn.SetWriteDeadline(time.Time{}) + }() + } + */ +} + +type udpForwardListener struct { + addr *net.UDPAddr + conn *net.UDPConn +} + +// UDPForwardListener creates a Listener for UDP port forwarding server. +func UDPForwardListener(addr string) (Listener, error) { + laddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + return nil, err + } + conn, err := net.ListenUDP("udp", laddr) + if err != nil { + return nil, err + } + return &udpForwardListener{conn: conn}, nil +} + +func (l *udpForwardListener) Accept() (net.Conn, error) { + // TODO: create udp forward connection + return nil, nil +} + +func (l *udpForwardListener) Addr() net.Addr { + return l.addr +} + +func (l *udpForwardListener) Close() error { + return l.conn.Close() +} + +type rtcpForwardListener struct { + addr net.Addr + chain *Chain + selector *clientSelector + close chan struct{} +} + +// RTCPForwardListener creates a Listener for TCP remote port forwarding server. +func RTCPForwardListener(addr string, chain *Chain) (Listener, error) { + laddr, err := net.ResolveTCPAddr("tcp", addr) + if err != nil { + return nil, err + } + if chain.IsEmpty() || chain.LastNode().Protocol != "socks5" { + return nil, errors.New("invalid chain") + } + selector := &clientSelector{ + TLSConfig: &tls.Config{InsecureSkipVerify: true}, + User: chain.LastNode().User, + } + selector.AddMethod( + gosocks5.MethodNoAuth, + gosocks5.MethodUserPass, + MethodTLS, + ) + + return &rtcpForwardListener{ + addr: laddr, + chain: chain, + selector: selector, + close: make(chan struct{}), + }, nil +} + +func (l *rtcpForwardListener) Accept() (net.Conn, error) { + select { + case <-l.close: + return nil, errors.New("closed") + default: + } + + if l.chain.IsEmpty() || l.chain.LastNode().Protocol != "socks5" { + return nil, errors.New("invalid chain") + } + + conn, err := l.chain.Conn() + if err != nil { + return nil, err + } + cc, err := l.handshake(conn) + if err != nil { + conn.Close() + return nil, err + } + + return cc, nil +} + +func (l *rtcpForwardListener) handshake(conn net.Conn) (net.Conn, error) { + cc := gosocks5.ClientConn(conn, l.selector) + if err := cc.Handleshake(); err != nil { + return nil, err + } + conn = cc + + req := gosocks5.NewRequest(gosocks5.CmdBind, toSocksAddr(l.addr)) + if err := req.Write(conn); err != nil { + log.Log("[rtcp] SOCKS5 BIND request: ", err) + return nil, err + } + + // first reply, bind status + conn.SetReadDeadline(time.Now().Add(ReadTimeout)) + rep, err := gosocks5.ReadReply(conn) + if err != nil { + log.Log("[rtcp] SOCKS5 BIND reply: ", err) + return nil, err + } + conn.SetReadDeadline(time.Time{}) + if rep.Rep != gosocks5.Succeeded { + log.Logf("[rtcp] bind on %s failure", l.addr) + return nil, fmt.Errorf("Bind on %s failure", l.addr.String()) + } + log.Logf("[rtcp] BIND ON %s OK", rep.Addr) + + // second reply, peer connected + rep, err = gosocks5.ReadReply(conn) + if err != nil { + log.Log("[rtcp]", err) + return nil, err + } + if rep.Rep != gosocks5.Succeeded { + log.Logf("[rtcp] peer connect failure: %d", rep.Rep) + return nil, errors.New("peer connect failure") + } + + log.Logf("[rtcp] PEER %s CONNECTED", rep.Addr) + return conn, nil +} + +func (l *rtcpForwardListener) Addr() net.Addr { + return l.addr +} + +func (l *rtcpForwardListener) Close() error { + close(l.close) + return nil +} + +type rudpForwardListener struct { + addr net.Addr + chain *Chain + selector *clientSelector + close chan struct{} +} + +// RUDPForwardListener creates a Listener for UDP remote port forwarding server. +func RUDPForwardListener(addr string, chain *Chain) (Listener, error) { + laddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + return nil, err + } + if chain.IsEmpty() || chain.LastNode().Protocol != "socks5" { + return nil, errors.New("invalid chain") + } + selector := &clientSelector{ + TLSConfig: &tls.Config{InsecureSkipVerify: true}, + User: chain.LastNode().User, + } + selector.AddMethod( + gosocks5.MethodNoAuth, + gosocks5.MethodUserPass, + MethodTLS, + ) + + return &rudpForwardListener{ + addr: laddr, + chain: chain, + selector: selector, + close: make(chan struct{}), + }, nil +} + +func (l *rudpForwardListener) Accept() (net.Conn, error) { + select { + case <-l.close: + return nil, errors.New("closed") + default: + } + + conn, err := l.chain.Conn() + if err != nil { + return nil, err + } + cc, err := l.handshake(conn) + if err != nil { + conn.Close() + return nil, err + } + conn = cc + + return cc, nil +} + +func (l *rudpForwardListener) handshake(conn net.Conn) (net.Conn, error) { + cc := gosocks5.ClientConn(conn, l.selector) + if err := cc.Handleshake(); err != nil { + return nil, err + } + conn = cc + + req := gosocks5.NewRequest(CmdUDPTun, toSocksAddr(l.addr)) + if err := req.Write(conn); err != nil { + log.Log("[rudp] SOCKS5 UDP relay request: ", err) + return nil, err + } + + conn.SetReadDeadline(time.Now().Add(ReadTimeout)) + rep, err := gosocks5.ReadReply(conn) + if err != nil { + log.Log("[rudp] SOCKS5 UDP relay reply: ", err) + return nil, err + } + conn.SetReadDeadline(time.Time{}) + if rep.Rep != gosocks5.Succeeded { + log.Logf("[rudp] bind on %s failure: %d", l.addr, rep.Rep) + return nil, fmt.Errorf("Bind on %s failure", l.addr.String()) + } + log.Logf("[rudp] BIND ON %s OK", rep.Addr) + return conn, nil +} + +func (l *rudpForwardListener) Addr() net.Addr { + return l.addr +} + +func (l *rudpForwardListener) Close() error { + close(l.close) + return nil +} diff --git a/gost/gost.go b/gost/gost.go index d2e3f3f..373b5f2 100644 --- a/gost/gost.go +++ b/gost/gost.go @@ -25,9 +25,9 @@ var ( // DialTimeout is the timeout of dial. DialTimeout = 30 * time.Second // ReadTimeout is the timeout for reading. - ReadTimeout = 90 * time.Second + ReadTimeout = 30 * time.Second // WriteTimeout is the timeout for writing. - WriteTimeout = 90 * time.Second + WriteTimeout = 60 * time.Second // default udp node TTL in second for udp port forwarding. defaultTTL = 60 ) diff --git a/gost/http.go b/gost/http.go index 63f2d82..7fc76a2 100644 --- a/gost/http.go +++ b/gost/http.go @@ -87,6 +87,8 @@ func HTTPHandler(opts ...HandlerOption) Handler { } func (h *httpHandler) Handle(conn net.Conn) { + defer conn.Close() + req, err := http.ReadRequest(bufio.NewReader(conn)) if err != nil { log.Log("[http]", err) diff --git a/gost/kcp.go b/gost/kcp.go index 5c4f8d8..15cf8a0 100644 --- a/gost/kcp.go +++ b/gost/kcp.go @@ -19,8 +19,8 @@ import ( ) var ( - // SALT is the default salt for KCP cipher. - SALT = "kcp-go" + // KCPSalt is the default salt for KCP cipher. + KCPSalt = "kcp-go" ) // KCPConfig describes the config for KCP. @@ -204,7 +204,7 @@ func (tr *kcpTransporter) Dial(addr string) (conn net.Conn, err error) { func (tr *kcpTransporter) dial(addr string, config *KCPConfig) (*kcpSession, error) { kcpconn, err := kcp.DialWithOptions(addr, - blockCrypt(config.Key, config.Crypt, SALT), config.DataShard, config.ParityShard) + blockCrypt(config.Key, config.Crypt, KCPSalt), config.DataShard, config.ParityShard) if err != nil { return nil, err } @@ -260,7 +260,7 @@ func KCPListener(addr string, config *KCPConfig) (Listener, error) { config.Init() ln, err := kcp.ListenWithOptions(addr, - blockCrypt(config.Key, config.Crypt, SALT), config.DataShard, config.ParityShard) + blockCrypt(config.Key, config.Crypt, KCPSalt), config.DataShard, config.ParityShard) if err != nil { return nil, err } diff --git a/gost/node.go b/gost/node.go index a710206..23e963e 100644 --- a/gost/node.go +++ b/gost/node.go @@ -1,9 +1,14 @@ package gost +import ( + "net/url" +) + // Node is a proxy node, mainly used to construct a proxy chain. type Node struct { Addr string Protocol string Transport string + User *url.Userinfo Client *Client } diff --git a/gost/redirect.go b/gost/redirect.go new file mode 100644 index 0000000..f7033c6 --- /dev/null +++ b/gost/redirect.go @@ -0,0 +1,91 @@ +// +build !windows + +package gost + +import ( + "errors" + "fmt" + "net" + "syscall" + + "github.com/go-log/log" +) + +type tcpRedirectHandler struct { + options *HandlerOptions +} + +// TCPRedirectHandler creates a server Handler for TCP redirect server. +func TCPRedirectHandler(opts ...HandlerOption) Handler { + h := &tcpRedirectHandler{ + options: &HandlerOptions{ + Chain: new(Chain), + }, + } + for _, opt := range opts { + opt(h.options) + } + return h +} + +func (h *tcpRedirectHandler) Handle(c net.Conn) { + conn, ok := c.(*net.TCPConn) + if !ok { + log.Log("[red-tcp] not a TCP connection") + } + + srcAddr := conn.RemoteAddr() + dstAddr, conn, err := h.getOriginalDstAddr(conn) + if err != nil { + log.Logf("[red-tcp] %s -> %s : %s", srcAddr, dstAddr, err) + return + } + defer conn.Close() + + log.Logf("[red-tcp] %s -> %s", srcAddr, dstAddr) + + cc, err := h.options.Chain.Dial(dstAddr.String()) + if err != nil { + log.Logf("[red-tcp] %s -> %s : %s", srcAddr, dstAddr, err) + return + } + defer cc.Close() + + log.Logf("[red-tcp] %s <-> %s", srcAddr, dstAddr) + transport(conn, cc) + log.Logf("[red-tcp] %s >-< %s", srcAddr, dstAddr) +} + +func (h *tcpRedirectHandler) getOriginalDstAddr(conn *net.TCPConn) (addr net.Addr, c *net.TCPConn, err error) { + defer conn.Close() + + fc, err := conn.File() + if err != nil { + return + } + defer fc.Close() + + mreq, err := syscall.GetsockoptIPv6Mreq(int(fc.Fd()), syscall.IPPROTO_IP, 80) + if err != nil { + return + } + + // only ipv4 support + ip := net.IPv4(mreq.Multiaddr[4], mreq.Multiaddr[5], mreq.Multiaddr[6], mreq.Multiaddr[7]) + port := uint16(mreq.Multiaddr[2])<<8 + uint16(mreq.Multiaddr[3]) + addr, err = net.ResolveTCPAddr("tcp4", fmt.Sprintf("%s:%d", ip.String(), port)) + if err != nil { + return + } + + cc, err := net.FileConn(fc) + if err != nil { + return + } + + c, ok := cc.(*net.TCPConn) + if !ok { + err = errors.New("not a TCP connection") + } + return +} diff --git a/gost/redirect_win.go b/gost/redirect_win.go new file mode 100644 index 0000000..848b70b --- /dev/null +++ b/gost/redirect_win.go @@ -0,0 +1,31 @@ +// +build windows + +package gost + +import ( + "net" + + "github.com/go-log/log" +) + +type tcpRedirectHandler struct { + options *HandlerOptions +} + +// TCPRedirectHandler creates a server Handler for TCP redirect server. +func TCPRedirectHandler(opts ...HandlerOption) Handler { + h := &tcpRedirectHandler{ + options: &HandlerOptions{ + Chain: new(Chain), + }, + } + for _, opt := range opts { + opt(h.options) + } + return h +} + +func (h *tcpRedirectHandler) Handle(c net.Conn) { + log.Log("[red-tcp] TCP redirect is not available on the Windows platform") + c.Close() +} diff --git a/gost/socks.go b/gost/socks.go index 81e8019..ce85899 100644 --- a/gost/socks.go +++ b/gost/socks.go @@ -365,6 +365,8 @@ func SOCKS5Handler(opts ...HandlerOption) Handler { } func (h *socks5Handler) Handle(conn net.Conn) { + defer conn.Close() + conn = gosocks5.ServerConn(conn, h.selector) req, err := gosocks5.ReadRequest(conn) if err != nil { @@ -960,6 +962,8 @@ func SOCKS4Handler(opts ...HandlerOption) Handler { } func (h *socks4Handler) Handle(conn net.Conn) { + defer conn.Close() + req, err := gosocks4.ReadRequest(conn) if err != nil { log.Log("[socks4]", err) diff --git a/gost/srv/srv.go b/gost/srv/srv.go index 0f212cc..4d467ea 100644 --- a/gost/srv/srv.go +++ b/gost/srv/srv.go @@ -6,8 +6,6 @@ import ( "net/url" - "sync" - "github.com/ginuerzh/gost/gost" ) @@ -17,27 +15,22 @@ func init() { } func main() { - wg := sync.WaitGroup{} - wg.Add(1) - go httpServer(&wg) - wg.Add(1) - go socks5Server(&wg) - wg.Add(1) - go tlsServer(&wg) - wg.Add(1) - go shadowServer(&wg) - wg.Add(1) - go wsServer(&wg) - wg.Add(1) - go wssServer(&wg) - wg.Add(1) - go kcpServer(&wg) - wg.Wait() + go httpServer() + go socks5Server() + go tlsServer() + go shadowServer() + go wsServer() + go wssServer() + go kcpServer() + go tcpForwardServer() + go rtcpForwardServer() + // go rudpForwardServer() + go tcpRedirectServer() + + select {} } -func httpServer(wg *sync.WaitGroup) { - defer wg.Done() - +func httpServer() { s := &gost.Server{} s.Handle(gost.HTTPHandler( gost.UsersHandlerOption(url.UserPassword("admin", "123456")), @@ -49,9 +42,7 @@ func httpServer(wg *sync.WaitGroup) { log.Fatal(s.Serve(ln)) } -func socks5Server(wg *sync.WaitGroup) { - defer wg.Done() - +func socks5Server() { cert, err := tls.LoadX509KeyPair("cert.pem", "key.pem") if err != nil { log.Fatal(err) @@ -69,9 +60,7 @@ func socks5Server(wg *sync.WaitGroup) { log.Fatal(s.Serve(ln)) } -func shadowServer(wg *sync.WaitGroup) { - defer wg.Done() - +func shadowServer() { s := &gost.Server{} s.Handle(gost.ShadowHandler( gost.UsersHandlerOption(url.UserPassword("chacha20", "123456")), @@ -83,9 +72,7 @@ func shadowServer(wg *sync.WaitGroup) { log.Fatal(s.Serve(ln)) } -func tlsServer(wg *sync.WaitGroup) { - defer wg.Done() - +func tlsServer() { s := &gost.Server{} s.Handle(gost.HTTPHandler( gost.UsersHandlerOption(url.UserPassword("admin", "123456")), @@ -101,9 +88,7 @@ func tlsServer(wg *sync.WaitGroup) { log.Fatal(s.Serve(ln)) } -func wsServer(wg *sync.WaitGroup) { - defer wg.Done() - +func wsServer() { s := &gost.Server{} s.Handle(gost.HTTPHandler( gost.UsersHandlerOption(url.UserPassword("admin", "123456")), @@ -115,9 +100,7 @@ func wsServer(wg *sync.WaitGroup) { log.Fatal(s.Serve(ln)) } -func wssServer(wg *sync.WaitGroup) { - defer wg.Done() - +func wssServer() { s := &gost.Server{} s.Handle(gost.HTTPHandler( gost.UsersHandlerOption(url.UserPassword("admin", "123456")), @@ -134,9 +117,7 @@ func wssServer(wg *sync.WaitGroup) { log.Fatal(s.Serve(ln)) } -func kcpServer(wg *sync.WaitGroup) { - defer wg.Done() - +func kcpServer() { s := &gost.Server{} s.Handle(gost.HTTPHandler()) ln, err := gost.KCPListener(":8388", nil) @@ -145,3 +126,71 @@ func kcpServer(wg *sync.WaitGroup) { } log.Fatal(s.Serve(ln)) } + +func tcpForwardServer() { + s := &gost.Server{} + s.Handle(gost.TCPForwardHandler("ginuerzh.xyz:22")) + ln, err := gost.TCPListener(":2222") + if err != nil { + log.Fatal(err) + } + log.Fatal(s.Serve(ln)) +} + +func rtcpForwardServer() { + s := &gost.Server{} + s.Handle(gost.RTCPForwardHandler(":1222", "ginuerzh.xyz:22")) + ln, err := gost.RTCPForwardListener( + ":1222", + gost.NewChain( + gost.Node{ + Protocol: "socks5", + Transport: "tcp", + Addr: "localhost:12345", + User: url.UserPassword("admin", "123456"), + Client: gost.NewClient( + gost.SOCKS5Connector(url.UserPassword("admin", "123456")), + gost.TCPTransporter(), + ), + }, + ), + ) + if err != nil { + log.Fatal() + } + log.Fatal(s.Serve(ln)) +} + +func rudpForwardServer() { + s := &gost.Server{} + s.Handle(gost.RUDPForwardHandler(":10053", "localhost:53")) + ln, err := gost.RUDPForwardListener( + ":10053", + gost.NewChain( + gost.Node{ + Protocol: "socks5", + Transport: "tcp", + Addr: "localhost:12345", + User: url.UserPassword("admin", "123456"), + Client: gost.NewClient( + gost.SOCKS5Connector(url.UserPassword("admin", "123456")), + gost.TCPTransporter(), + ), + }, + ), + ) + if err != nil { + log.Fatal() + } + log.Fatal(s.Serve(ln)) +} + +func tcpRedirectServer() { + s := &gost.Server{} + s.Handle(gost.TCPRedirectHandler()) + ln, err := gost.TCPListener(":8008") + if err != nil { + log.Fatal(err) + } + log.Fatal(s.Serve(ln)) +} diff --git a/gost/ss.go b/gost/ss.go index d053f7d..e6babd9 100644 --- a/gost/ss.go +++ b/gost/ss.go @@ -106,6 +106,8 @@ func ShadowHandler(opts ...HandlerOption) Handler { } func (h *shadowHandler) Handle(conn net.Conn) { + defer conn.Close() + var method, password string users := h.options.Users