add udp redirect listener
This commit is contained in:
parent
8e31e532e4
commit
6c1522dace
@ -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
1
go.mod
@ -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
4
go.sum
@ -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=
|
||||
|
@ -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),
|
||||
|
@ -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
|
||||
}
|
||||
|
42
pkg/listener/redirect/udp/conn.go
Normal file
42
pkg/listener/redirect/udp/conn.go
Normal 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)
|
||||
}
|
63
pkg/listener/redirect/udp/listener.go
Normal file
63
pkg/listener/redirect/udp/listener.go
Normal 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()
|
||||
}
|
37
pkg/listener/redirect/udp/listener_linux.go
Normal file
37
pkg/listener/redirect/udp/listener_linux.go
Normal 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
|
||||
}
|
16
pkg/listener/redirect/udp/listener_other.go
Normal file
16
pkg/listener/redirect/udp/listener_other.go
Normal 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")
|
||||
}
|
36
pkg/listener/redirect/udp/metadata.go
Normal file
36
pkg/listener/redirect/udp/metadata.go
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user