add udp transparent proxy
This commit is contained in:
parent
6ce3639c02
commit
bd9fc76466
@ -481,6 +481,12 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
TLSConfig: tlsCfg,
|
TLSConfig: tlsCfg,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
case "redu", "redirectu":
|
||||||
|
ln, err = gost.UDPRedirectListener(node.Addr, &gost.UDPListenConfig{
|
||||||
|
TTL: ttl,
|
||||||
|
Backlog: node.GetInt("backlog"),
|
||||||
|
QueueSize: node.GetInt("queue"),
|
||||||
|
})
|
||||||
default:
|
default:
|
||||||
ln, err = gost.TCPListener(node.Addr)
|
ln, err = gost.TCPListener(node.Addr)
|
||||||
}
|
}
|
||||||
@ -512,8 +518,10 @@ func (r *route) GenRouters() ([]router, error) {
|
|||||||
handler = gost.UDPRemoteForwardHandler(node.Remote)
|
handler = gost.UDPRemoteForwardHandler(node.Remote)
|
||||||
case "forward":
|
case "forward":
|
||||||
handler = gost.SSHForwardHandler()
|
handler = gost.SSHForwardHandler()
|
||||||
case "redirect":
|
case "red", "redirect":
|
||||||
handler = gost.TCPRedirectHandler()
|
handler = gost.TCPRedirectHandler()
|
||||||
|
case "redu", "redirectu":
|
||||||
|
handler = gost.UDPRedirectHandler()
|
||||||
case "ssu":
|
case "ssu":
|
||||||
handler = gost.ShadowUDPHandler()
|
handler = gost.ShadowUDPHandler()
|
||||||
case "sni":
|
case "sni":
|
||||||
|
@ -189,7 +189,7 @@ func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
|
|||||||
raddr, err := net.ResolveUDPAddr("udp", node.Addr)
|
raddr, err := net.ResolveUDPAddr("udp", node.Addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
node.MarkDead()
|
node.MarkDead()
|
||||||
log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
|
log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,7 +198,7 @@ func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
|
|||||||
cc, err = net.DialUDP("udp", nil, raddr)
|
cc, err = net.DialUDP("udp", nil, raddr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
node.MarkDead()
|
node.MarkDead()
|
||||||
log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
|
log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if h.options.Chain.LastNode().Protocol == "ssu" {
|
} else if h.options.Chain.LastNode().Protocol == "ssu" {
|
||||||
@ -208,14 +208,14 @@ func (h *udpDirectForwardHandler) Handle(conn net.Conn) {
|
|||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
node.MarkDead()
|
node.MarkDead()
|
||||||
log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
|
log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
var err error
|
var err error
|
||||||
cc, err = getSOCKS5UDPTunnel(h.options.Chain, nil)
|
cc, err = getSOCKS5UDPTunnel(h.options.Chain, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Logf("[udp] %s - %s : %s", conn.LocalAddr(), node.Addr, err)
|
log.Logf("[udp] %s - %s : %s", conn.RemoteAddr(), node.Addr, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
1
go.mod
1
go.mod
@ -5,6 +5,7 @@ go 1.13
|
|||||||
require (
|
require (
|
||||||
git.torproject.org/pluggable-transports/goptlib.git v0.0.0-20180321061416-7d56ec4f381e
|
git.torproject.org/pluggable-transports/goptlib.git v0.0.0-20180321061416-7d56ec4f381e
|
||||||
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e
|
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e
|
||||||
|
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
|
||||||
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63 // indirect
|
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63 // indirect
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
|
||||||
github.com/bifurcation/mint v0.0.0-20181105071958-a14404e9a861 // indirect
|
github.com/bifurcation/mint v0.0.0-20181105071958-a14404e9a861 // indirect
|
||||||
|
2
go.sum
2
go.sum
@ -2,6 +2,8 @@ git.torproject.org/pluggable-transports/goptlib.git v0.0.0-20180321061416-7d56ec
|
|||||||
git.torproject.org/pluggable-transports/goptlib.git v0.0.0-20180321061416-7d56ec4f381e/go.mod h1:YT4XMSkuEXbtqlydr9+OxqFAyspUv0Gr9qhM3B++o/Q=
|
git.torproject.org/pluggable-transports/goptlib.git v0.0.0-20180321061416-7d56ec4f381e/go.mod h1:YT4XMSkuEXbtqlydr9+OxqFAyspUv0Gr9qhM3B++o/Q=
|
||||||
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e h1:c8h60PKrRxEB5debIHBmP7T+s/EUNXTklXqlmJfYiJQ=
|
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e h1:c8h60PKrRxEB5debIHBmP7T+s/EUNXTklXqlmJfYiJQ=
|
||||||
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e/go.mod h1:jRZbfRcLIgFQoCw6tRmsnETVyIj54jOmXhHCYYa0jbs=
|
git.torproject.org/pluggable-transports/obfs4.git v0.0.0-20181103133120-08f4d470188e/go.mod h1:jRZbfRcLIgFQoCw6tRmsnETVyIj54jOmXhHCYYa0jbs=
|
||||||
|
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed h1:eqa6queieK8SvoszxCu0WwH7lSVeL4/N/f1JwOMw1G4=
|
||||||
|
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed/go.mod h1:rA52xkgZwql9LRZXWb2arHEFP6qSR48KY2xOfWzEciQ=
|
||||||
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63 h1:I6/SJSN9wJMJ+ZyQaCHUlzoTA4ypU5Bb44YWR1wTY/0=
|
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63 h1:I6/SJSN9wJMJ+ZyQaCHUlzoTA4ypU5Bb44YWR1wTY/0=
|
||||||
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63/go.mod h1:nf+Komq6fVP4SwmKEaVGxHTyQGKREVlwjQKpvOV39yE=
|
github.com/Yawning/chacha20 v0.0.0-20170904085104-e3b1f968fc63/go.mod h1:nf+Komq6fVP4SwmKEaVGxHTyQGKREVlwjQKpvOV39yE=
|
||||||
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
|
||||||
|
3
node.go
3
node.go
@ -90,6 +90,7 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
case "tun", "tap": // tun/tap device
|
case "tun", "tap": // tun/tap device
|
||||||
case "ftcp": // fake TCP
|
case "ftcp": // fake TCP
|
||||||
case "dns":
|
case "dns":
|
||||||
|
case "redu", "redirectu": // UDP tproxy
|
||||||
default:
|
default:
|
||||||
node.Transport = "tcp"
|
node.Transport = "tcp"
|
||||||
}
|
}
|
||||||
@ -105,7 +106,7 @@ func ParseNode(s string) (node Node, err error) {
|
|||||||
case "sni":
|
case "sni":
|
||||||
case "tcp", "udp", "rtcp", "rudp": // port forwarding
|
case "tcp", "udp", "rtcp", "rudp": // port forwarding
|
||||||
case "direct", "remote", "forward": // forwarding
|
case "direct", "remote", "forward": // forwarding
|
||||||
case "redirect": // TCP transparent proxy
|
case "red", "redirect", "redu", "redirectu": // TCP,UDP transparent proxy
|
||||||
case "tun", "tap": // tun/tap device
|
case "tun", "tap": // tun/tap device
|
||||||
case "ftcp": // fake TCP
|
case "ftcp": // fake TCP
|
||||||
case "dns", "dot", "doh":
|
case "dns", "dot", "doh":
|
||||||
|
194
redirect.go
194
redirect.go
@ -8,6 +8,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"syscall"
|
"syscall"
|
||||||
|
|
||||||
|
"github.com/LiamHaworth/go-tproxy"
|
||||||
"github.com/go-log/log"
|
"github.com/go-log/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -15,7 +16,7 @@ type tcpRedirectHandler struct {
|
|||||||
options *HandlerOptions
|
options *HandlerOptions
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCPRedirectHandler creates a server Handler for TCP redirect server.
|
// TCPRedirectHandler creates a server Handler for TCP transparent server.
|
||||||
func TCPRedirectHandler(opts ...HandlerOption) Handler {
|
func TCPRedirectHandler(opts ...HandlerOption) Handler {
|
||||||
h := &tcpRedirectHandler{}
|
h := &tcpRedirectHandler{}
|
||||||
h.Init(opts...)
|
h.Init(opts...)
|
||||||
@ -97,3 +98,194 @@ func (h *tcpRedirectHandler) getOriginalDstAddr(conn *net.TCPConn) (addr net.Add
|
|||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type udpRedirectHandler struct {
|
||||||
|
options *HandlerOptions
|
||||||
|
}
|
||||||
|
|
||||||
|
// UDPRedirectHandler creates a server Handler for UDP transparent server.
|
||||||
|
func UDPRedirectHandler(opts ...HandlerOption) Handler {
|
||||||
|
h := &udpRedirectHandler{}
|
||||||
|
h.Init(opts...)
|
||||||
|
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *udpRedirectHandler) Init(options ...HandlerOption) {
|
||||||
|
if h.options == nil {
|
||||||
|
h.options = &HandlerOptions{}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range options {
|
||||||
|
opt(h.options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *udpRedirectHandler) Handle(c net.Conn) {
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
conn, ok := c.(*udpRedirectServerConn)
|
||||||
|
if !ok {
|
||||||
|
log.Log("wrong connection type")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
raddr := conn.DstAddr()
|
||||||
|
|
||||||
|
var cc net.Conn
|
||||||
|
var err error
|
||||||
|
if h.options.Chain.IsEmpty() {
|
||||||
|
cc, err = net.DialUDP("udp", nil, raddr)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[red-udp] %s - %s : %s", conn.RemoteAddr(), raddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else if h.options.Chain.LastNode().Protocol == "ssu" {
|
||||||
|
cc, err = h.options.Chain.Dial(raddr.String(),
|
||||||
|
RetryChainOption(h.options.Retries),
|
||||||
|
TimeoutChainOption(h.options.Timeout),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[red-udp] %s - %s : %s", conn.RemoteAddr(), raddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var err error
|
||||||
|
cc, err = getSOCKS5UDPTunnel(h.options.Chain, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[red-udp] %s - %s : %s", conn.RemoteAddr(), raddr, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
cc = &udpTunnelConn{Conn: cc, raddr: raddr}
|
||||||
|
}
|
||||||
|
defer cc.Close()
|
||||||
|
|
||||||
|
log.Logf("[red-udp] %s <-> %s", conn.RemoteAddr(), raddr)
|
||||||
|
transport(conn, cc)
|
||||||
|
log.Logf("[red-udp] %s >-< %s", conn.RemoteAddr(), raddr)
|
||||||
|
}
|
||||||
|
|
||||||
|
type udpRedirectListener struct {
|
||||||
|
ln *net.UDPConn
|
||||||
|
connChan chan net.Conn
|
||||||
|
errChan chan error
|
||||||
|
connMap udpConnMap
|
||||||
|
config *UDPListenConfig
|
||||||
|
}
|
||||||
|
|
||||||
|
// UDPRedirectListener creates a Listener for UDP transparent proxy server.
|
||||||
|
func UDPRedirectListener(addr string, cfg *UDPListenConfig) (Listener, error) {
|
||||||
|
laddr, err := net.ResolveUDPAddr("udp", addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
ln, err := tproxy.ListenUDP("udp", laddr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg == nil {
|
||||||
|
cfg = &UDPListenConfig{}
|
||||||
|
}
|
||||||
|
|
||||||
|
backlog := cfg.Backlog
|
||||||
|
if backlog <= 0 {
|
||||||
|
backlog = defaultBacklog
|
||||||
|
}
|
||||||
|
|
||||||
|
l := &udpRedirectListener{
|
||||||
|
ln: ln,
|
||||||
|
connChan: make(chan net.Conn, backlog),
|
||||||
|
errChan: make(chan error, 1),
|
||||||
|
config: cfg,
|
||||||
|
}
|
||||||
|
go l.listenLoop()
|
||||||
|
return l, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *udpRedirectListener) listenLoop() {
|
||||||
|
for {
|
||||||
|
b := make([]byte, mediumBufferSize)
|
||||||
|
n, raddr, dstAddr, err := tproxy.ReadFromUDP(l.ln, b)
|
||||||
|
if err != nil {
|
||||||
|
log.Logf("[red-udp] peer -> %s : %s", l.Addr(), err)
|
||||||
|
l.Close()
|
||||||
|
l.errChan <- err
|
||||||
|
close(l.errChan)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, ok := l.connMap.Get(raddr.String())
|
||||||
|
if !ok {
|
||||||
|
conn = newUDPServerConn(l.ln, raddr, &udpServerConnConfig{
|
||||||
|
ttl: l.config.TTL,
|
||||||
|
qsize: l.config.QueueSize,
|
||||||
|
onClose: func() {
|
||||||
|
l.connMap.Delete(raddr.String())
|
||||||
|
log.Logf("[red-udp] %s closed (%d)", raddr, l.connMap.Size())
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
cc := udpRedirectServerConn{
|
||||||
|
udpServerConn: conn,
|
||||||
|
dstAddr: dstAddr,
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case l.connChan <- cc:
|
||||||
|
l.connMap.Set(raddr.String(), conn)
|
||||||
|
log.Logf("[red-udp] %s -> %s (%d)", raddr, l.Addr(), l.connMap.Size())
|
||||||
|
default:
|
||||||
|
conn.Close()
|
||||||
|
log.Logf("[red-udp] %s - %s: connection queue is full (%d)",
|
||||||
|
raddr, l.Addr(), cap(l.connChan))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
case conn.rChan <- b[:n]:
|
||||||
|
if Debug {
|
||||||
|
log.Logf("[red-udp] %s >>> %s : length %d", raddr, l.Addr(), n)
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
log.Logf("[red-udp] %s -> %s : recv queue is full (%d)",
|
||||||
|
raddr, l.Addr(), cap(conn.rChan))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *udpRedirectListener) Accept() (conn net.Conn, err error) {
|
||||||
|
var ok bool
|
||||||
|
select {
|
||||||
|
case conn = <-l.connChan:
|
||||||
|
case err, ok = <-l.errChan:
|
||||||
|
if !ok {
|
||||||
|
err = errors.New("accpet on closed listener")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *udpRedirectListener) Addr() net.Addr {
|
||||||
|
return l.ln.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *udpRedirectListener) Close() error {
|
||||||
|
err := l.ln.Close()
|
||||||
|
l.connMap.Range(func(k interface{}, v *udpServerConn) bool {
|
||||||
|
v.Close()
|
||||||
|
return true
|
||||||
|
})
|
||||||
|
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
type udpRedirectServerConn struct {
|
||||||
|
*udpServerConn
|
||||||
|
dstAddr *net.UDPAddr
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *udpRedirectServerConn) DstAddr() *net.UDPAddr {
|
||||||
|
return c.dstAddr
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user