proxy: nat fullcone support for tproxy, trojan, ss, socks5 (fix #253)

This commit is contained in:
nadoo 2022-03-11 19:08:07 +08:00
parent d68f361c35
commit a98995e2cb
42 changed files with 366 additions and 280 deletions

View File

@ -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

View File

@ -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

View File

@ -1,5 +1,5 @@
# Build Stage
FROM golang:1.18beta2-alpine AS build-env
FROM golang:1.18 AS build-env
ADD . /src

View File

@ -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

View File

@ -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"

4
go.mod
View File

@ -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 (

9
go.sum
View File

@ -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=

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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
}

View File

@ -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) {

View File

@ -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() {

View File

@ -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

View File

@ -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")
}

View File

@ -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 {

View File

@ -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) {

View File

@ -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,

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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
}

View File

@ -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{})}
}

View File

@ -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) {

View File

@ -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() {

View File

@ -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
}

View File

@ -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() {

View File

@ -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{})}
}

View File

@ -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
}

View File

@ -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)

View File

@ -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)
}

View File

@ -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 {
type session struct {
key string
src net.Addr
srcPC net.PacketConn
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)
}

View File

@ -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 .

View File

@ -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:

View File

@ -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.

View File

@ -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.

View File

@ -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)
}

View File

@ -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.

View File

@ -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() {

View File

@ -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.

View File

@ -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.

View File

@ -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)
}