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

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