add udp redirect listener

This commit is contained in:
ginuerzh 2021-12-17 15:00:13 +08:00
parent 8e31e532e4
commit 6c1522dace
10 changed files with 202 additions and 4 deletions

View File

@ -49,6 +49,7 @@ import (
_ "github.com/go-gost/gost/pkg/listener/obfs/http"
_ "github.com/go-gost/gost/pkg/listener/obfs/tls"
_ "github.com/go-gost/gost/pkg/listener/quic"
_ "github.com/go-gost/gost/pkg/listener/redirect/udp"
_ "github.com/go-gost/gost/pkg/listener/rtcp"
_ "github.com/go-gost/gost/pkg/listener/rudp"
_ "github.com/go-gost/gost/pkg/listener/tcp"

1
go.mod
View File

@ -3,6 +3,7 @@ module github.com/go-gost/gost
go 1.17
require (
github.com/LiamHaworth/go-tproxy v0.0.0-20190726054950-ef7efd7f24ed
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da // indirect
github.com/asaskevich/govalidator v0.0.0-20210307081110-f21760c49a8d
github.com/cheekybits/genny v1.0.0 // indirect

4
go.sum
View File

@ -51,6 +51,8 @@ dmitri.shuralyov.com/state v0.0.0-20180228185332-28bcc343414c/go.mod h1:0PRwlb0D
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
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/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da h1:KjTM2ks9d14ZYCvmHS9iAKVt9AyzRSqNU1qabPih5BY=
github.com/aead/chacha20 v0.0.0-20180709150244-8b13a72661da/go.mod h1:eHEWzANqSiWQsof+nXEI9bUVUyV6F53Fp89EuCh2EAA=
@ -397,8 +399,6 @@ github.com/xtaci/kcp-go/v5 v5.6.1 h1:Pwn0aoeNSPF9dTS7IgiPXn0HEtaIlVb6y5UKWPsx8bI
github.com/xtaci/kcp-go/v5 v5.6.1/go.mod h1:W3kVPyNYwZ06p79dNwFWQOVFrdcBpDBsdyvK8moQrYo=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae h1:J0GxkO96kL4WF+AIT3M4mfUVinOCPgf2uUWYFUzN0sM=
github.com/xtaci/lossyconn v0.0.0-20190602105132-8df528c0c9ae/go.mod h1:gXtu8J62kEgmN++bm9BVICuT/e8yiLI2KFobd/TRFsE=
github.com/xtaci/smux v1.5.15 h1:6hMiXswcleXj5oNfcJc+DXS8Vj36XX2LaX98udog6Kc=
github.com/xtaci/smux v1.5.15/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
github.com/xtaci/smux v1.5.16 h1:FBPYOkW8ZTjLKUM4LI4xnnuuDC8CQ/dB04HD519WoEk=
github.com/xtaci/smux v1.5.16/go.mod h1:OMlQbT5vcgl2gb49mFkYo6SMf+zP3rcjcwQz7ZU7IGY=
github.com/xtaci/tcpraw v1.2.25 h1:VDlqo0op17JeXBM6e2G9ocCNLOJcw9mZbobMbJjo0vk=

View File

@ -16,6 +16,7 @@ import (
func init() {
registry.RegisterHandler("red", NewHandler)
registry.RegisterHandler("redu", NewHandler)
registry.RegisterHandler("redir", NewHandler)
registry.RegisterHandler("redirect", NewHandler)
}
@ -49,6 +50,8 @@ func (h *redirectHandler) WithChain(chain *chain.Chain) {
}
func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn) {
defer conn.Close()
start := time.Now()
h.logger = h.logger.WithFields(map[string]interface{}{
"remote": conn.RemoteAddr().String(),
@ -78,7 +81,6 @@ func (h *redirectHandler) Handle(ctx context.Context, conn net.Conn) {
return
}
}
defer conn.Close()
h.logger = h.logger.WithFields(map[string]interface{}{
"dst": fmt.Sprintf("%s/%s", dstAddr, network),

View File

@ -10,6 +10,6 @@ import (
func (h *redirectHandler) getOriginalDstAddr(conn net.Conn) (addr net.Addr, c net.Conn, err error) {
defer conn.Close()
err = errors.New("TCP redirect is not available on Windows platform")
err = errors.New("TCP redirect is not available on non-linux platform")
return
}

View File

@ -0,0 +1,42 @@
package udp
import (
"net"
"sync"
"time"
"github.com/go-gost/gost/pkg/common/bufpool"
)
type redirConn struct {
net.Conn
buf []byte
ttl time.Duration
once sync.Once
}
func (c *redirConn) Read(b []byte) (n int, err error) {
if c.ttl > 0 {
c.SetReadDeadline(time.Now().Add(c.ttl))
defer c.SetReadDeadline(time.Time{})
}
c.once.Do(func() {
n = copy(b, c.buf)
bufpool.Put(c.buf)
c.buf = nil
})
if n == 0 {
n, err = c.Conn.Read(b)
}
return
}
func (c *redirConn) Write(b []byte) (n int, err error) {
if c.ttl > 0 {
c.SetWriteDeadline(time.Now().Add(c.ttl))
defer c.SetWriteDeadline(time.Time{})
}
return c.Conn.Write(b)
}

View File

@ -0,0 +1,63 @@
package udp
import (
"net"
"github.com/go-gost/gost/pkg/listener"
"github.com/go-gost/gost/pkg/logger"
md "github.com/go-gost/gost/pkg/metadata"
"github.com/go-gost/gost/pkg/registry"
)
func init() {
registry.RegisterListener("redu", NewListener)
}
type redirectListener struct {
addr string
ln *net.UDPConn
logger logger.Logger
md metadata
}
func NewListener(opts ...listener.Option) listener.Listener {
options := &listener.Options{}
for _, opt := range opts {
opt(options)
}
return &redirectListener{
addr: options.Addr,
logger: options.Logger,
}
}
func (l *redirectListener) Init(md md.Metadata) (err error) {
if err = l.parseMetadata(md); err != nil {
return
}
laddr, err := net.ResolveUDPAddr("udp", l.addr)
if err != nil {
return
}
ln, err := l.listenUDP(laddr)
if err != nil {
return
}
l.ln = ln
return
}
func (l *redirectListener) Accept() (conn net.Conn, err error) {
return l.accept()
}
func (l *redirectListener) Addr() net.Addr {
return l.ln.LocalAddr()
}
func (l *redirectListener) Close() error {
return l.ln.Close()
}

View File

@ -0,0 +1,37 @@
package udp
import (
"net"
"github.com/LiamHaworth/go-tproxy"
"github.com/go-gost/gost/pkg/common/bufpool"
)
func (l *redirectListener) listenUDP(addr *net.UDPAddr) (*net.UDPConn, error) {
return tproxy.ListenUDP("udp", addr)
}
func (l *redirectListener) accept() (conn net.Conn, err error) {
b := bufpool.Get(l.md.readBufferSize)
n, raddr, dstAddr, err := tproxy.ReadFromUDP(l.ln, b)
if err != nil {
l.logger.Error(err)
return
}
l.logger.Infof("%s >> %s", raddr.String(), dstAddr.String())
c, err := tproxy.DialUDP("udp", dstAddr, raddr)
if err != nil {
l.logger.Error(err)
return
}
conn = &redirConn{
Conn: c,
buf: b[:n],
ttl: l.md.ttl,
}
return
}

View File

@ -0,0 +1,16 @@
//go:build !linux
package udp
import (
"errors"
"net"
)
func (l *redirectListener) listenUDP(addr *net.UDPAddr) (*net.UDPConn, error) {
return nil, errors.New("UDP redirect is not available on non-linux platform")
}
func (l *redirectListener) accept() (conn net.Conn, err error) {
return nil, errors.New("UDP redirect is not available on non-linux platform")
}

View File

@ -0,0 +1,36 @@
package udp
import (
"time"
md "github.com/go-gost/gost/pkg/metadata"
)
const (
defaultTTL = 60 * time.Second
defaultReadBufferSize = 1024
)
type metadata struct {
ttl time.Duration
readBufferSize int
}
func (l *redirectListener) parseMetadata(md md.Metadata) (err error) {
const (
ttl = "ttl"
readBufferSize = "readBufferSize"
)
l.md.ttl = md.GetDuration(ttl)
if l.md.ttl <= 0 {
l.md.ttl = defaultTTL
}
l.md.readBufferSize = md.GetInt(readBufferSize)
if l.md.readBufferSize <= 0 {
l.md.readBufferSize = defaultReadBufferSize
}
return
}