From 6c1522dace5162c65767a894369aab3b14c7d47b Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Fri, 17 Dec 2021 15:00:13 +0800 Subject: [PATCH] add udp redirect listener --- cmd/gost/register.go | 1 + go.mod | 1 + go.sum | 4 +- pkg/handler/redirect/handler.go | 4 +- pkg/handler/redirect/handler_other.go | 2 +- pkg/listener/redirect/udp/conn.go | 42 ++++++++++++++ pkg/listener/redirect/udp/listener.go | 63 +++++++++++++++++++++ pkg/listener/redirect/udp/listener_linux.go | 37 ++++++++++++ pkg/listener/redirect/udp/listener_other.go | 16 ++++++ pkg/listener/redirect/udp/metadata.go | 36 ++++++++++++ 10 files changed, 202 insertions(+), 4 deletions(-) create mode 100644 pkg/listener/redirect/udp/conn.go create mode 100644 pkg/listener/redirect/udp/listener.go create mode 100644 pkg/listener/redirect/udp/listener_linux.go create mode 100644 pkg/listener/redirect/udp/listener_other.go create mode 100644 pkg/listener/redirect/udp/metadata.go diff --git a/cmd/gost/register.go b/cmd/gost/register.go index 8c7cf87..c6782a0 100644 --- a/cmd/gost/register.go +++ b/cmd/gost/register.go @@ -49,6 +49,7 @@ import ( _ "github.com/go-gost/gost/pkg/listener/obfs/http" _ "github.com/go-gost/gost/pkg/listener/obfs/tls" _ "github.com/go-gost/gost/pkg/listener/quic" + _ "github.com/go-gost/gost/pkg/listener/redirect/udp" _ "github.com/go-gost/gost/pkg/listener/rtcp" _ "github.com/go-gost/gost/pkg/listener/rudp" _ "github.com/go-gost/gost/pkg/listener/tcp" diff --git a/go.mod b/go.mod index 37a6d53..84aa030 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/go-gost/gost go 1.17 require ( + github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d github.com/cheekybits/genny v1.0.0 // indirect diff --git a/go.sum b/go.sum index 2945c44..b99f18d 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed h1:eqa6queieK8SvoszxCu0WwH7lSVeL4/N/f1JwOMw1G4= +github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed/go.mod h1:rA52xkgZwql9LRZXWb2arHEFP6qSR48KY2xOfWzEciQ= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY= github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA= @@ -397,8 +399,6 @@ github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM= github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE= -github.com/xtaci/smux v1.5.15 h1:6hMiXswcleXj5oNfcJc+DXS8Vj36XX2LaX98udog6Kc= -github.com/xtaci/smux v1.5.15/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY= github.com/xtaci/smux v1.5.16 h1:FBPYOkW8ZTjLKUM4LI4xnnuuDC8CQ/dB04HD519WoEk= github.com/xtaci/smux v1.5.16/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY= github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk= diff --git a/pkg/handler/redirect/handler.go b/pkg/handler/redirect/handler.go index f180d38..b319079 100644 --- a/pkg/handler/redirect/handler.go +++ b/pkg/handler/redirect/handler.go @@ -16,6 +16,7 @@ import ( func init() { registry.RegisterHandler("red", NewHandler) + registry.RegisterHandler("redu", NewHandler) registry.RegisterHandler("redir", NewHandler) registry.RegisterHandler("redirect", NewHandler) } @@ -49,6 +50,8 @@ func (h *redirectHandler) WithChain(chain *chain.Chain) { } func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn) { + defer conn.Close() + start := time.Now() h.logger = h.logger.WithFields(map[string]interface{}{ "remote": conn.RemoteAddr().String(), @@ -78,7 +81,6 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn) { return } } - defer conn.Close() h.logger = h.logger.WithFields(map[string]interface{}{ "dst": fmt.Sprintf("%s/%s", dstAddr, network), diff --git a/pkg/handler/redirect/handler_other.go b/pkg/handler/redirect/handler_other.go index f576617..58a6f7e 100644 --- a/pkg/handler/redirect/handler_other.go +++ b/pkg/handler/redirect/handler_other.go @@ -10,6 +10,6 @@ import ( func (h *redirectHandler) getOriginalDstAddr(conn net.Conn) (addr net.Addr, c net.Conn, err error) { defer conn.Close() - err = errors.New("TCP redirect is not available on Windows platform") + err = errors.New("TCP redirect is not available on non-linux platform") return } diff --git a/pkg/listener/redirect/udp/conn.go b/pkg/listener/redirect/udp/conn.go new file mode 100644 index 0000000..585f98f --- /dev/null +++ b/pkg/listener/redirect/udp/conn.go @@ -0,0 +1,42 @@ +package udp + +import ( + "net" + "sync" + "time" + + "github.com/go-gost/gost/pkg/common/bufpool" +) + +type redirConn struct { + net.Conn + buf []byte + ttl time.Duration + once sync.Once +} + +func (c *redirConn) Read(b []byte) (n int, err error) { + if c.ttl > 0 { + c.SetReadDeadline(time.Now().Add(c.ttl)) + defer c.SetReadDeadline(time.Time{}) + } + + c.once.Do(func() { + n = copy(b, c.buf) + bufpool.Put(c.buf) + c.buf = nil + }) + + if n == 0 { + n, err = c.Conn.Read(b) + } + return +} + +func (c *redirConn) Write(b []byte) (n int, err error) { + if c.ttl > 0 { + c.SetWriteDeadline(time.Now().Add(c.ttl)) + defer c.SetWriteDeadline(time.Time{}) + } + return c.Conn.Write(b) +} diff --git a/pkg/listener/redirect/udp/listener.go b/pkg/listener/redirect/udp/listener.go new file mode 100644 index 0000000..281c8b4 --- /dev/null +++ b/pkg/listener/redirect/udp/listener.go @@ -0,0 +1,63 @@ +package udp + +import ( + "net" + + "github.com/go-gost/gost/pkg/listener" + "github.com/go-gost/gost/pkg/logger" + md "github.com/go-gost/gost/pkg/metadata" + "github.com/go-gost/gost/pkg/registry" +) + +func init() { + registry.RegisterListener("redu", NewListener) +} + +type redirectListener struct { + addr string + ln *net.UDPConn + logger logger.Logger + md metadata +} + +func NewListener(opts ...listener.Option) listener.Listener { + options := &listener.Options{} + for _, opt := range opts { + opt(options) + } + return &redirectListener{ + addr: options.Addr, + logger: options.Logger, + } +} + +func (l *redirectListener) Init(md md.Metadata) (err error) { + if err = l.parseMetadata(md); err != nil { + return + } + + laddr, err := net.ResolveUDPAddr("udp", l.addr) + if err != nil { + return + } + + ln, err := l.listenUDP(laddr) + if err != nil { + return + } + + l.ln = ln + return +} + +func (l *redirectListener) Accept() (conn net.Conn, err error) { + return l.accept() +} + +func (l *redirectListener) Addr() net.Addr { + return l.ln.LocalAddr() +} + +func (l *redirectListener) Close() error { + return l.ln.Close() +} diff --git a/pkg/listener/redirect/udp/listener_linux.go b/pkg/listener/redirect/udp/listener_linux.go new file mode 100644 index 0000000..9989af2 --- /dev/null +++ b/pkg/listener/redirect/udp/listener_linux.go @@ -0,0 +1,37 @@ +package udp + +import ( + "net" + + "github.com/LiamHaworth/go-tproxy" + "github.com/go-gost/gost/pkg/common/bufpool" +) + +func (l *redirectListener) listenUDP(addr *net.UDPAddr) (*net.UDPConn, error) { + return tproxy.ListenUDP("udp", addr) +} + +func (l *redirectListener) accept() (conn net.Conn, err error) { + b := bufpool.Get(l.md.readBufferSize) + + n, raddr, dstAddr, err := tproxy.ReadFromUDP(l.ln, b) + if err != nil { + l.logger.Error(err) + return + } + + l.logger.Infof("%s >> %s", raddr.String(), dstAddr.String()) + + c, err := tproxy.DialUDP("udp", dstAddr, raddr) + if err != nil { + l.logger.Error(err) + return + } + + conn = &redirConn{ + Conn: c, + buf: b[:n], + ttl: l.md.ttl, + } + return +} diff --git a/pkg/listener/redirect/udp/listener_other.go b/pkg/listener/redirect/udp/listener_other.go new file mode 100644 index 0000000..82a93ff --- /dev/null +++ b/pkg/listener/redirect/udp/listener_other.go @@ -0,0 +1,16 @@ +//go:build !linux + +package udp + +import ( + "errors" + "net" +) + +func (l *redirectListener) listenUDP(addr *net.UDPAddr) (*net.UDPConn, error) { + return nil, errors.New("UDP redirect is not available on non-linux platform") +} + +func (l *redirectListener) accept() (conn net.Conn, err error) { + return nil, errors.New("UDP redirect is not available on non-linux platform") +} diff --git a/pkg/listener/redirect/udp/metadata.go b/pkg/listener/redirect/udp/metadata.go new file mode 100644 index 0000000..2a513b5 --- /dev/null +++ b/pkg/listener/redirect/udp/metadata.go @@ -0,0 +1,36 @@ +package udp + +import ( + "time" + + md "github.com/go-gost/gost/pkg/metadata" +) + +const ( + defaultTTL = 60 * time.Second + defaultReadBufferSize = 1024 +) + +type metadata struct { + ttl time.Duration + readBufferSize int +} + +func (l *redirectListener) parseMetadata(md md.Metadata) (err error) { + const ( + ttl = "ttl" + readBufferSize = "readBufferSize" + ) + + l.md.ttl = md.GetDuration(ttl) + if l.md.ttl <= 0 { + l.md.ttl = defaultTTL + } + + l.md.readBufferSize = md.GetInt(readBufferSize) + if l.md.readBufferSize <= 0 { + l.md.readBufferSize = defaultReadBufferSize + } + + return +}