add udp redirect listener
This commit is contained in:
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
|
||||
}
|
Reference in New Issue
Block a user