diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 87bedbd..6c452c7 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -98,7 +98,7 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Set up QEMU + - name: Docker - Set up QEMU uses: docker/setup-qemu-action@v1 - name: Docker - Set up Buildx diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index f7fd285..1c5c99b 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -7,7 +7,7 @@ jobs: stale: runs-on: ubuntu-latest steps: - - uses: actions/stale@v4 + - uses: actions/stale@v5 with: stale-issue-message: 'This issue is stale because it has been open 90 days with no activity. Remove stale label or comment or this will be closed in 5 days.' days-before-stale: 90 diff --git a/Dockerfile b/Dockerfile index 8f73394..13e497f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Build Stage -FROM golang:1.18beta2-alpine AS build-env +FROM golang:1.18 AS build-env ADD . /src diff --git a/config/glider.conf.example b/config/glider.conf.example index 9843109..9a83516 100644 --- a/config/glider.conf.example +++ b/config/glider.conf.example @@ -61,7 +61,7 @@ listen=socks5://:1080 # listen=tls://:443?cert=crtFilePath&key=keyFilePath,ss://AEAD_CHACHA20_POLY1305:pass@ # socks5 over unix domain socket -# listen=unix:///tmp/glider.socket,socks5:// +# listen=unix:///dev/shm/socket,socks5:// # socks5 over kcp # listen=kcp://aes:key@127.0.0.1:8444?dataShards=10&parityShards=3&mode=fast,socks5:// @@ -152,7 +152,7 @@ listen=socks5://:1080 # forward=simple-obfs://1.1.1.1:443?type=tls&host=apple.com,ss://AEAD_CHACHA20_POLY1305:pass@ # socks5 over unix domain socket -# forward=unix:///tmp/glider.socket,socks5:// +# forward=unix:///dev/shm/socket,socks5:// # FORWARDER CHAIN # --------------- @@ -254,6 +254,7 @@ dnsrecord=www.example.com/2606:2800:220:1:248:1893:25c8:1946 # SERVICES # service=dhcpd,INTERFACE,START_IP,END_IP,LEASE_MINUTES[,MAC=IP,MAC=IP...] +# service=dhcpd-failover,INTERFACE,START_IP,END_IP,LEASE_MINUTES[,MAC=IP,MAC=IP...] # e.g.: # service=dhcpd,eth1,192.168.1.100,192.168.1.199,720 # service=dhcpd,eth2,192.168.2.100,192.168.2.199,720,fc:23:34:9e:25:01=192.168.2.101,fc:23:34:9e:25:02=192.168.2.102 diff --git a/feature.go b/feature.go index 21b49fc..1884cab 100644 --- a/feature.go +++ b/feature.go @@ -7,12 +7,14 @@ import ( // comment out the protocols you don't need to make the compiled binary smaller. _ "github.com/nadoo/glider/proxy/http" _ "github.com/nadoo/glider/proxy/kcp" + _ "github.com/nadoo/glider/proxy/mixed" _ "github.com/nadoo/glider/proxy/obfs" _ "github.com/nadoo/glider/proxy/pxyproto" _ "github.com/nadoo/glider/proxy/reject" _ "github.com/nadoo/glider/proxy/smux" _ "github.com/nadoo/glider/proxy/socks4" + _ "github.com/nadoo/glider/proxy/socks5" _ "github.com/nadoo/glider/proxy/ss" _ "github.com/nadoo/glider/proxy/ssh" @@ -20,6 +22,7 @@ import ( _ "github.com/nadoo/glider/proxy/tcp" _ "github.com/nadoo/glider/proxy/tls" _ "github.com/nadoo/glider/proxy/trojan" + _ "github.com/nadoo/glider/proxy/udp" _ "github.com/nadoo/glider/proxy/vless" _ "github.com/nadoo/glider/proxy/vmess" diff --git a/go.mod b/go.mod index de522d9..3c8d0e8 100644 --- a/go.mod +++ b/go.mod @@ -11,8 +11,8 @@ require ( github.com/nadoo/conflag v0.3.1 github.com/nadoo/ipset v0.4.1-0.20220218075046-ca3cdce74266 github.com/xtaci/kcp-go/v5 v5.6.1 - golang.org/x/crypto v0.0.0-20220214200702-86341886e292 - golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 + golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 + golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 ) require ( diff --git a/go.sum b/go.sum index fd908b5..7f1e8d2 100644 --- a/go.sum +++ b/go.sum @@ -49,7 +49,6 @@ github.com/jsimonetti/rtnetlink v0.0.0-20201009170750-9c6f07d100c1/go.mod h1:hqo github.com/jsimonetti/rtnetlink v0.0.0-20201110080708-d2c240429e6c/go.mod h1:huN4d1phzjhlOsNIjFsw2SVRbwIHj3fJDMEU2SDPTmg= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= github.com/klauspost/cpuid v1.2.4/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= -github.com/klauspost/cpuid v1.3.1 h1:5JNjFYYQrZeKRJ0734q51WCEEn2huer72Dc7K+R/b6s= github.com/klauspost/cpuid v1.3.1/go.mod h1:bYW4mA6ZgKPob1/Dlai2LviZJO7KGI3uoWLd42rAQw4= github.com/klauspost/cpuid/v2 v2.0.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.11 h1:i2lw1Pm7Yi/4O6XCSyJWqEHI2MDw2FzUK6o/D21xn2A= @@ -112,8 +111,8 @@ golang.org/x/crypto v0.0.0-20191219195013-becbf705a915/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292 h1:f+lwQ+GtmgoY+A2YaQxlSOnDjXcQ7ZRLWOHbC6HtRqE= -golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU= +golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -165,8 +164,8 @@ golang.org/x/sys v0.0.0-20201101102859-da207088b7d1/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210525143221-35b2ab0089ea/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9 h1:nhht2DYV/Sn3qOayu8lM+cU1ii9sTLUeBQwQQfUHtrs= -golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng= +golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= diff --git a/pkg/socks/socks.go b/pkg/socks/socks.go index 448ccd1..aba1810 100644 --- a/pkg/socks/socks.go +++ b/pkg/socks/socks.go @@ -71,11 +71,9 @@ func (a Addr) String() string { // Network returns network name. Implements net.Addr interface. func (a Addr) Network() string { return "socks" } -// ReadAddrBuf reads just enough bytes from r to get a valid Addr. -func ReadAddrBuf(r io.Reader, b []byte) (Addr, error) { - if len(b) < MaxAddrLen { - return nil, io.ErrShortBuffer - } +// ReadAddr reads just enough bytes from r to get a valid Addr. +func ReadAddr(r io.Reader) (Addr, error) { + b := make([]byte, MaxAddrLen) _, err := io.ReadFull(r, b[:1]) // read 1st byte for address type if err != nil { return nil, err @@ -100,11 +98,6 @@ func ReadAddrBuf(r io.Reader, b []byte) (Addr, error) { return nil, Errors[8] } -// ReadAddr reads just enough bytes from r to get a valid Addr. -func ReadAddr(r io.Reader) (Addr, error) { - return ReadAddrBuf(r, make([]byte, MaxAddrLen)) -} - // SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed. func SplitAddr(b []byte) Addr { addrLen := 1 diff --git a/proxy/dialer.go b/proxy/dialer.go index 753fa6a..83553e3 100644 --- a/proxy/dialer.go +++ b/proxy/dialer.go @@ -33,7 +33,7 @@ type UDPDialer interface { Addr() string // DialUDP connects to the given address - DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) + DialUDP(network, addr string) (pc net.PacketConn, err error) } // DialerCreator is a function to create dialers. diff --git a/proxy/direct.go b/proxy/direct.go index 2487a59..12a7063 100644 --- a/proxy/direct.go +++ b/proxy/direct.go @@ -7,7 +7,6 @@ import ( "net/netip" "time" - "github.com/nadoo/glider/pkg/log" "github.com/nadoo/glider/pkg/sockopt" ) @@ -109,7 +108,7 @@ func (d *Direct) dial(network, addr string, localIP net.IP) (net.Conn, error) { } // DialUDP connects to the given address. -func (d *Direct) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { +func (d *Direct) DialUDP(network, addr string) (net.PacketConn, error) { var la string if d.ip != nil { la = net.JoinHostPort(d.ip.String(), "0") @@ -120,14 +119,7 @@ func (d *Direct) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) lc.Control = sockopt.Control(sockopt.Bind(d.iface)) } - pc, err := lc.ListenPacket(context.Background(), network, la) - if err != nil { - log.F("ListenPacket error: %s", err) - return nil, nil, err - } - - uAddr, err := net.ResolveUDPAddr("udp", addr) - return pc, uAddr, err + return lc.ListenPacket(context.Background(), network, la) } // IFaceIPs returns ip addresses according to the specified interface. diff --git a/proxy/http/client.go b/proxy/http/client.go index c724059..b2f3f7c 100644 --- a/proxy/http/client.go +++ b/proxy/http/client.go @@ -76,6 +76,6 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *HTTP) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) { - return nil, nil, proxy.ErrNotSupported +func (s *HTTP) DialUDP(network, addr string) (pc net.PacketConn, err error) { + return nil, proxy.ErrNotSupported } diff --git a/proxy/kcp/kcp.go b/proxy/kcp/kcp.go index 3a41e8f..4f03700 100644 --- a/proxy/kcp/kcp.go +++ b/proxy/kcp/kcp.go @@ -239,8 +239,8 @@ func (s *KCP) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *KCP) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - return nil, nil, proxy.ErrNotSupported +func (s *KCP) DialUDP(network, addr string) (net.PacketConn, error) { + return nil, proxy.ErrNotSupported } func (s *KCP) setParams(c *kcp.UDPSession) { diff --git a/proxy/obfs/obfs.go b/proxy/obfs/obfs.go index 75ffe0b..7a497b5 100644 --- a/proxy/obfs/obfs.go +++ b/proxy/obfs/obfs.go @@ -106,8 +106,8 @@ func (s *Obfs) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *Obfs) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - return nil, nil, proxy.ErrNotSupported +func (s *Obfs) DialUDP(network, addr string) (net.PacketConn, error) { + return nil, proxy.ErrNotSupported } func init() { diff --git a/proxy/proxy.go b/proxy/proxy.go index 03eda74..afc5dfc 100644 --- a/proxy/proxy.go +++ b/proxy/proxy.go @@ -8,7 +8,7 @@ type Proxy interface { Dial(network, addr string) (c net.Conn, dialer Dialer, err error) // DialUDP connects to the given address via the proxy. - DialUDP(network, addr string) (pc net.PacketConn, dialer UDPDialer, writeTo net.Addr, err error) + DialUDP(network, addr string) (pc net.PacketConn, dialer UDPDialer, err error) // Get the dialer by dstAddr. NextDialer(dstAddr string) Dialer diff --git a/proxy/reject/reject.go b/proxy/reject/reject.go index 13935c4..33cf487 100644 --- a/proxy/reject/reject.go +++ b/proxy/reject/reject.go @@ -34,6 +34,6 @@ func (s *Reject) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *Reject) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - return nil, nil, errors.New("REJECT") +func (s *Reject) DialUDP(network, addr string) (net.PacketConn, error) { + return nil, errors.New("REJECT") } diff --git a/proxy/smux/client.go b/proxy/smux/client.go index f3aaa93..5b0be95 100644 --- a/proxy/smux/client.go +++ b/proxy/smux/client.go @@ -64,8 +64,8 @@ func (s *SmuxClient) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *SmuxClient) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - return nil, nil, proxy.ErrNotSupported +func (s *SmuxClient) DialUDP(network, addr string) (net.PacketConn, error) { + return nil, proxy.ErrNotSupported } func (s *SmuxClient) initConn() error { diff --git a/proxy/socks4/socks4.go b/proxy/socks4/socks4.go index 61222c3..c2c745c 100644 --- a/proxy/socks4/socks4.go +++ b/proxy/socks4/socks4.go @@ -88,8 +88,8 @@ func (s *SOCKS4) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *SOCKS4) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) { - return nil, nil, proxy.ErrNotSupported +func (s *SOCKS4) DialUDP(network, addr string) (pc net.PacketConn, err error) { + return nil, proxy.ErrNotSupported } func (s *SOCKS4) lookupIP(host string) (ip net.IP, err error) { diff --git a/proxy/socks5/client.go b/proxy/socks5/client.go index d0ba28f..b10cbcd 100644 --- a/proxy/socks5/client.go +++ b/proxy/socks5/client.go @@ -63,17 +63,17 @@ func (s *Socks5) dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *Socks5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) { +func (s *Socks5) DialUDP(network, addr string) (pc net.PacketConn, err error) { c, err := s.dial("tcp", s.addr) if err != nil { log.F("[socks5] dialudp dial tcp to %s error: %s", s.addr, err) - return nil, nil, err + return nil, err } var uAddr socks.Addr if uAddr, err = s.connect(c, addr, socks.CmdUDPAssociate); err != nil { c.Close() - return nil, nil, err + return nil, err } buf := pool.GetBuffer(socks.MaxAddrLen) @@ -88,14 +88,19 @@ func (s *Socks5) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.A uAddress = net.JoinHostPort(h, p) } - pc, nextHop, err := s.dialer.DialUDP(network, uAddress) + pc, err = s.dialer.DialUDP(network, uAddress) if err != nil { log.F("[socks5] dialudp to %s error: %s", uAddress, err) - return nil, nil, err + return nil, err } - pkc := NewPktConn(pc, nextHop, socks.ParseAddr(addr), true, c) - return pkc, nextHop, err + writeTo, err := net.ResolveUDPAddr("udp", uAddress) + if err != nil { + log.F("[socks5] resolve addr error: %s", err) + return nil, err + } + + return NewPktConn(pc, writeTo, socks.ParseAddr(addr), c), err } // connect takes an existing connection to a socks5 proxy server, diff --git a/proxy/socks5/packet.go b/proxy/socks5/packet.go index 75c26ee..32309df 100644 --- a/proxy/socks5/packet.go +++ b/proxy/socks5/packet.go @@ -11,22 +11,17 @@ import ( // PktConn . type PktConn struct { net.PacketConn - - writeAddr net.Addr // write to and read from addr - - tgtAddr socks.Addr - tgtHeader bool - ctrlConn net.Conn // tcp control conn + writeTo net.Addr // write to and read from addr + target socks.Addr } -// NewPktConn returns a PktConn. -func NewPktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr socks.Addr, tgtHeader bool, ctrlConn net.Conn) *PktConn { +// NewPktConn returns a PktConn, the writeAddr must be *net.UDPAddr or *net.UnixAddr. +func NewPktConn(c net.PacketConn, writeAddr net.Addr, targetAddr socks.Addr, ctrlConn net.Conn) *PktConn { pc := &PktConn{ PacketConn: c, - writeAddr: writeAddr, - tgtAddr: tgtAddr, - tgtHeader: tgtHeader, + writeTo: writeAddr, + target: targetAddr, ctrlConn: ctrlConn, } @@ -50,20 +45,21 @@ func NewPktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr socks.Addr, tgtHea // ReadFrom overrides the original function from net.PacketConn. func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { - if !pc.tgtHeader { - return pc.PacketConn.ReadFrom(b) - } + n, _, target, err := pc.readFrom(b) + return n, target, err +} +func (pc *PktConn) readFrom(b []byte) (int, net.Addr, net.Addr, error) { buf := pool.GetBuffer(len(b)) defer pool.PutBuffer(buf) n, raddr, err := pc.PacketConn.ReadFrom(buf) if err != nil { - return n, raddr, err + return n, raddr, nil, err } if n < 3 { - return n, raddr, errors.New("not enough size to get addr") + return n, raddr, nil, errors.New("not enough size to get addr") } // https://www.rfc-editor.org/rfc/rfc1928#section-7 @@ -74,38 +70,46 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { // +----+------+------+----------+----------+----------+ tgtAddr := socks.SplitAddr(buf[3:n]) if tgtAddr == nil { - return n, raddr, errors.New("can not get addr") + return n, raddr, nil, errors.New("can not get target addr") + } + + target, err := net.ResolveUDPAddr("udp", tgtAddr.String()) + if err != nil { + return n, raddr, nil, errors.New("wrong target addr") + } + + if pc.writeTo == nil { + pc.writeTo = raddr + } + + if pc.target == nil { + pc.target = make([]byte, len(tgtAddr)) + copy(pc.target, tgtAddr) } n = copy(b, buf[3+len(tgtAddr):n]) - - //test - if pc.writeAddr == nil { - pc.writeAddr = raddr - } - - if pc.tgtAddr == nil { - pc.tgtAddr = make([]byte, len(tgtAddr)) - copy(pc.tgtAddr, tgtAddr) - } - - return n, raddr, err + return n, raddr, target, err } // WriteTo overrides the original function from net.PacketConn. func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { - if !pc.tgtHeader { - return pc.PacketConn.WriteTo(b, addr) + target := pc.target + if addr != nil { + target = socks.ParseAddr(addr.String()) + } + + if target == nil { + return 0, errors.New("invalid addr") } buf := pool.GetBytesBuffer() defer pool.PutBytesBuffer(buf) buf.Write([]byte{0, 0, 0}) - tgtLen, _ := buf.Write(pc.tgtAddr) + tgtLen, _ := buf.Write(target) buf.Write(b) - n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeAddr) + n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeTo) if n > tgtLen+3 { return n - tgtLen - 3, err } diff --git a/proxy/socks5/server.go b/proxy/socks5/server.go index 3dd10ec..0b0db0d 100644 --- a/proxy/socks5/server.go +++ b/proxy/socks5/server.go @@ -116,10 +116,10 @@ func (s *Socks5) ListenAndServeUDP() { // ServePacket implementes proxy.PacketServer. func (s *Socks5) ServePacket(pc net.PacketConn) { for { - c := NewPktConn(pc, nil, nil, true, nil) + c := NewPktConn(pc, nil, nil, nil) buf := pool.GetBuffer(proxy.UDPBufSize) - n, srcAddr, err := c.ReadFrom(buf) + n, srcAddr, dstAddr, err := c.readFrom(buf) if err != nil { log.F("[socks5u] remote read error: %v", err) continue @@ -130,60 +130,66 @@ func (s *Socks5) ServePacket(pc net.PacketConn) { v, ok := nm.Load(sessionKey) if !ok || v == nil { - session = newSession(sessionKey, srcAddr, c) + session = newSession(sessionKey, srcAddr, dstAddr, c) nm.Store(sessionKey, session) go s.serveSession(session) } else { session = v.(*Session) } - session.msgCh <- buf[:n] + session.msgCh <- message{dstAddr, buf[:n]} } } func (s *Socks5) serveSession(session *Session) { - dstC, dialer, writeTo, err := s.proxy.DialUDP("udp", session.srcPC.tgtAddr.String()) + dstPC, dialer, err := s.proxy.DialUDP("udp", session.srcPC.target.String()) if err != nil { log.F("[socks5u] remote dial error: %v", err) nm.Delete(session.key) return } - dstPC := NewPktConn(dstC, writeTo, nil, false, nil) defer dstPC.Close() go func() { - proxy.CopyUDP(session.srcPC, session.src, dstPC, 2*time.Minute, 5*time.Second) + proxy.CopyUDP(session.srcPC, nil, dstPC, 2*time.Minute, 5*time.Second) nm.Delete(session.key) close(session.finCh) }() - log.F("[socks5u] %s <-> %s via %s", session.src, session.srcPC.tgtAddr, dialer.Addr()) + log.F("[socks5u] %s <-> %s via %s", session.src, session.srcPC.target, dialer.Addr()) for { select { - case p := <-session.msgCh: - _, err = dstPC.WriteTo(p, writeTo) + case msg := <-session.msgCh: + _, err = dstPC.WriteTo(msg.msg, msg.dst) if err != nil { - log.F("[socks5u] writeTo %s error: %v", writeTo, err) + log.F("[socks5u] writeTo %s error: %v", nil, err) } - pool.PutBuffer(p) + pool.PutBuffer(msg.msg) + msg.msg = nil case <-session.finCh: return } } } +type message struct { + dst net.Addr + msg []byte +} + // Session is a udp session type Session struct { key string src net.Addr + dst net.Addr srcPC *PktConn - msgCh chan []byte + msgCh chan message finCh chan struct{} } -func newSession(key string, src net.Addr, srcPC *PktConn) *Session { - return &Session{key, src, srcPC, make(chan []byte, 32), make(chan struct{})} +func newSession(key string, src, dst net.Addr, srcPC *PktConn) *Session { + return &Session{key, src, dst, srcPC, make(chan message, 32), make(chan struct{})} } // Handshake fast-tracks SOCKS initialization to get target address to connect. @@ -268,7 +274,7 @@ func (s *Socks5) handshake(c net.Conn) (socks.Addr, error) { return nil, err } cmd := buf[1] - addr, err := socks.ReadAddrBuf(c, buf) + addr, err := socks.ReadAddr(c) if err != nil { return nil, err } diff --git a/proxy/ss/client.go b/proxy/ss/client.go index 5ea2240..20d875b 100644 --- a/proxy/ss/client.go +++ b/proxy/ss/client.go @@ -45,13 +45,19 @@ func (s *SS) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *SS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - pc, nextHop, err := s.dialer.DialUDP(network, s.addr) +func (s *SS) DialUDP(network, addr string) (net.PacketConn, error) { + pc, err := s.dialer.DialUDP(network, s.addr) if err != nil { log.F("[ss] dialudp to %s error: %s", s.addr, err) - return nil, nil, err + return nil, err } - pkc := NewPktConn(s.PacketConn(pc), nextHop, socks.ParseAddr(addr), true) - return pkc, nextHop, err + writeTo, err := net.ResolveUDPAddr("udp", s.addr) + if err != nil { + log.F("[ss] resolve addr error: %s", err) + return nil, err + } + + pkc := NewPktConn(s.PacketConn(pc), writeTo, socks.ParseAddr(addr)) + return pkc, nil } diff --git a/proxy/ss/packet.go b/proxy/ss/packet.go index ae71da2..8aae5e4 100644 --- a/proxy/ss/packet.go +++ b/proxy/ss/packet.go @@ -11,70 +11,71 @@ import ( // PktConn . type PktConn struct { net.PacketConn - - writeAddr net.Addr // write to and read from addr - - tgtAddr socks.Addr - tgtHeader bool + writeTo net.Addr + target socks.Addr // if target is not nil, it may be a tunnel } -// NewPktConn returns a PktConn -func NewPktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr socks.Addr, tgtHeader bool) *PktConn { - pc := &PktConn{ - PacketConn: c, - writeAddr: writeAddr, - tgtAddr: tgtAddr, - tgtHeader: tgtHeader} - return pc +// NewPktConn returns a PktConn, the writeAddr must be *net.UDPAddr or *net.UnixAddr. +func NewPktConn(c net.PacketConn, writeAddr net.Addr, targetAddr socks.Addr) *PktConn { + return &PktConn{PacketConn: c, writeTo: writeAddr, target: targetAddr} } -// ReadFrom overrides the original function from net.PacketConn +// ReadFrom overrides the original function from net.PacketConn. func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { - if !pc.tgtHeader { - return pc.PacketConn.ReadFrom(b) - } + n, _, target, err := pc.readFrom(b) + return n, target, err +} +func (pc *PktConn) readFrom(b []byte) (int, net.Addr, net.Addr, error) { buf := pool.GetBuffer(len(b)) defer pool.PutBuffer(buf) n, raddr, err := pc.PacketConn.ReadFrom(buf) if err != nil { - return n, raddr, err + return n, raddr, nil, err } tgtAddr := socks.SplitAddr(buf[:n]) if tgtAddr == nil { - return n, raddr, errors.New("can not get addr") + return n, raddr, nil, errors.New("can not get target addr") + } + + target, err := net.ResolveUDPAddr("udp", tgtAddr.String()) + if err != nil { + return n, raddr, nil, errors.New("wrong target addr") + } + + if pc.writeTo == nil { + pc.writeTo = raddr + } + + if pc.target == nil { + pc.target = make([]byte, len(tgtAddr)) + copy(pc.target, tgtAddr) } n = copy(b, buf[len(tgtAddr):n]) - - //test - if pc.writeAddr == nil { - pc.writeAddr = raddr - } - - if pc.tgtAddr == nil { - pc.tgtAddr = make([]byte, len(tgtAddr)) - copy(pc.tgtAddr, tgtAddr) - } - - return n, raddr, err + return n, raddr, target, err } // WriteTo overrides the original function from net.PacketConn func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { - if !pc.tgtHeader { - return pc.PacketConn.WriteTo(b, addr) + target := pc.target + if addr != nil { + target = socks.ParseAddr(addr.String()) + } + + if target == nil { + return 0, errors.New("invalid addr") } buf := pool.GetBytesBuffer() defer pool.PutBytesBuffer(buf) - tgtLen, _ := buf.Write(pc.tgtAddr) + tgtLen, _ := buf.Write(target) buf.Write(b) - n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeAddr) + n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeTo) if n > tgtLen { return n - tgtLen, err } diff --git a/proxy/ss/server.go b/proxy/ss/server.go index a9fe535..441409b 100644 --- a/proxy/ss/server.go +++ b/proxy/ss/server.go @@ -64,10 +64,8 @@ func (s *SS) Serve(c net.Conn) { return } - network := "tcp" dialer := s.proxy.NextDialer(tgt.String()) - - rc, err := dialer.Dial(network, tgt.String()) + rc, err := dialer.Dial("tcp", tgt.String()) if err != nil { log.F("[ss] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err) return @@ -103,10 +101,10 @@ func (s *SS) ListenAndServeUDP() { func (s *SS) ServePacket(pc net.PacketConn) { lc := s.PacketConn(pc) for { - c := NewPktConn(lc, nil, nil, true) + c := NewPktConn(lc, nil, nil) buf := pool.GetBuffer(proxy.UDPBufSize) - n, srcAddr, err := c.ReadFrom(buf) + n, srcAddr, dstAddr, err := c.readFrom(buf) if err != nil { log.F("[ssu] remote read error: %v", err) continue @@ -117,58 +115,64 @@ func (s *SS) ServePacket(pc net.PacketConn) { v, ok := nm.Load(sessionKey) if !ok || v == nil { - session = newSession(sessionKey, srcAddr, c) + session = newSession(sessionKey, srcAddr, dstAddr, c) nm.Store(sessionKey, session) go s.serveSession(session) } else { session = v.(*Session) } - session.msgCh <- buf[:n] + session.msgCh <- message{dstAddr, buf[:n]} } } func (s *SS) serveSession(session *Session) { - dstC, dialer, writeTo, err := s.proxy.DialUDP("udp", session.srcPC.tgtAddr.String()) + dstPC, dialer, err := s.proxy.DialUDP("udp", session.dst.String()) if err != nil { log.F("[ssu] remote dial error: %v", err) nm.Delete(session.key) return } - dstPC := NewPktConn(dstC, writeTo, nil, false) defer dstPC.Close() go func() { - proxy.CopyUDP(session.srcPC, session.src, dstPC, 2*time.Minute, 5*time.Second) + proxy.CopyUDP(session.srcPC, nil, dstPC, 2*time.Minute, 5*time.Second) nm.Delete(session.key) close(session.finCh) }() - log.F("[ssu] %s <-> %s via %s", session.src, session.srcPC.tgtAddr, dialer.Addr()) + log.F("[ssu] %s <-> %s via %s", session.src, session.dst, dialer.Addr()) for { select { - case p := <-session.msgCh: - _, err = dstPC.WriteTo(p, writeTo) + case msg := <-session.msgCh: + _, err = dstPC.WriteTo(msg.msg, msg.dst) if err != nil { - log.F("[ssu] writeTo %s error: %v", writeTo, err) + log.F("[ssu] writeTo %s error: %v", msg.dst, err) } - pool.PutBuffer(p) + pool.PutBuffer(msg.msg) + msg.msg = nil case <-session.finCh: return } } } +type message struct { + dst net.Addr + msg []byte +} + // Session is a udp session type Session struct { key string src net.Addr + dst net.Addr srcPC *PktConn - msgCh chan []byte + msgCh chan message finCh chan struct{} } -func newSession(key string, src net.Addr, srcPC *PktConn) *Session { - return &Session{key, src, srcPC, make(chan []byte, 32), make(chan struct{})} +func newSession(key string, src, dst net.Addr, srcPC *PktConn) *Session { + return &Session{key, src, dst, srcPC, make(chan message, 32), make(chan struct{})} } diff --git a/proxy/ssh/ssh.go b/proxy/ssh/ssh.go index dc51f0f..044238a 100644 --- a/proxy/ssh/ssh.go +++ b/proxy/ssh/ssh.go @@ -149,8 +149,8 @@ func (s *SSH) initConn() error { } // DialUDP connects to the given address via the proxy. -func (s *SSH) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) { - return nil, nil, proxy.ErrNotSupported +func (s *SSH) DialUDP(network, addr string) (pc net.PacketConn, err error) { + return nil, proxy.ErrNotSupported } func privateKeyAuth(file string) (ssh.AuthMethod, error) { diff --git a/proxy/ssr/ssr.go b/proxy/ssr/ssr.go index 257e243..bdd24b4 100644 --- a/proxy/ssr/ssr.go +++ b/proxy/ssr/ssr.go @@ -152,8 +152,8 @@ func (s *SSR) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *SSR) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - return nil, nil, proxy.ErrNotSupported +func (s *SSR) DialUDP(network, addr string) (net.PacketConn, error) { + return nil, proxy.ErrNotSupported } func init() { diff --git a/proxy/tcp/tcp.go b/proxy/tcp/tcp.go index 397ec46..cdb2cc6 100644 --- a/proxy/tcp/tcp.go +++ b/proxy/tcp/tcp.go @@ -111,6 +111,6 @@ func (s *TCP) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *TCP) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - return nil, nil, proxy.ErrNotSupported +func (s *TCP) DialUDP(network, addr string) (net.PacketConn, error) { + return nil, proxy.ErrNotSupported } diff --git a/proxy/tls/tls.go b/proxy/tls/tls.go index 683cfb2..b31e34e 100644 --- a/proxy/tls/tls.go +++ b/proxy/tls/tls.go @@ -208,8 +208,8 @@ func (s *TLS) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *TLS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - return nil, nil, proxy.ErrNotSupported +func (s *TLS) DialUDP(network, addr string) (net.PacketConn, error) { + return nil, proxy.ErrNotSupported } func init() { diff --git a/proxy/tproxy/server.go b/proxy/tproxy/server.go index 4adcd58..b14b443 100644 --- a/proxy/tproxy/server.go +++ b/proxy/tproxy/server.go @@ -85,25 +85,25 @@ func (s *TProxy) ListenAndServeUDP() { continue } - var session *Session - sessionKey := srcAddr.String() + var sess *session + sessKey := srcAddr.String() - v, ok := nm.Load(sessionKey) + v, ok := nm.Load(sessKey) if !ok || v == nil { - session = newSession(sessionKey, srcAddr, dstAddr) - nm.Store(sessionKey, session) - go s.serveSession(session) + sess = newSession(sessKey, srcAddr, dstAddr) + nm.Store(sessKey, sess) + go s.serveSession(sess) } else { - session = v.(*Session) + sess = v.(*session) } - session.msgCh <- buf[:n] + sess.msgCh <- message{dstAddr, buf[:n]} } } // serveSession serves a udp session. -func (s *TProxy) serveSession(session *Session) { - dstPC, dialer, writeTo, err := s.proxy.DialUDP("udp", session.dst.String()) +func (s *TProxy) serveSession(session *session) { + dstPC, dialer, err := s.proxy.DialUDP("udp", session.dst.String()) if err != nil { log.F("[tproxyu] dial to %s error: %v", session.dst, err) nm.Delete(session.key) @@ -111,15 +111,43 @@ func (s *TProxy) serveSession(session *Session) { } defer dstPC.Close() - srcPC, err := ListenPacket(session.dst) - if err != nil { - log.F("[tproxyu] ListenPacket as %s error: %v", session.dst, err) - return - } - defer srcPC.Close() - go func() { - proxy.CopyUDP(srcPC, session.src, dstPC, 2*time.Minute, 5*time.Second) + timeout, step := 2*time.Minute, 5*time.Second + buf := pool.GetBuffer(proxy.UDPBufSize) + defer pool.PutBuffer(buf) + + var t time.Duration + for { + if t += step; t == 0 || t > timeout { + t = timeout + } + + dstPC.SetReadDeadline(time.Now().Add(t)) + n, addr, err := dstPC.ReadFrom(buf) + if err != nil { + break + } + + tgtAddr, err := net.ResolveUDPAddr("udp", addr.String()) + if err != nil { + log.F("error in ResolveUDPAddr: %v", err) + break + } + + srcPC, err := ListenPacket(tgtAddr) + if err != nil { + log.F("[tproxyu] ListenPacket as %s error: %v", tgtAddr, err) + break + } + + _, err = srcPC.WriteTo(buf[:n], session.src) + srcPC.Close() + + if err != nil { + break + } + } + nm.Delete(session.key) close(session.finCh) }() @@ -128,26 +156,31 @@ func (s *TProxy) serveSession(session *Session) { for { select { - case p := <-session.msgCh: - _, err = dstPC.WriteTo(p, writeTo) + case msg := <-session.msgCh: + _, err = dstPC.WriteTo(msg.msg, msg.dst) if err != nil { - log.F("[tproxyu] writeTo %s error: %v", writeTo, err) + log.F("[tproxyu] writeTo %s error: %v", msg.dst, err) } - pool.PutBuffer(p) + pool.PutBuffer(msg.msg) + msg.msg = nil case <-session.finCh: return } } } -// Session is a udp session -type Session struct { +type message struct { + dst *net.UDPAddr + msg []byte +} + +type session struct { key string src, dst *net.UDPAddr - msgCh chan []byte + msgCh chan message finCh chan struct{} } -func newSession(key string, src, dst *net.UDPAddr) *Session { - return &Session{key, src, dst, make(chan []byte, 32), make(chan struct{})} +func newSession(key string, src, dst *net.UDPAddr) *session { + return &session{key, src, dst, make(chan message, 32), make(chan struct{})} } diff --git a/proxy/trojan/client.go b/proxy/trojan/client.go index b28dd2e..a83779b 100644 --- a/proxy/trojan/client.go +++ b/proxy/trojan/client.go @@ -105,8 +105,7 @@ func (s *Trojan) dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *Trojan) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { +func (s *Trojan) DialUDP(network, addr string) (net.PacketConn, error) { c, err := s.dial("udp", addr) - // TODO: check the addr in return value - return NewPktConn(c, socks.ParseAddr(addr)), nil, err + return NewPktConn(c, socks.ParseAddr(addr)), err } diff --git a/proxy/trojan/packet.go b/proxy/trojan/packet.go index 5c2b517..38a5681 100644 --- a/proxy/trojan/packet.go +++ b/proxy/trojan/packet.go @@ -13,24 +13,23 @@ import ( // PktConn is a udp Packet.Conn. type PktConn struct { net.Conn - tgtAddr socks.Addr + target socks.Addr } // NewPktConn returns a PktConn. -func NewPktConn(c net.Conn, tgtAddr socks.Addr) *PktConn { - pc := &PktConn{ - Conn: c, - tgtAddr: tgtAddr, - } - return pc +func NewPktConn(c net.Conn, target socks.Addr) *PktConn { + return &PktConn{Conn: c, target: target} } // ReadFrom implements the necessary function of net.PacketConn. -// NOTE: the underlying connection is not udp, we returned the target address here, -// it's not the server's address, do not WriteTo it. func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { // ATYP, DST.ADDR, DST.PORT - _, err := socks.ReadAddr(pc.Conn) + tgtAddr, err := socks.ReadAddr(pc.Conn) + if err != nil { + return 0, nil, err + } + + target, err := net.ResolveUDPAddr("udp", tgtAddr.String()) if err != nil { return 0, nil, err } @@ -62,16 +61,24 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { return n, nil, err } - // TODO: check the addr in return value, it's a fake packetConn so the addr is not valid - return n, pc.tgtAddr, err + return n, target, err } // WriteTo implements the necessary function of net.PacketConn. func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { + target := pc.target + if addr != nil { + target = socks.ParseAddr(addr.String()) + } + + if target == nil { + return 0, errors.New("invalid addr") + } + buf := pool.GetBytesBuffer() defer pool.PutBytesBuffer(buf) - tgtLen, _ := buf.Write(pc.tgtAddr) + tgtLen, _ := buf.Write(target) binary.Write(buf, binary.BigEndian, uint16(len(b))) buf.WriteString("\r\n") buf.Write(b) diff --git a/proxy/trojan/server.go b/proxy/trojan/server.go index 4a4c1d1..cc06bf2 100644 --- a/proxy/trojan/server.go +++ b/proxy/trojan/server.go @@ -194,22 +194,16 @@ func (s *Trojan) readHeader(r io.Reader) (byte, socks.Addr, error) { // ServeUoT serves udp over tcp requests. func (s *Trojan) ServeUoT(c net.Conn, tgt socks.Addr) { - rc, err := net.ListenPacket("udp", "") + lc, err := net.ListenPacket("udp", "") if err != nil { log.F("[trojan] UDP listen error: %v", err) return } - defer rc.Close() - - tgtAddr, err := net.ResolveUDPAddr("udp", tgt.String()) - if err != nil { - log.F("[vless] error in ResolveUDPAddr: %v", err) - return - } + defer lc.Close() pc := NewPktConn(c, tgt) - log.F("[trojan] %s <-tcp-> %s - %s <-udp-> %s", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt) + log.F("[trojan] %s <-UoT-> %s <-> %s", c.RemoteAddr(), lc.LocalAddr(), tgt) - go proxy.CopyUDP(rc, tgtAddr, pc, 2*time.Minute, 5*time.Second) - proxy.CopyUDP(pc, nil, rc, 2*time.Minute, 5*time.Second) + go proxy.CopyUDP(lc, nil, pc, 2*time.Minute, 5*time.Second) + proxy.CopyUDP(pc, nil, lc, 2*time.Minute, 5*time.Second) } diff --git a/proxy/udp/udp.go b/proxy/udp/udp.go index 80ab3a8..3cc19f0 100644 --- a/proxy/udp/udp.go +++ b/proxy/udp/udp.go @@ -1,7 +1,6 @@ package udp import ( - "fmt" "net" "net/url" "sync" @@ -22,6 +21,7 @@ func init() { // UDP struct. type UDP struct { addr string + uaddr *net.UDPAddr dialer proxy.Dialer proxy proxy.Proxy } @@ -40,7 +40,8 @@ func NewUDP(s string, d proxy.Dialer, p proxy.Proxy) (*UDP, error) { addr: u.Host, } - return t, nil + t.uaddr, err = net.ResolveUDPAddr("udp", t.addr) + return t, err } // NewUDPDialer returns a udp dialer. @@ -72,26 +73,26 @@ func (s *UDP) ListenAndServe() { continue } - var session *Session - sessionKey := srcAddr.String() + var sess *session + sessKey := srcAddr.String() - v, ok := nm.Load(sessionKey) + v, ok := nm.Load(sessKey) if !ok || v == nil { - session = newSession(sessionKey, srcAddr, c) - nm.Store(sessionKey, session) - go s.serveSession(session) + sess = newSession(sessKey, srcAddr, c) + nm.Store(sessKey, sess) + go s.serveSession(sess) } else { - session = v.(*Session) + sess = v.(*session) } - session.msgCh <- buf[:n] + sess.msgCh <- buf[:n] } } -func (s *UDP) serveSession(session *Session) { +func (s *UDP) serveSession(session *session) { // we know we are creating an udp tunnel, so the dial addr is meaningless, // we use srcAddr here to help the unix client to identify the source socket. - dstPC, dialer, writeTo, err := s.proxy.DialUDP("udp", session.src.String()) + dstPC, dialer, err := s.proxy.DialUDP("udp", session.src.String()) if err != nil { log.F("[udp] remote dial error: %v", err) nm.Delete(session.key) @@ -100,7 +101,7 @@ func (s *UDP) serveSession(session *Session) { defer dstPC.Close() go func() { - proxy.CopyUDP(session.srcPC, session.src, dstPC, 2*time.Minute, 5*time.Second) + proxy.CopyUDP(session, session.src, dstPC, 2*time.Minute, 5*time.Second) nm.Delete(session.key) close(session.finCh) }() @@ -110,9 +111,9 @@ func (s *UDP) serveSession(session *Session) { for { select { case p := <-session.msgCh: - _, err = dstPC.WriteTo(p, writeTo) + _, err = dstPC.WriteTo(p, nil) // we know it's tunnel so dst addr could be nil if err != nil { - log.F("[udp] writeTo %s error: %v", writeTo, err) + log.F("[udp] writeTo error: %v", err) } pool.PutBuffer(p) case <-session.finCh: @@ -121,17 +122,17 @@ func (s *UDP) serveSession(session *Session) { } } -// Session is a udp session -type Session struct { - key string - src net.Addr - srcPC net.PacketConn +type session struct { + key string + src *net.UDPAddr + net.PacketConn msgCh chan []byte finCh chan struct{} } -func newSession(key string, src net.Addr, srcPC net.PacketConn) *Session { - return &Session{key, src, srcPC, make(chan []byte, 32), make(chan struct{})} +func newSession(key string, src net.Addr, srcPC net.PacketConn) *session { + srcAddr, _ := net.ResolveUDPAddr("udp", src.String()) + return &session{key, srcAddr, srcPC, make(chan []byte, 32), make(chan struct{})} } // Serve serves a connection. @@ -149,10 +150,23 @@ func (s *UDP) Addr() string { // Dial connects to the address addr on the network net via the proxy. func (s *UDP) Dial(network, addr string) (net.Conn, error) { - return nil, fmt.Errorf("can not dial tcp via udp dialer: %w", proxy.ErrNotSupported) + return nil, proxy.ErrNotSupported } // 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) +func (s *UDP) DialUDP(network, addr string) (net.PacketConn, error) { + // return s.dialer.DialUDP(network, s.addr) + pc, err := s.dialer.DialUDP(network, s.addr) + return &PktConn{pc, s.uaddr}, err +} + +// PktConn . +type PktConn struct { + net.PacketConn + uaddr *net.UDPAddr +} + +// WriteTo overrides the original function from net.PacketConn. +func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) { + return pc.PacketConn.WriteTo(b, pc.uaddr) } diff --git a/proxy/unix/client.go b/proxy/unix/client.go index 2ab2a19..3396825 100644 --- a/proxy/unix/client.go +++ b/proxy/unix/client.go @@ -32,21 +32,21 @@ func (s *Unix) Dial(network, addr string) (net.Conn, error) { // DialUDP connects to the given address via the proxy. // NOTE: must be the first dialer in a chain -func (s *Unix) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { +func (s *Unix) DialUDP(network, addr string) (net.PacketConn, error) { laddru := s.addru + "_" + addr os.Remove(laddru) luaddru, err := net.ResolveUnixAddr("unixgram", laddru) if err != nil { - return nil, nil, err + return nil, err } pc, err := net.ListenUnixgram("unixgram", luaddru) if err != nil { - return nil, nil, err + return nil, err } - return &PktConn{pc, laddru, luaddru, s.uaddru}, s.uaddru, nil + return &PktConn{pc, laddru, luaddru, s.uaddru}, nil } // PktConn . diff --git a/proxy/unix/server.go b/proxy/unix/server.go index dc2d891..3ee97a8 100644 --- a/proxy/unix/server.go +++ b/proxy/unix/server.go @@ -140,7 +140,7 @@ func (s *Unix) ServePacket(pc net.PacketConn) { } func (s *Unix) serveSession(session *Session) { - dstPC, dialer, writeTo, err := s.proxy.DialUDP("udp", "") + dstPC, dialer, err := s.proxy.DialUDP("udp", "") if err != nil { log.F("[unix] remote dial error: %v", err) nm.Delete(session.key) @@ -159,9 +159,9 @@ func (s *Unix) serveSession(session *Session) { for { select { case p := <-session.msgCh: - _, err = dstPC.WriteTo(p, writeTo) + _, err = dstPC.WriteTo(p, nil) if err != nil { - log.F("[unix] writeTo %s error: %v", writeTo, err) + log.F("[unix] writeTo error: %v", err) } pool.PutBuffer(p) case <-session.finCh: diff --git a/proxy/vless/client.go b/proxy/vless/client.go index 74eead2..e30978f 100644 --- a/proxy/vless/client.go +++ b/proxy/vless/client.go @@ -39,10 +39,19 @@ func (s *VLess) dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *VLess) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { +func (s *VLess) DialUDP(network, addr string) (net.PacketConn, error) { c, err := s.dial("udp", addr) - // TODO: check the addr in return value - return NewPktConn(c), nil, err + if err != nil { + return nil, err + } + + tgtAddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + log.F("[vless] error in ResolveUDPAddr: %v", err) + return nil, err + } + + return NewPktConn(c, tgtAddr), err } // ClientConn is a vless client connection. diff --git a/proxy/vless/packet.go b/proxy/vless/packet.go index 169778a..1ca0297 100644 --- a/proxy/vless/packet.go +++ b/proxy/vless/packet.go @@ -10,31 +10,35 @@ import ( ) // PktConn is a udp Packet.Conn. -type PktConn struct{ net.Conn } +type PktConn struct { + net.Conn + target *net.UDPAddr +} // NewPktConn returns a PktConn. -func NewPktConn(c net.Conn) *PktConn { return &PktConn{Conn: c} } +func NewPktConn(c net.Conn, target *net.UDPAddr) *PktConn { + return &PktConn{Conn: c, target: target} +} // ReadFrom implements the necessary function of net.PacketConn. -// TODO: we know that we use it in proxy.CopyUDP and the length of b is enough, check it later. func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { if len(b) < 2 { - return 0, nil, errors.New("buf size is not enough") + return 0, pc.target, errors.New("buf size is not enough") } // Length if _, err := io.ReadFull(pc.Conn, b[:2]); err != nil { - return 0, nil, err + return 0, pc.target, err } length := int(binary.BigEndian.Uint16(b[:2])) if len(b) < length { - return 0, nil, errors.New("buf size is not enough") + return 0, pc.target, errors.New("buf size is not enough") } // Payload n, err := io.ReadFull(pc.Conn, b[:length]) - return n, nil, err + return n, pc.target, err } // WriteTo implements the necessary function of net.PacketConn. diff --git a/proxy/vless/server.go b/proxy/vless/server.go index 079472a..eb78084 100644 --- a/proxy/vless/server.go +++ b/proxy/vless/server.go @@ -162,10 +162,10 @@ func (s *VLess) ServeUoT(c net.Conn, tgt string) { return } - pc := NewPktConn(c) - log.F("[vless] %s <-tcp-> %s - %s <-udp-> %s", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt) + pc := NewPktConn(c, tgtAddr) + log.F("[vless] %s <-UoT-> %s <-> %s", c.RemoteAddr(), rc.LocalAddr(), tgt) - go proxy.CopyUDP(rc, tgtAddr, pc, 2*time.Minute, 5*time.Second) + go proxy.CopyUDP(rc, nil, pc, 2*time.Minute, 5*time.Second) proxy.CopyUDP(pc, nil, rc, 2*time.Minute, 5*time.Second) } diff --git a/proxy/vmess/packet.go b/proxy/vmess/packet.go index b44e30f..ca4670d 100644 --- a/proxy/vmess/packet.go +++ b/proxy/vmess/packet.go @@ -5,15 +5,20 @@ import ( ) // PktConn is a udp Packet.Conn. -type PktConn struct{ net.Conn } +type PktConn struct { + net.Conn + target *net.UDPAddr +} // NewPktConn returns a PktConn. -func NewPktConn(c net.Conn) *PktConn { return &PktConn{Conn: c} } +func NewPktConn(c net.Conn, target *net.UDPAddr) *PktConn { + return &PktConn{Conn: c, target: target} +} // ReadFrom implements the necessary function of net.PacketConn. func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) { n, err := pc.Read(b) - return n, nil, err + return n, pc.target, err } // WriteTo implements the necessary function of net.PacketConn. diff --git a/proxy/vmess/vmess.go b/proxy/vmess/vmess.go index 6f07f3b..60a20d6 100644 --- a/proxy/vmess/vmess.go +++ b/proxy/vmess/vmess.go @@ -98,16 +98,23 @@ func (s *VMess) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *VMess) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { +func (s *VMess) DialUDP(network, addr string) (net.PacketConn, error) { + tgtAddr, err := net.ResolveUDPAddr("udp", addr) + if err != nil { + log.F("[vmess] error in ResolveUDPAddr: %v", err) + return nil, err + } + rc, err := s.dialer.Dial("tcp", s.addr) if err != nil { - return nil, nil, err + return nil, err } rc, err = s.client.NewConn(rc, addr, CmdUDP) if err != nil { - return nil, nil, err + return nil, err } - return NewPktConn(rc), nil, err + + return NewPktConn(rc, tgtAddr), err } func init() { diff --git a/proxy/ws/client.go b/proxy/ws/client.go index 0c5bdd7..948f126 100644 --- a/proxy/ws/client.go +++ b/proxy/ws/client.go @@ -79,8 +79,8 @@ func (s *WS) Dial(network, addr string) (net.Conn, error) { } // DialUDP connects to the given address via the proxy. -func (s *WS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) { - return nil, nil, proxy.ErrNotSupported +func (s *WS) DialUDP(network, addr string) (net.PacketConn, error) { + return nil, proxy.ErrNotSupported } // ClientConn is a connection to ws server. diff --git a/rule/group.go b/rule/group.go index 7aaf391..fc9607b 100644 --- a/rule/group.go +++ b/rule/group.go @@ -109,10 +109,10 @@ func (p *FwdrGroup) Dial(network, addr string) (net.Conn, proxy.Dialer, error) { } // DialUDP connects to the given address. -func (p *FwdrGroup) DialUDP(network, addr string) (pc net.PacketConn, dialer proxy.UDPDialer, writeTo net.Addr, err error) { +func (p *FwdrGroup) DialUDP(network, addr string) (pc net.PacketConn, dialer proxy.UDPDialer, err error) { nd := p.NextDialer(addr) - pc, wt, err := nd.DialUDP(network, addr) - return pc, nd, wt, err + pc, err = nd.DialUDP(network, addr) + return pc, nd, err } // NextDialer returns the next dialer. diff --git a/rule/proxy.go b/rule/proxy.go index b9a8bf6..495b83e 100644 --- a/rule/proxy.go +++ b/rule/proxy.go @@ -73,7 +73,7 @@ func (p *Proxy) Dial(network, addr string) (net.Conn, proxy.Dialer, error) { } // DialUDP connects to the given address via the proxy. -func (p *Proxy) DialUDP(network, addr string) (pc net.PacketConn, dialer proxy.UDPDialer, writeTo net.Addr, err error) { +func (p *Proxy) DialUDP(network, addr string) (pc net.PacketConn, dialer proxy.UDPDialer, err error) { return p.findDialer(addr).DialUDP(network, addr) }