mirror of
https://github.com/nadoo/glider.git
synced 2025-02-23 01:15:41 +08:00
proxy: nat fullcone support for tproxy, trojan, ss, socks5 (fix #253)
This commit is contained in:
parent
d68f361c35
commit
a98995e2cb
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@ -98,7 +98,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Docker - Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v1
|
uses: docker/setup-qemu-action@v1
|
||||||
|
|
||||||
- name: Docker - Set up Buildx
|
- name: Docker - Set up Buildx
|
||||||
|
2
.github/workflows/stale.yml
vendored
2
.github/workflows/stale.yml
vendored
@ -7,7 +7,7 @@ jobs:
|
|||||||
stale:
|
stale:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@v4
|
- uses: actions/stale@v5
|
||||||
with:
|
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.'
|
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
|
days-before-stale: 90
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Build Stage
|
# Build Stage
|
||||||
FROM golang:1.18beta2-alpine AS build-env
|
FROM golang:1.18 AS build-env
|
||||||
|
|
||||||
ADD . /src
|
ADD . /src
|
||||||
|
|
||||||
|
@ -61,7 +61,7 @@ listen=socks5://:1080
|
|||||||
# listen=tls://:443?cert=crtFilePath&key=keyFilePath,ss://AEAD_CHACHA20_POLY1305:pass@
|
# listen=tls://:443?cert=crtFilePath&key=keyFilePath,ss://AEAD_CHACHA20_POLY1305:pass@
|
||||||
|
|
||||||
# socks5 over unix domain socket
|
# socks5 over unix domain socket
|
||||||
# listen=unix:///tmp/glider.socket,socks5://
|
# listen=unix:///dev/shm/socket,socks5://
|
||||||
|
|
||||||
# socks5 over kcp
|
# socks5 over kcp
|
||||||
# listen=kcp://aes:key@127.0.0.1:8444?dataShards=10&parityShards=3&mode=fast,socks5://
|
# 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@
|
# forward=simple-obfs://1.1.1.1:443?type=tls&host=apple.com,ss://AEAD_CHACHA20_POLY1305:pass@
|
||||||
|
|
||||||
# socks5 over unix domain socket
|
# socks5 over unix domain socket
|
||||||
# forward=unix:///tmp/glider.socket,socks5://
|
# forward=unix:///dev/shm/socket,socks5://
|
||||||
|
|
||||||
# FORWARDER CHAIN
|
# FORWARDER CHAIN
|
||||||
# ---------------
|
# ---------------
|
||||||
@ -254,6 +254,7 @@ dnsrecord=www.example.com/2606:2800:220:1:248:1893:25c8:1946
|
|||||||
|
|
||||||
# SERVICES
|
# SERVICES
|
||||||
# service=dhcpd,INTERFACE,START_IP,END_IP,LEASE_MINUTES[,MAC=IP,MAC=IP...]
|
# 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.:
|
# e.g.:
|
||||||
# service=dhcpd,eth1,192.168.1.100,192.168.1.199,720
|
# 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
|
# 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
|
||||||
|
@ -7,12 +7,14 @@ import (
|
|||||||
// comment out the protocols you don't need to make the compiled binary smaller.
|
// 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/http"
|
||||||
_ "github.com/nadoo/glider/proxy/kcp"
|
_ "github.com/nadoo/glider/proxy/kcp"
|
||||||
|
|
||||||
_ "github.com/nadoo/glider/proxy/mixed"
|
_ "github.com/nadoo/glider/proxy/mixed"
|
||||||
_ "github.com/nadoo/glider/proxy/obfs"
|
_ "github.com/nadoo/glider/proxy/obfs"
|
||||||
_ "github.com/nadoo/glider/proxy/pxyproto"
|
_ "github.com/nadoo/glider/proxy/pxyproto"
|
||||||
_ "github.com/nadoo/glider/proxy/reject"
|
_ "github.com/nadoo/glider/proxy/reject"
|
||||||
_ "github.com/nadoo/glider/proxy/smux"
|
_ "github.com/nadoo/glider/proxy/smux"
|
||||||
_ "github.com/nadoo/glider/proxy/socks4"
|
_ "github.com/nadoo/glider/proxy/socks4"
|
||||||
|
|
||||||
_ "github.com/nadoo/glider/proxy/socks5"
|
_ "github.com/nadoo/glider/proxy/socks5"
|
||||||
_ "github.com/nadoo/glider/proxy/ss"
|
_ "github.com/nadoo/glider/proxy/ss"
|
||||||
_ "github.com/nadoo/glider/proxy/ssh"
|
_ "github.com/nadoo/glider/proxy/ssh"
|
||||||
@ -20,6 +22,7 @@ import (
|
|||||||
_ "github.com/nadoo/glider/proxy/tcp"
|
_ "github.com/nadoo/glider/proxy/tcp"
|
||||||
_ "github.com/nadoo/glider/proxy/tls"
|
_ "github.com/nadoo/glider/proxy/tls"
|
||||||
_ "github.com/nadoo/glider/proxy/trojan"
|
_ "github.com/nadoo/glider/proxy/trojan"
|
||||||
|
|
||||||
_ "github.com/nadoo/glider/proxy/udp"
|
_ "github.com/nadoo/glider/proxy/udp"
|
||||||
_ "github.com/nadoo/glider/proxy/vless"
|
_ "github.com/nadoo/glider/proxy/vless"
|
||||||
_ "github.com/nadoo/glider/proxy/vmess"
|
_ "github.com/nadoo/glider/proxy/vmess"
|
||||||
|
4
go.mod
4
go.mod
@ -11,8 +11,8 @@ require (
|
|||||||
github.com/nadoo/conflag v0.3.1
|
github.com/nadoo/conflag v0.3.1
|
||||||
github.com/nadoo/ipset v0.4.1-0.20220218075046-ca3cdce74266
|
github.com/nadoo/ipset v0.4.1-0.20220218075046-ca3cdce74266
|
||||||
github.com/xtaci/kcp-go/v5 v5.6.1
|
github.com/xtaci/kcp-go/v5 v5.6.1
|
||||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292
|
golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70
|
||||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9
|
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
9
go.sum
9
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/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/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.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 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.6/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||||
github.com/klauspost/cpuid/v2 v2.0.11 h1:i2lw1Pm7Yi/4O6XCSyJWqEHI2MDw2FzUK6o/D21xn2A=
|
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-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-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-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-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
|
||||||
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
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/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-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
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-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-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-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-20220310020820-b874c991c1a5 h1:y/woIyUBFbpQGKS0u1aHF/40WUDnek3fPOyD08H5Vng=
|
||||||
golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
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/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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
|
@ -71,11 +71,9 @@ func (a Addr) String() string {
|
|||||||
// Network returns network name. Implements net.Addr interface.
|
// Network returns network name. Implements net.Addr interface.
|
||||||
func (a Addr) Network() string { return "socks" }
|
func (a Addr) Network() string { return "socks" }
|
||||||
|
|
||||||
// ReadAddrBuf reads just enough bytes from r to get a valid Addr.
|
// ReadAddr reads just enough bytes from r to get a valid Addr.
|
||||||
func ReadAddrBuf(r io.Reader, b []byte) (Addr, error) {
|
func ReadAddr(r io.Reader) (Addr, error) {
|
||||||
if len(b) < MaxAddrLen {
|
b := make([]byte, MaxAddrLen)
|
||||||
return nil, io.ErrShortBuffer
|
|
||||||
}
|
|
||||||
_, err := io.ReadFull(r, b[:1]) // read 1st byte for address type
|
_, err := io.ReadFull(r, b[:1]) // read 1st byte for address type
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -100,11 +98,6 @@ func ReadAddrBuf(r io.Reader, b []byte) (Addr, error) {
|
|||||||
return nil, Errors[8]
|
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.
|
// SplitAddr slices a SOCKS address from beginning of b. Returns nil if failed.
|
||||||
func SplitAddr(b []byte) Addr {
|
func SplitAddr(b []byte) Addr {
|
||||||
addrLen := 1
|
addrLen := 1
|
||||||
|
@ -33,7 +33,7 @@ type UDPDialer interface {
|
|||||||
Addr() string
|
Addr() string
|
||||||
|
|
||||||
// DialUDP connects to the given address
|
// 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.
|
// DialerCreator is a function to create dialers.
|
||||||
|
@ -7,7 +7,6 @@ import (
|
|||||||
"net/netip"
|
"net/netip"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/nadoo/glider/pkg/log"
|
|
||||||
"github.com/nadoo/glider/pkg/sockopt"
|
"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.
|
// 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
|
var la string
|
||||||
if d.ip != nil {
|
if d.ip != nil {
|
||||||
la = net.JoinHostPort(d.ip.String(), "0")
|
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))
|
lc.Control = sockopt.Control(sockopt.Bind(d.iface))
|
||||||
}
|
}
|
||||||
|
|
||||||
pc, err := lc.ListenPacket(context.Background(), network, la)
|
return 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IFaceIPs returns ip addresses according to the specified interface.
|
// IFaceIPs returns ip addresses according to the specified interface.
|
||||||
|
@ -76,6 +76,6 @@ func (s *HTTP) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *HTTP) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
|
func (s *HTTP) DialUDP(network, addr string) (pc net.PacketConn, err error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
@ -239,8 +239,8 @@ func (s *KCP) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *KCP) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *KCP) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *KCP) setParams(c *kcp.UDPSession) {
|
func (s *KCP) setParams(c *kcp.UDPSession) {
|
||||||
|
@ -106,8 +106,8 @@ func (s *Obfs) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *Obfs) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *Obfs) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -8,7 +8,7 @@ type Proxy interface {
|
|||||||
Dial(network, addr string) (c net.Conn, dialer Dialer, err error)
|
Dial(network, addr string) (c net.Conn, dialer Dialer, err error)
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// 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.
|
// Get the dialer by dstAddr.
|
||||||
NextDialer(dstAddr string) Dialer
|
NextDialer(dstAddr string) Dialer
|
||||||
|
@ -34,6 +34,6 @@ func (s *Reject) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *Reject) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *Reject) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return nil, nil, errors.New("REJECT")
|
return nil, errors.New("REJECT")
|
||||||
}
|
}
|
||||||
|
@ -64,8 +64,8 @@ func (s *SmuxClient) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *SmuxClient) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *SmuxClient) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SmuxClient) initConn() error {
|
func (s *SmuxClient) initConn() error {
|
||||||
|
@ -88,8 +88,8 @@ func (s *SOCKS4) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *SOCKS4) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
|
func (s *SOCKS4) DialUDP(network, addr string) (pc net.PacketConn, err error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SOCKS4) lookupIP(host string) (ip net.IP, err error) {
|
func (s *SOCKS4) lookupIP(host string) (ip net.IP, err error) {
|
||||||
|
@ -63,17 +63,17 @@ func (s *Socks5) dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// 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)
|
c, err := s.dial("tcp", s.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[socks5] dialudp dial tcp to %s error: %s", s.addr, err)
|
log.F("[socks5] dialudp dial tcp to %s error: %s", s.addr, err)
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var uAddr socks.Addr
|
var uAddr socks.Addr
|
||||||
if uAddr, err = s.connect(c, addr, socks.CmdUDPAssociate); err != nil {
|
if uAddr, err = s.connect(c, addr, socks.CmdUDPAssociate); err != nil {
|
||||||
c.Close()
|
c.Close()
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := pool.GetBuffer(socks.MaxAddrLen)
|
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)
|
uAddress = net.JoinHostPort(h, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
pc, nextHop, err := s.dialer.DialUDP(network, uAddress)
|
pc, err = s.dialer.DialUDP(network, uAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[socks5] dialudp to %s error: %s", uAddress, err)
|
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)
|
writeTo, err := net.ResolveUDPAddr("udp", uAddress)
|
||||||
return pkc, nextHop, err
|
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,
|
// connect takes an existing connection to a socks5 proxy server,
|
||||||
|
@ -11,22 +11,17 @@ import (
|
|||||||
// PktConn .
|
// PktConn .
|
||||||
type PktConn struct {
|
type PktConn struct {
|
||||||
net.PacketConn
|
net.PacketConn
|
||||||
|
|
||||||
writeAddr net.Addr // write to and read from addr
|
|
||||||
|
|
||||||
tgtAddr socks.Addr
|
|
||||||
tgtHeader bool
|
|
||||||
|
|
||||||
ctrlConn net.Conn // tcp control conn
|
ctrlConn net.Conn // tcp control conn
|
||||||
|
writeTo net.Addr // write to and read from addr
|
||||||
|
target socks.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPktConn returns a PktConn.
|
// NewPktConn returns a PktConn, the writeAddr must be *net.UDPAddr or *net.UnixAddr.
|
||||||
func NewPktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr socks.Addr, tgtHeader bool, ctrlConn net.Conn) *PktConn {
|
func NewPktConn(c net.PacketConn, writeAddr net.Addr, targetAddr socks.Addr, ctrlConn net.Conn) *PktConn {
|
||||||
pc := &PktConn{
|
pc := &PktConn{
|
||||||
PacketConn: c,
|
PacketConn: c,
|
||||||
writeAddr: writeAddr,
|
writeTo: writeAddr,
|
||||||
tgtAddr: tgtAddr,
|
target: targetAddr,
|
||||||
tgtHeader: tgtHeader,
|
|
||||||
ctrlConn: ctrlConn,
|
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.
|
// ReadFrom overrides the original function from net.PacketConn.
|
||||||
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||||
if !pc.tgtHeader {
|
n, _, target, err := pc.readFrom(b)
|
||||||
return pc.PacketConn.ReadFrom(b)
|
return n, target, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pc *PktConn) readFrom(b []byte) (int, net.Addr, net.Addr, error) {
|
||||||
buf := pool.GetBuffer(len(b))
|
buf := pool.GetBuffer(len(b))
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBuffer(buf)
|
||||||
|
|
||||||
n, raddr, err := pc.PacketConn.ReadFrom(buf)
|
n, raddr, err := pc.PacketConn.ReadFrom(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, raddr, err
|
return n, raddr, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if n < 3 {
|
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
|
// 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])
|
tgtAddr := socks.SplitAddr(buf[3:n])
|
||||||
if tgtAddr == nil {
|
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])
|
n = copy(b, buf[3+len(tgtAddr):n])
|
||||||
|
return n, raddr, target, err
|
||||||
//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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo overrides the original function from net.PacketConn.
|
// WriteTo overrides the original function from net.PacketConn.
|
||||||
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||||
if !pc.tgtHeader {
|
target := pc.target
|
||||||
return pc.PacketConn.WriteTo(b, addr)
|
if addr != nil {
|
||||||
|
target = socks.ParseAddr(addr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if target == nil {
|
||||||
|
return 0, errors.New("invalid addr")
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := pool.GetBytesBuffer()
|
buf := pool.GetBytesBuffer()
|
||||||
defer pool.PutBytesBuffer(buf)
|
defer pool.PutBytesBuffer(buf)
|
||||||
|
|
||||||
buf.Write([]byte{0, 0, 0})
|
buf.Write([]byte{0, 0, 0})
|
||||||
tgtLen, _ := buf.Write(pc.tgtAddr)
|
tgtLen, _ := buf.Write(target)
|
||||||
buf.Write(b)
|
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 {
|
if n > tgtLen+3 {
|
||||||
return n - tgtLen - 3, err
|
return n - tgtLen - 3, err
|
||||||
}
|
}
|
||||||
|
@ -116,10 +116,10 @@ func (s *Socks5) ListenAndServeUDP() {
|
|||||||
// ServePacket implementes proxy.PacketServer.
|
// ServePacket implementes proxy.PacketServer.
|
||||||
func (s *Socks5) ServePacket(pc net.PacketConn) {
|
func (s *Socks5) ServePacket(pc net.PacketConn) {
|
||||||
for {
|
for {
|
||||||
c := NewPktConn(pc, nil, nil, true, nil)
|
c := NewPktConn(pc, nil, nil, nil)
|
||||||
buf := pool.GetBuffer(proxy.UDPBufSize)
|
buf := pool.GetBuffer(proxy.UDPBufSize)
|
||||||
|
|
||||||
n, srcAddr, err := c.ReadFrom(buf)
|
n, srcAddr, dstAddr, err := c.readFrom(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[socks5u] remote read error: %v", err)
|
log.F("[socks5u] remote read error: %v", err)
|
||||||
continue
|
continue
|
||||||
@ -130,60 +130,66 @@ func (s *Socks5) ServePacket(pc net.PacketConn) {
|
|||||||
|
|
||||||
v, ok := nm.Load(sessionKey)
|
v, ok := nm.Load(sessionKey)
|
||||||
if !ok || v == nil {
|
if !ok || v == nil {
|
||||||
session = newSession(sessionKey, srcAddr, c)
|
session = newSession(sessionKey, srcAddr, dstAddr, c)
|
||||||
nm.Store(sessionKey, session)
|
nm.Store(sessionKey, session)
|
||||||
go s.serveSession(session)
|
go s.serveSession(session)
|
||||||
} else {
|
} else {
|
||||||
session = v.(*Session)
|
session = v.(*Session)
|
||||||
}
|
}
|
||||||
|
|
||||||
session.msgCh <- buf[:n]
|
session.msgCh <- message{dstAddr, buf[:n]}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Socks5) serveSession(session *Session) {
|
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 {
|
if err != nil {
|
||||||
log.F("[socks5u] remote dial error: %v", err)
|
log.F("[socks5u] remote dial error: %v", err)
|
||||||
nm.Delete(session.key)
|
nm.Delete(session.key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dstPC := NewPktConn(dstC, writeTo, nil, false, nil)
|
|
||||||
defer dstPC.Close()
|
defer dstPC.Close()
|
||||||
|
|
||||||
go func() {
|
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)
|
nm.Delete(session.key)
|
||||||
close(session.finCh)
|
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 {
|
for {
|
||||||
select {
|
select {
|
||||||
case p := <-session.msgCh:
|
case msg := <-session.msgCh:
|
||||||
_, err = dstPC.WriteTo(p, writeTo)
|
_, err = dstPC.WriteTo(msg.msg, msg.dst)
|
||||||
if err != nil {
|
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:
|
case <-session.finCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type message struct {
|
||||||
|
dst net.Addr
|
||||||
|
msg []byte
|
||||||
|
}
|
||||||
|
|
||||||
// Session is a udp session
|
// Session is a udp session
|
||||||
type Session struct {
|
type Session struct {
|
||||||
key string
|
key string
|
||||||
src net.Addr
|
src net.Addr
|
||||||
|
dst net.Addr
|
||||||
srcPC *PktConn
|
srcPC *PktConn
|
||||||
msgCh chan []byte
|
msgCh chan message
|
||||||
finCh chan struct{}
|
finCh chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSession(key string, src net.Addr, srcPC *PktConn) *Session {
|
func newSession(key string, src, dst net.Addr, srcPC *PktConn) *Session {
|
||||||
return &Session{key, src, srcPC, make(chan []byte, 32), make(chan struct{})}
|
return &Session{key, src, dst, srcPC, make(chan message, 32), make(chan struct{})}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handshake fast-tracks SOCKS initialization to get target address to connect.
|
// 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
|
return nil, err
|
||||||
}
|
}
|
||||||
cmd := buf[1]
|
cmd := buf[1]
|
||||||
addr, err := socks.ReadAddrBuf(c, buf)
|
addr, err := socks.ReadAddr(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -45,13 +45,19 @@ func (s *SS) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *SS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *SS) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
pc, nextHop, err := s.dialer.DialUDP(network, s.addr)
|
pc, err := s.dialer.DialUDP(network, s.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[ss] dialudp to %s error: %s", s.addr, err)
|
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)
|
writeTo, err := net.ResolveUDPAddr("udp", s.addr)
|
||||||
return pkc, nextHop, err
|
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
|
||||||
}
|
}
|
||||||
|
@ -11,70 +11,71 @@ import (
|
|||||||
// PktConn .
|
// PktConn .
|
||||||
type PktConn struct {
|
type PktConn struct {
|
||||||
net.PacketConn
|
net.PacketConn
|
||||||
|
writeTo net.Addr
|
||||||
writeAddr net.Addr // write to and read from addr
|
target socks.Addr // if target is not nil, it may be a tunnel
|
||||||
|
|
||||||
tgtAddr socks.Addr
|
|
||||||
tgtHeader bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPktConn returns a PktConn
|
// NewPktConn returns a PktConn, the writeAddr must be *net.UDPAddr or *net.UnixAddr.
|
||||||
func NewPktConn(c net.PacketConn, writeAddr net.Addr, tgtAddr socks.Addr, tgtHeader bool) *PktConn {
|
func NewPktConn(c net.PacketConn, writeAddr net.Addr, targetAddr socks.Addr) *PktConn {
|
||||||
pc := &PktConn{
|
return &PktConn{PacketConn: c, writeTo: writeAddr, target: targetAddr}
|
||||||
PacketConn: c,
|
|
||||||
writeAddr: writeAddr,
|
|
||||||
tgtAddr: tgtAddr,
|
|
||||||
tgtHeader: tgtHeader}
|
|
||||||
return pc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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) {
|
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||||
if !pc.tgtHeader {
|
n, _, target, err := pc.readFrom(b)
|
||||||
return pc.PacketConn.ReadFrom(b)
|
return n, target, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (pc *PktConn) readFrom(b []byte) (int, net.Addr, net.Addr, error) {
|
||||||
buf := pool.GetBuffer(len(b))
|
buf := pool.GetBuffer(len(b))
|
||||||
defer pool.PutBuffer(buf)
|
defer pool.PutBuffer(buf)
|
||||||
|
|
||||||
n, raddr, err := pc.PacketConn.ReadFrom(buf)
|
n, raddr, err := pc.PacketConn.ReadFrom(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return n, raddr, err
|
return n, raddr, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
tgtAddr := socks.SplitAddr(buf[:n])
|
tgtAddr := socks.SplitAddr(buf[:n])
|
||||||
if tgtAddr == nil {
|
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])
|
n = copy(b, buf[len(tgtAddr):n])
|
||||||
|
return n, raddr, target, err
|
||||||
//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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo overrides the original function from net.PacketConn
|
// WriteTo overrides the original function from net.PacketConn
|
||||||
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
||||||
if !pc.tgtHeader {
|
target := pc.target
|
||||||
return pc.PacketConn.WriteTo(b, addr)
|
if addr != nil {
|
||||||
|
target = socks.ParseAddr(addr.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
if target == nil {
|
||||||
|
return 0, errors.New("invalid addr")
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := pool.GetBytesBuffer()
|
buf := pool.GetBytesBuffer()
|
||||||
defer pool.PutBytesBuffer(buf)
|
defer pool.PutBytesBuffer(buf)
|
||||||
|
|
||||||
tgtLen, _ := buf.Write(pc.tgtAddr)
|
tgtLen, _ := buf.Write(target)
|
||||||
buf.Write(b)
|
buf.Write(b)
|
||||||
|
|
||||||
n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeAddr)
|
n, err := pc.PacketConn.WriteTo(buf.Bytes(), pc.writeTo)
|
||||||
if n > tgtLen {
|
if n > tgtLen {
|
||||||
return n - tgtLen, err
|
return n - tgtLen, err
|
||||||
}
|
}
|
||||||
|
@ -64,10 +64,8 @@ func (s *SS) Serve(c net.Conn) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
network := "tcp"
|
|
||||||
dialer := s.proxy.NextDialer(tgt.String())
|
dialer := s.proxy.NextDialer(tgt.String())
|
||||||
|
rc, err := dialer.Dial("tcp", tgt.String())
|
||||||
rc, err := dialer.Dial(network, tgt.String())
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[ss] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err)
|
log.F("[ss] %s <-> %s via %s, error in dial: %v", c.RemoteAddr(), tgt, dialer.Addr(), err)
|
||||||
return
|
return
|
||||||
@ -103,10 +101,10 @@ func (s *SS) ListenAndServeUDP() {
|
|||||||
func (s *SS) ServePacket(pc net.PacketConn) {
|
func (s *SS) ServePacket(pc net.PacketConn) {
|
||||||
lc := s.PacketConn(pc)
|
lc := s.PacketConn(pc)
|
||||||
for {
|
for {
|
||||||
c := NewPktConn(lc, nil, nil, true)
|
c := NewPktConn(lc, nil, nil)
|
||||||
buf := pool.GetBuffer(proxy.UDPBufSize)
|
buf := pool.GetBuffer(proxy.UDPBufSize)
|
||||||
|
|
||||||
n, srcAddr, err := c.ReadFrom(buf)
|
n, srcAddr, dstAddr, err := c.readFrom(buf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[ssu] remote read error: %v", err)
|
log.F("[ssu] remote read error: %v", err)
|
||||||
continue
|
continue
|
||||||
@ -117,58 +115,64 @@ func (s *SS) ServePacket(pc net.PacketConn) {
|
|||||||
|
|
||||||
v, ok := nm.Load(sessionKey)
|
v, ok := nm.Load(sessionKey)
|
||||||
if !ok || v == nil {
|
if !ok || v == nil {
|
||||||
session = newSession(sessionKey, srcAddr, c)
|
session = newSession(sessionKey, srcAddr, dstAddr, c)
|
||||||
nm.Store(sessionKey, session)
|
nm.Store(sessionKey, session)
|
||||||
go s.serveSession(session)
|
go s.serveSession(session)
|
||||||
} else {
|
} else {
|
||||||
session = v.(*Session)
|
session = v.(*Session)
|
||||||
}
|
}
|
||||||
|
|
||||||
session.msgCh <- buf[:n]
|
session.msgCh <- message{dstAddr, buf[:n]}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SS) serveSession(session *Session) {
|
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 {
|
if err != nil {
|
||||||
log.F("[ssu] remote dial error: %v", err)
|
log.F("[ssu] remote dial error: %v", err)
|
||||||
nm.Delete(session.key)
|
nm.Delete(session.key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dstPC := NewPktConn(dstC, writeTo, nil, false)
|
|
||||||
defer dstPC.Close()
|
defer dstPC.Close()
|
||||||
|
|
||||||
go func() {
|
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)
|
nm.Delete(session.key)
|
||||||
close(session.finCh)
|
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 {
|
for {
|
||||||
select {
|
select {
|
||||||
case p := <-session.msgCh:
|
case msg := <-session.msgCh:
|
||||||
_, err = dstPC.WriteTo(p, writeTo)
|
_, err = dstPC.WriteTo(msg.msg, msg.dst)
|
||||||
if err != nil {
|
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:
|
case <-session.finCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type message struct {
|
||||||
|
dst net.Addr
|
||||||
|
msg []byte
|
||||||
|
}
|
||||||
|
|
||||||
// Session is a udp session
|
// Session is a udp session
|
||||||
type Session struct {
|
type Session struct {
|
||||||
key string
|
key string
|
||||||
src net.Addr
|
src net.Addr
|
||||||
|
dst net.Addr
|
||||||
srcPC *PktConn
|
srcPC *PktConn
|
||||||
msgCh chan []byte
|
msgCh chan message
|
||||||
finCh chan struct{}
|
finCh chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSession(key string, src net.Addr, srcPC *PktConn) *Session {
|
func newSession(key string, src, dst net.Addr, srcPC *PktConn) *Session {
|
||||||
return &Session{key, src, srcPC, make(chan []byte, 32), make(chan struct{})}
|
return &Session{key, src, dst, srcPC, make(chan message, 32), make(chan struct{})}
|
||||||
}
|
}
|
||||||
|
@ -149,8 +149,8 @@ func (s *SSH) initConn() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *SSH) DialUDP(network, addr string) (pc net.PacketConn, writeTo net.Addr, err error) {
|
func (s *SSH) DialUDP(network, addr string) (pc net.PacketConn, err error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func privateKeyAuth(file string) (ssh.AuthMethod, error) {
|
func privateKeyAuth(file string) (ssh.AuthMethod, error) {
|
||||||
|
@ -152,8 +152,8 @@ func (s *SSR) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *SSR) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *SSR) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -111,6 +111,6 @@ func (s *TCP) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *TCP) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *TCP) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
@ -208,8 +208,8 @@ func (s *TLS) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *TLS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *TLS) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -85,25 +85,25 @@ func (s *TProxy) ListenAndServeUDP() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var session *Session
|
var sess *session
|
||||||
sessionKey := srcAddr.String()
|
sessKey := srcAddr.String()
|
||||||
|
|
||||||
v, ok := nm.Load(sessionKey)
|
v, ok := nm.Load(sessKey)
|
||||||
if !ok || v == nil {
|
if !ok || v == nil {
|
||||||
session = newSession(sessionKey, srcAddr, dstAddr)
|
sess = newSession(sessKey, srcAddr, dstAddr)
|
||||||
nm.Store(sessionKey, session)
|
nm.Store(sessKey, sess)
|
||||||
go s.serveSession(session)
|
go s.serveSession(sess)
|
||||||
} else {
|
} else {
|
||||||
session = v.(*Session)
|
sess = v.(*session)
|
||||||
}
|
}
|
||||||
|
|
||||||
session.msgCh <- buf[:n]
|
sess.msgCh <- message{dstAddr, buf[:n]}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// serveSession serves a udp session.
|
// serveSession serves a udp session.
|
||||||
func (s *TProxy) serveSession(session *Session) {
|
func (s *TProxy) serveSession(session *session) {
|
||||||
dstPC, dialer, writeTo, err := s.proxy.DialUDP("udp", session.dst.String())
|
dstPC, dialer, err := s.proxy.DialUDP("udp", session.dst.String())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[tproxyu] dial to %s error: %v", session.dst, err)
|
log.F("[tproxyu] dial to %s error: %v", session.dst, err)
|
||||||
nm.Delete(session.key)
|
nm.Delete(session.key)
|
||||||
@ -111,15 +111,43 @@ func (s *TProxy) serveSession(session *Session) {
|
|||||||
}
|
}
|
||||||
defer dstPC.Close()
|
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() {
|
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)
|
nm.Delete(session.key)
|
||||||
close(session.finCh)
|
close(session.finCh)
|
||||||
}()
|
}()
|
||||||
@ -128,26 +156,31 @@ func (s *TProxy) serveSession(session *Session) {
|
|||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case p := <-session.msgCh:
|
case msg := <-session.msgCh:
|
||||||
_, err = dstPC.WriteTo(p, writeTo)
|
_, err = dstPC.WriteTo(msg.msg, msg.dst)
|
||||||
if err != nil {
|
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:
|
case <-session.finCh:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Session is a udp session
|
type message struct {
|
||||||
type Session struct {
|
dst *net.UDPAddr
|
||||||
|
msg []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
type session struct {
|
||||||
key string
|
key string
|
||||||
src, dst *net.UDPAddr
|
src, dst *net.UDPAddr
|
||||||
msgCh chan []byte
|
msgCh chan message
|
||||||
finCh chan struct{}
|
finCh chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSession(key string, src, dst *net.UDPAddr) *Session {
|
func newSession(key string, src, dst *net.UDPAddr) *session {
|
||||||
return &Session{key, src, dst, make(chan []byte, 32), make(chan struct{})}
|
return &session{key, src, dst, make(chan message, 32), make(chan struct{})}
|
||||||
}
|
}
|
||||||
|
@ -105,8 +105,7 @@ func (s *Trojan) dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// 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)
|
c, err := s.dial("udp", addr)
|
||||||
// TODO: check the addr in return value
|
return NewPktConn(c, socks.ParseAddr(addr)), err
|
||||||
return NewPktConn(c, socks.ParseAddr(addr)), nil, err
|
|
||||||
}
|
}
|
||||||
|
@ -13,24 +13,23 @@ import (
|
|||||||
// PktConn is a udp Packet.Conn.
|
// PktConn is a udp Packet.Conn.
|
||||||
type PktConn struct {
|
type PktConn struct {
|
||||||
net.Conn
|
net.Conn
|
||||||
tgtAddr socks.Addr
|
target socks.Addr
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPktConn returns a PktConn.
|
// NewPktConn returns a PktConn.
|
||||||
func NewPktConn(c net.Conn, tgtAddr socks.Addr) *PktConn {
|
func NewPktConn(c net.Conn, target socks.Addr) *PktConn {
|
||||||
pc := &PktConn{
|
return &PktConn{Conn: c, target: target}
|
||||||
Conn: c,
|
|
||||||
tgtAddr: tgtAddr,
|
|
||||||
}
|
|
||||||
return pc
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadFrom implements the necessary function of net.PacketConn.
|
// 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) {
|
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||||
// ATYP, DST.ADDR, DST.PORT
|
// 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 {
|
if err != nil {
|
||||||
return 0, nil, err
|
return 0, nil, err
|
||||||
}
|
}
|
||||||
@ -62,16 +61,24 @@ func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
|||||||
return n, nil, err
|
return n, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: check the addr in return value, it's a fake packetConn so the addr is not valid
|
return n, target, err
|
||||||
return n, pc.tgtAddr, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo implements the necessary function of net.PacketConn.
|
// WriteTo implements the necessary function of net.PacketConn.
|
||||||
func (pc *PktConn) WriteTo(b []byte, addr net.Addr) (int, error) {
|
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()
|
buf := pool.GetBytesBuffer()
|
||||||
defer pool.PutBytesBuffer(buf)
|
defer pool.PutBytesBuffer(buf)
|
||||||
|
|
||||||
tgtLen, _ := buf.Write(pc.tgtAddr)
|
tgtLen, _ := buf.Write(target)
|
||||||
binary.Write(buf, binary.BigEndian, uint16(len(b)))
|
binary.Write(buf, binary.BigEndian, uint16(len(b)))
|
||||||
buf.WriteString("\r\n")
|
buf.WriteString("\r\n")
|
||||||
buf.Write(b)
|
buf.Write(b)
|
||||||
|
@ -194,22 +194,16 @@ func (s *Trojan) readHeader(r io.Reader) (byte, socks.Addr, error) {
|
|||||||
|
|
||||||
// ServeUoT serves udp over tcp requests.
|
// ServeUoT serves udp over tcp requests.
|
||||||
func (s *Trojan) ServeUoT(c net.Conn, tgt socks.Addr) {
|
func (s *Trojan) ServeUoT(c net.Conn, tgt socks.Addr) {
|
||||||
rc, err := net.ListenPacket("udp", "")
|
lc, err := net.ListenPacket("udp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[trojan] UDP listen error: %v", err)
|
log.F("[trojan] UDP listen error: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
defer rc.Close()
|
defer lc.Close()
|
||||||
|
|
||||||
tgtAddr, err := net.ResolveUDPAddr("udp", tgt.String())
|
|
||||||
if err != nil {
|
|
||||||
log.F("[vless] error in ResolveUDPAddr: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
pc := NewPktConn(c, tgt)
|
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)
|
go proxy.CopyUDP(lc, nil, pc, 2*time.Minute, 5*time.Second)
|
||||||
proxy.CopyUDP(pc, nil, rc, 2*time.Minute, 5*time.Second)
|
proxy.CopyUDP(pc, nil, lc, 2*time.Minute, 5*time.Second)
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package udp
|
package udp
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
@ -22,6 +21,7 @@ func init() {
|
|||||||
// UDP struct.
|
// UDP struct.
|
||||||
type UDP struct {
|
type UDP struct {
|
||||||
addr string
|
addr string
|
||||||
|
uaddr *net.UDPAddr
|
||||||
dialer proxy.Dialer
|
dialer proxy.Dialer
|
||||||
proxy proxy.Proxy
|
proxy proxy.Proxy
|
||||||
}
|
}
|
||||||
@ -40,7 +40,8 @@ func NewUDP(s string, d proxy.Dialer, p proxy.Proxy) (*UDP, error) {
|
|||||||
addr: u.Host,
|
addr: u.Host,
|
||||||
}
|
}
|
||||||
|
|
||||||
return t, nil
|
t.uaddr, err = net.ResolveUDPAddr("udp", t.addr)
|
||||||
|
return t, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUDPDialer returns a udp dialer.
|
// NewUDPDialer returns a udp dialer.
|
||||||
@ -72,26 +73,26 @@ func (s *UDP) ListenAndServe() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var session *Session
|
var sess *session
|
||||||
sessionKey := srcAddr.String()
|
sessKey := srcAddr.String()
|
||||||
|
|
||||||
v, ok := nm.Load(sessionKey)
|
v, ok := nm.Load(sessKey)
|
||||||
if !ok || v == nil {
|
if !ok || v == nil {
|
||||||
session = newSession(sessionKey, srcAddr, c)
|
sess = newSession(sessKey, srcAddr, c)
|
||||||
nm.Store(sessionKey, session)
|
nm.Store(sessKey, sess)
|
||||||
go s.serveSession(session)
|
go s.serveSession(sess)
|
||||||
} else {
|
} 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 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.
|
// 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 {
|
if err != nil {
|
||||||
log.F("[udp] remote dial error: %v", err)
|
log.F("[udp] remote dial error: %v", err)
|
||||||
nm.Delete(session.key)
|
nm.Delete(session.key)
|
||||||
@ -100,7 +101,7 @@ func (s *UDP) serveSession(session *Session) {
|
|||||||
defer dstPC.Close()
|
defer dstPC.Close()
|
||||||
|
|
||||||
go func() {
|
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)
|
nm.Delete(session.key)
|
||||||
close(session.finCh)
|
close(session.finCh)
|
||||||
}()
|
}()
|
||||||
@ -110,9 +111,9 @@ func (s *UDP) serveSession(session *Session) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case p := <-session.msgCh:
|
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 {
|
if err != nil {
|
||||||
log.F("[udp] writeTo %s error: %v", writeTo, err)
|
log.F("[udp] writeTo error: %v", err)
|
||||||
}
|
}
|
||||||
pool.PutBuffer(p)
|
pool.PutBuffer(p)
|
||||||
case <-session.finCh:
|
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
|
||||||
key string
|
src *net.UDPAddr
|
||||||
src net.Addr
|
net.PacketConn
|
||||||
srcPC net.PacketConn
|
|
||||||
msgCh chan []byte
|
msgCh chan []byte
|
||||||
finCh chan struct{}
|
finCh chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newSession(key string, src net.Addr, srcPC net.PacketConn) *Session {
|
func newSession(key string, src net.Addr, srcPC net.PacketConn) *session {
|
||||||
return &Session{key, src, srcPC, make(chan []byte, 32), make(chan struct{})}
|
srcAddr, _ := net.ResolveUDPAddr("udp", src.String())
|
||||||
|
return &session{key, srcAddr, srcPC, make(chan []byte, 32), make(chan struct{})}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Serve serves a connection.
|
// 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.
|
// Dial connects to the address addr on the network net via the proxy.
|
||||||
func (s *UDP) Dial(network, addr string) (net.Conn, error) {
|
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.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *UDP) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *UDP) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return s.dialer.DialUDP(network, s.addr)
|
// 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)
|
||||||
}
|
}
|
||||||
|
@ -32,21 +32,21 @@ func (s *Unix) Dial(network, addr string) (net.Conn, error) {
|
|||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
// NOTE: must be the first dialer in a chain
|
// 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
|
laddru := s.addru + "_" + addr
|
||||||
os.Remove(laddru)
|
os.Remove(laddru)
|
||||||
|
|
||||||
luaddru, err := net.ResolveUnixAddr("unixgram", laddru)
|
luaddru, err := net.ResolveUnixAddr("unixgram", laddru)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pc, err := net.ListenUnixgram("unixgram", luaddru)
|
pc, err := net.ListenUnixgram("unixgram", luaddru)
|
||||||
if err != nil {
|
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 .
|
// PktConn .
|
||||||
|
@ -140,7 +140,7 @@ func (s *Unix) ServePacket(pc net.PacketConn) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *Unix) serveSession(session *Session) {
|
func (s *Unix) serveSession(session *Session) {
|
||||||
dstPC, dialer, writeTo, err := s.proxy.DialUDP("udp", "")
|
dstPC, dialer, err := s.proxy.DialUDP("udp", "")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[unix] remote dial error: %v", err)
|
log.F("[unix] remote dial error: %v", err)
|
||||||
nm.Delete(session.key)
|
nm.Delete(session.key)
|
||||||
@ -159,9 +159,9 @@ func (s *Unix) serveSession(session *Session) {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case p := <-session.msgCh:
|
case p := <-session.msgCh:
|
||||||
_, err = dstPC.WriteTo(p, writeTo)
|
_, err = dstPC.WriteTo(p, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.F("[unix] writeTo %s error: %v", writeTo, err)
|
log.F("[unix] writeTo error: %v", err)
|
||||||
}
|
}
|
||||||
pool.PutBuffer(p)
|
pool.PutBuffer(p)
|
||||||
case <-session.finCh:
|
case <-session.finCh:
|
||||||
|
@ -39,10 +39,19 @@ func (s *VLess) dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// 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)
|
c, err := s.dial("udp", addr)
|
||||||
// TODO: check the addr in return value
|
if err != nil {
|
||||||
return NewPktConn(c), nil, err
|
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.
|
// ClientConn is a vless client connection.
|
||||||
|
@ -10,31 +10,35 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// PktConn is a udp Packet.Conn.
|
// PktConn is a udp Packet.Conn.
|
||||||
type PktConn struct{ net.Conn }
|
type PktConn struct {
|
||||||
|
net.Conn
|
||||||
|
target *net.UDPAddr
|
||||||
|
}
|
||||||
|
|
||||||
// NewPktConn returns a PktConn.
|
// 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.
|
// 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) {
|
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||||
if len(b) < 2 {
|
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
|
// Length
|
||||||
if _, err := io.ReadFull(pc.Conn, b[:2]); err != nil {
|
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]))
|
length := int(binary.BigEndian.Uint16(b[:2]))
|
||||||
|
|
||||||
if len(b) < length {
|
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
|
// Payload
|
||||||
n, err := io.ReadFull(pc.Conn, b[:length])
|
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.
|
// WriteTo implements the necessary function of net.PacketConn.
|
||||||
|
@ -162,10 +162,10 @@ func (s *VLess) ServeUoT(c net.Conn, tgt string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
pc := NewPktConn(c)
|
pc := NewPktConn(c, tgtAddr)
|
||||||
log.F("[vless] %s <-tcp-> %s - %s <-udp-> %s", c.RemoteAddr(), c.LocalAddr(), rc.LocalAddr(), tgt)
|
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)
|
proxy.CopyUDP(pc, nil, rc, 2*time.Minute, 5*time.Second)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,15 +5,20 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// PktConn is a udp Packet.Conn.
|
// PktConn is a udp Packet.Conn.
|
||||||
type PktConn struct{ net.Conn }
|
type PktConn struct {
|
||||||
|
net.Conn
|
||||||
|
target *net.UDPAddr
|
||||||
|
}
|
||||||
|
|
||||||
// NewPktConn returns a PktConn.
|
// 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.
|
// ReadFrom implements the necessary function of net.PacketConn.
|
||||||
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
func (pc *PktConn) ReadFrom(b []byte) (int, net.Addr, error) {
|
||||||
n, err := pc.Read(b)
|
n, err := pc.Read(b)
|
||||||
return n, nil, err
|
return n, pc.target, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo implements the necessary function of net.PacketConn.
|
// WriteTo implements the necessary function of net.PacketConn.
|
||||||
|
@ -98,16 +98,23 @@ func (s *VMess) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// 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)
|
rc, err := s.dialer.Dial("tcp", s.addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
rc, err = s.client.NewConn(rc, addr, CmdUDP)
|
rc, err = s.client.NewConn(rc, addr, CmdUDP)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return NewPktConn(rc), nil, err
|
|
||||||
|
return NewPktConn(rc, tgtAddr), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
@ -79,8 +79,8 @@ func (s *WS) Dial(network, addr string) (net.Conn, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address via the proxy.
|
// DialUDP connects to the given address via the proxy.
|
||||||
func (s *WS) DialUDP(network, addr string) (net.PacketConn, net.Addr, error) {
|
func (s *WS) DialUDP(network, addr string) (net.PacketConn, error) {
|
||||||
return nil, nil, proxy.ErrNotSupported
|
return nil, proxy.ErrNotSupported
|
||||||
}
|
}
|
||||||
|
|
||||||
// ClientConn is a connection to ws server.
|
// ClientConn is a connection to ws server.
|
||||||
|
@ -109,10 +109,10 @@ func (p *FwdrGroup) Dial(network, addr string) (net.Conn, proxy.Dialer, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DialUDP connects to the given address.
|
// 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)
|
nd := p.NextDialer(addr)
|
||||||
pc, wt, err := nd.DialUDP(network, addr)
|
pc, err = nd.DialUDP(network, addr)
|
||||||
return pc, nd, wt, err
|
return pc, nd, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NextDialer returns the next dialer.
|
// NextDialer returns the next dialer.
|
||||||
|
@ -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.
|
// 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)
|
return p.findDialer(addr).DialUDP(network, addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user