From 682064407363b84a67e104c2592105b5810392fb Mon Sep 17 00:00:00 2001 From: nadoo <287492+nadoo@users.noreply.github.com> Date: Tue, 24 Nov 2020 19:30:08 +0800 Subject: [PATCH] proxy: added new scheme `udp` as replacement of `udptun` --- feature.go | 7 ++- go.mod | 2 +- go.sum | 4 +- proxy/udp/udp.go | 129 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 137 insertions(+), 5 deletions(-) create mode 100644 proxy/udp/udp.go diff --git a/feature.go b/feature.go index 51e6634..a9c8cc2 100644 --- a/feature.go +++ b/feature.go @@ -16,11 +16,14 @@ import ( _ "github.com/nadoo/glider/proxy/ssh" _ "github.com/nadoo/glider/proxy/ssr" _ "github.com/nadoo/glider/proxy/tcp" - _ "github.com/nadoo/glider/proxy/tcptun" _ "github.com/nadoo/glider/proxy/tls" _ "github.com/nadoo/glider/proxy/trojan" - _ "github.com/nadoo/glider/proxy/udptun" + _ "github.com/nadoo/glider/proxy/udp" _ "github.com/nadoo/glider/proxy/vless" _ "github.com/nadoo/glider/proxy/vmess" _ "github.com/nadoo/glider/proxy/ws" + + // deprecated, to be removed. + _ "github.com/nadoo/glider/proxy/tcptun" + _ "github.com/nadoo/glider/proxy/udptun" ) diff --git a/go.mod b/go.mod index 0609f9b..3bfacb6 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/xtaci/kcp-go/v5 v5.6.1 golang.org/x/crypto v0.0.0-20201117144127-c1f2f97bffc9 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68 // indirect - golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e // indirect + golang.org/x/tools v0.0.0-20201124005743-911501bfb504 // indirect gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect ) diff --git a/go.sum b/go.sum index a456fa6..90abcce 100644 --- a/go.sum +++ b/go.sum @@ -141,8 +141,8 @@ golang.org/x/tools v0.0.0-20200425043458-8463f397d07c/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200808161706-5bf02b21f123/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20201105001634-bc3cf281b174 h1:0rx0F4EjJNbxTuzWe0KjKcIzs+3VEb/Mrs/d1ciNz1c= golang.org/x/tools v0.0.0-20201105001634-bc3cf281b174/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e h1:t96dS3DO8DGjawSLJL/HIdz8CycAd2v07XxqB3UPTi0= -golang.org/x/tools v0.0.0-20201120155355-20be4ac4bd6e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201124005743-911501bfb504 h1:jOKV2ysikH1GANB7t2LotmhyvkkPvl7HQoEXkV6slJA= +golang.org/x/tools v0.0.0-20201124005743-911501bfb504/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/proxy/udp/udp.go b/proxy/udp/udp.go new file mode 100644 index 0000000..52d5a1a --- /dev/null +++ b/proxy/udp/udp.go @@ -0,0 +1,129 @@ +package udp + +import ( + "net" + "net/url" + "sync" + "time" + + "github.com/nadoo/glider/log" + "github.com/nadoo/glider/proxy" +) + +// UDP struct. +type UDP struct { + addr string + dialer proxy.Dialer + proxy proxy.Proxy + server proxy.Server +} + +func init() { + proxy.RegisterDialer("udp", NewUDPDialer) + proxy.RegisterServer("udp", NewUDPServer) +} + +// NewUDP returns a udp struct. +func NewUDP(s string, d proxy.Dialer, p proxy.Proxy) (*UDP, error) { + u, err := url.Parse(s) + if err != nil { + log.F("[udp] parse url err: %s", err) + return nil, err + } + + t := &UDP{ + dialer: d, + proxy: p, + addr: u.Host, + } + + return t, nil +} + +// NewUDPDialer returns a udp dialer. +func NewUDPDialer(s string, d proxy.Dialer) (proxy.Dialer, error) { + return NewUDP(s, d, nil) +} + +// NewUDPServer returns a udp transport layer before the real server. +func NewUDPServer(s string, p proxy.Proxy) (proxy.Server, error) { + return NewUDP(s, nil, p) +} + +// ListenAndServe listens on server's addr and serves connections. +func (s *UDP) ListenAndServe() { + c, err := net.ListenPacket("udp", s.addr) + if err != nil { + log.F("[udp] failed to listen on %s: %v", s.addr, err) + return + } + defer c.Close() + + log.F("[udp] listening UDP on %s", s.addr) + + var nm sync.Map + buf := make([]byte, proxy.UDPBufSize) + + for { + n, lraddr, err := c.ReadFrom(buf) + if err != nil { + log.F("[udp] read error: %v", err) + continue + } + + var raddr net.Addr + var pc net.PacketConn + + v, ok := nm.Load(lraddr.String()) + if !ok && v == nil { + pc, raddr, err = s.proxy.DialUDP("udp", "") + if err != nil { + log.F("[udp] remote dial error: %v", err) + continue + } + + nm.Store(lraddr.String(), pc) + + go func(c, pc net.PacketConn, lraddr net.Addr) { + proxy.RelayUDP(c, lraddr, pc, 2*time.Minute) + pc.Close() + nm.Delete(lraddr.String()) + }(c, pc, lraddr) + + } else { + pc = v.(net.PacketConn) + } + + _, err = pc.WriteTo(buf[:n], raddr) + if err != nil { + log.F("[udp] remote write error: %v", err) + continue + } + + log.F("[udp] %s <-> %s", lraddr, raddr) + + } +} + +// Serve serves a connection. +func (s *UDP) Serve(c net.Conn) { + log.F("[udp] func Serve: can not be called directly") +} + +// Addr returns forwarder's address. +func (s *UDP) Addr() string { + if s.addr == "" { + return s.dialer.Addr() + } + return s.addr +} + +// Dial connects to the address addr on the network net via the proxy. +func (s *UDP) Dial(network, addr string) (net.Conn, error) { + return s.dialer.Dial("udp", s.addr) +} + +// DialUDP connects to the given address via the proxy. +func (s *UDP) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { + return s.dialer.DialUDP(network, s.addr) +}