add buffer size option for udp connection

This commit is contained in:
ginuerzh
2025-07-30 21:40:53 +08:00
parent b64e5901b6
commit a5309eee97
26 changed files with 218 additions and 219 deletions
+12 -10
View File
@@ -2,10 +2,10 @@ package v5
import ( import (
"bytes" "bytes"
"math"
"net" "net"
"time" "time"
"github.com/go-gost/core/common/bufpool"
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
"github.com/go-gost/gosocks5" "github.com/go-gost/gosocks5"
) )
@@ -25,17 +25,18 @@ func (c *bindConn) RemoteAddr() net.Addr {
} }
type udpRelayConn struct { type udpRelayConn struct {
udpConn *net.UDPConn udpConn *net.UDPConn
tcpConn net.Conn tcpConn net.Conn
taddr net.Addr taddr net.Addr
rbuf [math.MaxUint16]byte bufferSize int
wbuf [math.MaxInt16]byte logger logger.Logger
logger logger.Logger
} }
func (c *udpRelayConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { func (c *udpRelayConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
buf := c.rbuf[:] buf := bufpool.Get(c.bufferSize)
nn, err := c.udpConn.Read(buf[:]) defer bufpool.Put(buf)
nn, err := c.udpConn.Read(buf)
if err != nil { if err != nil {
return return
} }
@@ -81,7 +82,8 @@ func (c *udpRelayConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
Data: b, Data: b,
} }
buf := c.wbuf[:] buf := bufpool.Get(c.bufferSize)
defer bufpool.Put(buf)
nn, err := dgram.WriteTo(bytes.NewBuffer(buf[:0])) nn, err := dgram.WriteTo(bytes.NewBuffer(buf[:0]))
if err != nil { if err != nil {
+5 -4
View File
@@ -225,9 +225,10 @@ func (c *socks5Connector) relayUDP(ctx context.Context, conn net.Conn, addr net.
} }
return &udpRelayConn{ return &udpRelayConn{
udpConn: cc.(*net.UDPConn), udpConn: cc.(*net.UDPConn),
tcpConn: conn, tcpConn: conn,
taddr: addr, taddr: addr,
logger: log, bufferSize: c.md.udpBufferSize,
logger: log,
}, nil }, nil
} }
+9
View File
@@ -8,10 +8,15 @@ import (
mdutil "github.com/go-gost/x/metadata/util" mdutil "github.com/go-gost/x/metadata/util"
) )
const (
defaultUDPBufferSize = 4096
)
type metadata struct { type metadata struct {
connectTimeout time.Duration connectTimeout time.Duration
noTLS bool noTLS bool
relay string relay string
udpBufferSize int
udpTimeout time.Duration udpTimeout time.Duration
muxCfg *mux.Config muxCfg *mux.Config
} }
@@ -20,6 +25,10 @@ func (c *socks5Connector) parseMetadata(md mdata.Metadata) (err error) {
c.md.connectTimeout = mdutil.GetDuration(md, "timeout") c.md.connectTimeout = mdutil.GetDuration(md, "timeout")
c.md.noTLS = mdutil.GetBool(md, "notls") c.md.noTLS = mdutil.GetBool(md, "notls")
c.md.relay = mdutil.GetString(md, "relay") c.md.relay = mdutil.GetString(md, "relay")
c.md.udpBufferSize = mdutil.GetInt(md, "udp.bufferSize", "udpBufferSize")
if c.md.udpBufferSize <= 0 {
c.md.udpBufferSize = defaultUDPBufferSize
}
c.md.udpTimeout = mdutil.GetDuration(md, "udp.timeout") c.md.udpTimeout = mdutil.GetDuration(md, "udp.timeout")
c.md.muxCfg = &mux.Config{ c.md.muxCfg = &mux.Config{
+1 -1
View File
@@ -85,7 +85,7 @@ func (c *ssuConnector) Connect(ctx context.Context, conn net.Conn, network, addr
} }
// standard UDP relay // standard UDP relay
return ss.UDPClientConn(pc, conn.RemoteAddr(), taddr), nil return ss.UDPClientConn(pc, conn.RemoteAddr(), taddr, c.md.udpBufferSize), nil
} }
if c.cipher != nil { if c.cipher != nil {
+4 -7
View File
@@ -10,16 +10,13 @@ import (
type metadata struct { type metadata struct {
key string key string
connectTimeout time.Duration connectTimeout time.Duration
udpBufferSize int
} }
func (c *ssuConnector) parseMetadata(md mdata.Metadata) (err error) { func (c *ssuConnector) parseMetadata(md mdata.Metadata) (err error) {
const ( c.md.key = mdutil.GetString(md, "key")
key = "key" c.md.connectTimeout = mdutil.GetDuration(md, "timeout", "connectTimeout")
connectTimeout = "timeout" c.md.udpBufferSize = mdutil.GetInt(md, "udpBufferSize", "udp.bufferSize")
)
c.md.key = mdutil.GetString(md, key)
c.md.connectTimeout = mdutil.GetDuration(md, connectTimeout)
return return
} }
+2
View File
@@ -25,6 +25,7 @@ type metadata struct {
compression bool compression bool
probeResistance *probeResistance probeResistance *probeResistance
enableUDP bool enableUDP bool
udpBufferSize int
header http.Header header http.Header
hash string hash string
authBasicRealm string authBasicRealm string
@@ -77,6 +78,7 @@ func (h *httpHandler) parseMetadata(md mdata.Metadata) error {
} }
} }
h.md.enableUDP = mdutil.GetBool(md, "udp") h.md.enableUDP = mdutil.GetBool(md, "udp")
h.md.udpBufferSize = mdutil.GetInt(md, "udp.bufferSize", "udpBufferSize")
h.md.hash = mdutil.GetString(md, "hash") h.md.hash = mdutil.GetString(md, "hash")
h.md.authBasicRealm = mdutil.GetString(md, "authBasicRealm") h.md.authBasicRealm = mdutil.GetString(md, "authBasicRealm")
+1
View File
@@ -75,6 +75,7 @@ func (h *httpHandler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecorde
relay := udp.NewRelay(socks.UDPTunServerConn(conn), pc). relay := udp.NewRelay(socks.UDPTunServerConn(conn), pc).
WithBypass(h.options.Bypass). WithBypass(h.options.Bypass).
WithBufferSize(h.md.udpBufferSize).
WithLogger(log) WithLogger(log)
t := time.Now() t := time.Now()
+1
View File
@@ -205,6 +205,7 @@ func (h *relayHandler) bindUDP(ctx context.Context, conn net.Conn, network, addr
r := udp.NewRelay(relay_util.UDPTunServerConn(conn), pc). r := udp.NewRelay(relay_util.UDPTunServerConn(conn), pc).
WithBypass(h.options.Bypass). WithBypass(h.options.Bypass).
WithBufferSize(h.md.udpBufferSize).
WithLogger(log) WithLogger(log)
t := time.Now() t := time.Now()
+7 -5
View File
@@ -14,11 +14,12 @@ import (
) )
type metadata struct { type metadata struct {
readTimeout time.Duration readTimeout time.Duration
enableBind bool udpBufferSize int
noDelay bool enableBind bool
hash string noDelay bool
muxCfg *mux.Config hash string
muxCfg *mux.Config
observerPeriod time.Duration observerPeriod time.Duration
observerResetTraffic bool observerResetTraffic bool
@@ -43,6 +44,7 @@ func (h *relayHandler) parseMetadata(md mdata.Metadata) (err error) {
h.md.readTimeout = 15 * time.Second h.md.readTimeout = 15 * time.Second
} }
h.md.udpBufferSize = mdutil.GetInt(md, "udp.bufferSize", "udpBufferSize")
h.md.enableBind = mdutil.GetBool(md, "bind") h.md.enableBind = mdutil.GetBool(md, "bind")
h.md.noDelay = mdutil.GetBool(md, "nodelay") h.md.noDelay = mdutil.GetBool(md, "nodelay")
h.md.hash = mdutil.GetString(md, "hash") h.md.hash = mdutil.GetString(md, "hash")
+4 -2
View File
@@ -121,9 +121,11 @@ func (h *routerHandler) handleAssociate(ctx context.Context, conn net.Conn, netw
log.Debugf("%s/%s: router=%s, connector=%s, weight=%d established", host, network, routerID, connectorID, connectorID.Weight()) log.Debugf("%s/%s: router=%s, connector=%s, weight=%d established", host, network, routerID, connectorID, connectorID.Weight())
var b [MaxMessageSize]byte b := bufpool.Get(h.md.bufferSize)
defer bufpool.Put(b)
for { for {
n, err := conn.Read(b[:]) n, err := conn.Read(b)
if err != nil { if err != nil {
if err == io.EOF { if err == io.EOF {
return nil return nil
+4 -2
View File
@@ -3,16 +3,18 @@ package router
import ( import (
"bytes" "bytes"
"github.com/go-gost/core/common/bufpool"
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
"github.com/go-gost/relay" "github.com/go-gost/relay"
) )
func (h *routerHandler) handleEntrypoint(log logger.Logger) error { func (h *routerHandler) handleEntrypoint(log logger.Logger) error {
var buf [MaxMessageSize]byte buf := bufpool.Get(h.md.bufferSize)
defer bufpool.Put(buf)
for { for {
err := func() error { err := func() error {
n, addr, err := h.epConn.ReadFrom(buf[:]) n, addr, err := h.epConn.ReadFrom(buf)
if err != nil { if err != nil {
return err return err
} }
+6 -2
View File
@@ -1,7 +1,6 @@
package router package router
import ( import (
"math"
"time" "time"
"github.com/go-gost/core/ingress" "github.com/go-gost/core/ingress"
@@ -13,13 +12,14 @@ import (
) )
const ( const (
MaxMessageSize = math.MaxUint16
defaultTTL = 15 * time.Second defaultTTL = 15 * time.Second
defaultBufferSize = 4096
defaultCacheExpiration = time.Second defaultCacheExpiration = time.Second
) )
type metadata struct { type metadata struct {
readTimeout time.Duration readTimeout time.Duration
bufferSize int
entryPoint string entryPoint string
ingress ingress.Ingress ingress ingress.Ingress
@@ -40,6 +40,10 @@ type metadata struct {
func (h *routerHandler) parseMetadata(md mdata.Metadata) (err error) { func (h *routerHandler) parseMetadata(md mdata.Metadata) (err error) {
h.md.readTimeout = mdutil.GetDuration(md, "readTimeout") h.md.readTimeout = mdutil.GetDuration(md, "readTimeout")
h.md.bufferSize = mdutil.GetInt(md, "router.bufferSize", "bufferSize")
if h.md.bufferSize <= 0 {
h.md.bufferSize = defaultBufferSize
}
h.md.entryPoint = mdutil.GetString(md, "entrypoint") h.md.entryPoint = mdutil.GetString(md, "entrypoint")
h.md.ingress = registry.IngressRegistry().Get(mdutil.GetString(md, "ingress")) h.md.ingress = registry.IngressRegistry().Get(mdutil.GetString(md, "ingress"))
+2 -1
View File
@@ -145,6 +145,7 @@ func (h *socks5Handler) Handle(ctx context.Context, conn net.Conn, opts ...handl
} }
log.WithFields(map[string]any{ log.WithFields(map[string]any{
"network": ro.Network,
"duration": time.Since(start), "duration": time.Since(start),
"inputBytes": ro.InputBytes, "inputBytes": ro.InputBytes,
"outputBytes": ro.OutputBytes, "outputBytes": ro.OutputBytes,
@@ -186,7 +187,7 @@ func (h *socks5Handler) Handle(ctx context.Context, conn net.Conn, opts ...handl
return h.handleMuxBind(ctx, conn, "tcp", address, ro, log) return h.handleMuxBind(ctx, conn, "tcp", address, ro, log)
case gosocks5.CmdUdp: case gosocks5.CmdUdp:
ro.Network = "udp" ro.Network = "udp"
return h.handleUDP(ctx, conn, ro, log) return h.handleUDP(ctx, conn, "udp", ro, log)
case socks.CmdUDPTun: case socks.CmdUDPTun:
ro.Network = "udp" ro.Network = "udp"
return h.handleUDPTun(ctx, conn, "udp", address, ro, log) return h.handleUDPTun(ctx, conn, "udp", address, ro, log)
+2
View File
@@ -19,6 +19,7 @@ type metadata struct {
noTLS bool noTLS bool
enableBind bool enableBind bool
enableUDP bool enableUDP bool
udpBufferSize int
compatibilityMode bool compatibilityMode bool
hash string hash string
muxCfg *mux.Config muxCfg *mux.Config
@@ -50,6 +51,7 @@ func (h *socks5Handler) parseMetadata(md mdata.Metadata) (err error) {
h.md.noTLS = mdutil.GetBool(md, "notls") h.md.noTLS = mdutil.GetBool(md, "notls")
h.md.enableBind = mdutil.GetBool(md, "bind") h.md.enableBind = mdutil.GetBool(md, "bind")
h.md.enableUDP = mdutil.GetBool(md, "udp") h.md.enableUDP = mdutil.GetBool(md, "udp")
h.md.udpBufferSize = mdutil.GetInt(md, "udp.bufferSize", "udpBufferSize")
h.md.compatibilityMode = mdutil.GetBool(md, "comp") h.md.compatibilityMode = mdutil.GetBool(md, "comp")
h.md.hash = mdutil.GetString(md, "hash") h.md.hash = mdutil.GetString(md, "hash")
+8 -6
View File
@@ -23,9 +23,10 @@ import (
xrecorder "github.com/go-gost/x/recorder" xrecorder "github.com/go-gost/x/recorder"
) )
func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error { func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, network string, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
log = log.WithFields(map[string]any{ log = log.WithFields(map[string]any{
"cmd": "udp", "network": network,
"cmd": network,
}) })
if !h.md.enableUDP { if !h.md.enableUDP {
@@ -39,7 +40,7 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecor
Netns: h.options.Netns, Netns: h.options.Netns,
} }
cc, err := lc.ListenPacket(ctx, "udp", "") cc, err := lc.ListenPacket(ctx, network, "")
if err != nil { if err != nil {
log.Error(err) log.Error(err)
reply := gosocks5.NewReply(gosocks5.Failure, nil) reply := gosocks5.NewReply(gosocks5.Failure, nil)
@@ -74,7 +75,7 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecor
// obtain a udp connection // obtain a udp connection
var buf bytes.Buffer var buf bytes.Buffer
c, err := h.options.Router.Dial(ctxvalue.ContextWithBuffer(ctx, &buf), "udp", "") // UDP association c, err := h.options.Router.Dial(ctxvalue.ContextWithBuffer(ctx, &buf), network, "") // UDP association
ro.Route = buf.String() ro.Route = buf.String()
if err != nil { if err != nil {
log.Error(err) log.Error(err)
@@ -106,7 +107,7 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecor
string(clientID), string(clientID),
limiter.ServiceOption(h.options.Service), limiter.ServiceOption(h.options.Service),
limiter.ScopeOption(limiter.ScopeClient), limiter.ScopeOption(limiter.ScopeClient),
limiter.NetworkOption("udp"), limiter.NetworkOption(network),
limiter.ClientOption(string(clientID)), limiter.ClientOption(string(clientID)),
limiter.SrcOption(conn.RemoteAddr().String()), limiter.SrcOption(conn.RemoteAddr().String()),
) )
@@ -119,8 +120,9 @@ func (h *socks5Handler) handleUDP(ctx context.Context, conn net.Conn, ro *xrecor
} }
} }
r := udp.NewRelay(socks.UDPConn(cc), pc). r := udp.NewRelay(socks.UDPConn(cc, h.md.udpBufferSize), pc).
WithBypass(h.options.Bypass). WithBypass(h.options.Bypass).
WithBufferSize(h.md.udpBufferSize).
WithLogger(log) WithLogger(log)
go r.Run(ctx) go r.Run(ctx)
+5 -3
View File
@@ -22,7 +22,8 @@ import (
func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network, address string, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error { func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network, address string, ro *xrecorder.HandlerRecorderObject, log logger.Logger) error {
log = log.WithFields(map[string]any{ log = log.WithFields(map[string]any{
"cmd": "udp-tun", "network": network,
"cmd": "udp-tun",
}) })
{ {
@@ -66,7 +67,7 @@ func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network
// obtain a udp connection // obtain a udp connection
var buf bytes.Buffer var buf bytes.Buffer
c, err := h.options.Router.Dial(ctxvalue.ContextWithBuffer(ctx, &buf), "udp", "") // UDP association c, err := h.options.Router.Dial(ctxvalue.ContextWithBuffer(ctx, &buf), network, "") // UDP association
ro.Route = buf.String() ro.Route = buf.String()
if err != nil { if err != nil {
log.Error(err) log.Error(err)
@@ -94,7 +95,7 @@ func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network
Netns: h.options.Netns, Netns: h.options.Netns,
} }
var err error var err error
pc, err = lc.ListenPacket(ctx, "udp", bindAddr.String()) pc, err = lc.ListenPacket(ctx, network, bindAddr.String())
if err != nil { if err != nil {
log.Error(err) log.Error(err)
reply := gosocks5.NewReply(gosocks5.Failure, nil) reply := gosocks5.NewReply(gosocks5.Failure, nil)
@@ -133,6 +134,7 @@ func (h *socks5Handler) handleUDPTun(ctx context.Context, conn net.Conn, network
r := udp.NewRelay(socks.UDPTunServerConn(conn), pc). r := udp.NewRelay(socks.UDPTunServerConn(conn), pc).
WithBypass(h.options.Bypass). WithBypass(h.options.Bypass).
WithBufferSize(h.md.udpBufferSize).
WithLogger(log) WithLogger(log)
t := time.Now() t := time.Now()
+15 -5
View File
@@ -7,6 +7,7 @@ import (
"net" "net"
"time" "time"
"github.com/go-gost/core/common/bufpool"
"github.com/go-gost/core/handler" "github.com/go-gost/core/handler"
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
md "github.com/go-gost/core/metadata" md "github.com/go-gost/core/metadata"
@@ -112,7 +113,7 @@ func (h *ssuHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.
pc = h.cipher.PacketConn(pc) pc = h.cipher.PacketConn(pc)
} }
// standard UDP relay. // standard UDP relay.
pc = ss.UDPServerConn(pc, conn.RemoteAddr()) pc = ss.UDPServerConn(pc, conn.RemoteAddr(), h.md.udpBufferSize)
} else { } else {
if h.cipher != nil { if h.cipher != nil {
conn = ss.ShadowConn(h.cipher.StreamConn(conn), nil) conn = ss.ShadowConn(h.cipher.StreamConn(conn), nil)
@@ -150,11 +151,18 @@ func (h *ssuHandler) Handle(ctx context.Context, conn net.Conn, opts ...handler.
func (h *ssuHandler) relayPacket(ctx context.Context, pc1, pc2 net.PacketConn, ro *xrecorder.HandlerRecorderObject, log logger.Logger) (err error) { func (h *ssuHandler) relayPacket(ctx context.Context, pc1, pc2 net.PacketConn, ro *xrecorder.HandlerRecorderObject, log logger.Logger) (err error) {
errc := make(chan error, 2) errc := make(chan error, 2)
bufferSize := h.md.udpBufferSize
if bufferSize <= 0 {
bufferSize = defaultBufferSize
}
go func() { go func() {
var b [MaxMessageSize]byte b := bufpool.Get(bufferSize)
defer bufpool.Put(b)
for { for {
err := func() error { err := func() error {
n, addr, err := pc1.ReadFrom(b[:]) n, addr, err := pc1.ReadFrom(b)
if err != nil { if err != nil {
return err return err
} }
@@ -185,10 +193,12 @@ func (h *ssuHandler) relayPacket(ctx context.Context, pc1, pc2 net.PacketConn, r
}() }()
go func() { go func() {
var b [MaxMessageSize]byte b := bufpool.Get(bufferSize)
defer bufpool.Put(b)
for { for {
err := func() error { err := func() error {
n, raddr, err := pc2.ReadFrom(b[:]) n, raddr, err := pc2.ReadFrom(b)
if err != nil { if err != nil {
return err return err
} }
+7 -10
View File
@@ -1,7 +1,6 @@
package ss package ss
import ( import (
"math"
"time" "time"
mdata "github.com/go-gost/core/metadata" mdata "github.com/go-gost/core/metadata"
@@ -9,22 +8,20 @@ import (
) )
const ( const (
MaxMessageSize = math.MaxUint16 defaultBufferSize = 4096
) )
type metadata struct { type metadata struct {
key string key string
readTimeout time.Duration readTimeout time.Duration
udpBufferSize int
} }
func (h *ssuHandler) parseMetadata(md mdata.Metadata) (err error) { func (h *ssuHandler) parseMetadata(md mdata.Metadata) (err error) {
const (
key = "key"
readTimeout = "readTimeout"
)
h.md.key = mdutil.GetString(md, key) h.md.key = mdutil.GetString(md, "key")
h.md.readTimeout = mdutil.GetDuration(md, readTimeout) h.md.readTimeout = mdutil.GetDuration(md, "readTimeout")
h.md.udpBufferSize = mdutil.GetInt(md, "udpBufferSize", "udp.bufferSize")
return return
} }
+7 -1
View File
@@ -10,8 +10,13 @@ import (
mdutil "github.com/go-gost/x/metadata/util" mdutil "github.com/go-gost/x/metadata/util"
) )
const (
defaultBufferSize = 4096
)
type metadata struct { type metadata struct {
udpTimeout time.Duration udpTimeout time.Duration
udpBufferSize int
sniffing bool sniffing bool
sniffingUDP bool sniffingUDP bool
@@ -34,6 +39,7 @@ type metadata struct {
func (h *tungoHandler) parseMetadata(md mdata.Metadata) (err error) { func (h *tungoHandler) parseMetadata(md mdata.Metadata) (err error) {
h.md.udpTimeout = mdutil.GetDuration(md, "udpTimeout", "tungo.udpTimeout") h.md.udpTimeout = mdutil.GetDuration(md, "udpTimeout", "tungo.udpTimeout")
h.md.udpBufferSize = mdutil.GetInt(md, "udp.bufferSize", "udpBufferSize")
h.md.sniffing = mdutil.GetBool(md, "sniffing") h.md.sniffing = mdutil.GetBool(md, "sniffing")
h.md.sniffingUDP = mdutil.GetBool(md, "sniffing.udp") h.md.sniffingUDP = mdutil.GetBool(md, "sniffing.udp")
+22 -8
View File
@@ -6,13 +6,13 @@ import (
"context" "context"
"crypto/tls" "crypto/tls"
"io" "io"
"math"
"net" "net"
"net/netip" "net/netip"
"strings" "strings"
"sync" "sync"
"time" "time"
"github.com/go-gost/core/common/bufpool"
"github.com/go-gost/core/handler" "github.com/go-gost/core/handler"
"github.com/go-gost/core/observer/stats" "github.com/go-gost/core/observer/stats"
"github.com/go-gost/core/recorder" "github.com/go-gost/core/recorder"
@@ -44,7 +44,8 @@ type transportHandler struct {
procCancel context.CancelFunc procCancel context.CancelFunc
// UDP session timeout. // UDP session timeout.
udpTimeout time.Duration udpTimeout time.Duration
udpBufferSize int
sniffing bool sniffing bool
sniffingUDP bool sniffingUDP bool
@@ -344,33 +345,46 @@ func (h *transportHandler) handleUDPConn(uc adapter.UDPConn) {
t := time.Now() t := time.Now()
log.Infof("%s <-> %s", remoteAddr, dstAddr) log.Infof("%s <-> %s", remoteAddr, dstAddr)
pipePacketData(conn, cc, h.sniffingUDP, ro, h.udpTimeout) h.pipePacketData(conn, cc, ro)
log.WithFields(map[string]any{ log.WithFields(map[string]any{
"duration": time.Since(t), "duration": time.Since(t),
}).Infof("%s >-< %s", remoteAddr, dstAddr) }).Infof("%s >-< %s", remoteAddr, dstAddr)
} }
func pipePacketData(conn1, conn2 net.Conn, sniffing bool, ro *xrecorder.HandlerRecorderObject, timeout time.Duration) { func (h *transportHandler) pipePacketData(conn1, conn2 net.Conn, ro *xrecorder.HandlerRecorderObject) {
timeout := h.udpTimeout
if timeout <= 0 { if timeout <= 0 {
timeout = udpSessionTimeout timeout = udpSessionTimeout
} }
bufferSize := h.udpBufferSize
if bufferSize <= 0 {
bufferSize = defaultBufferSize
}
wg := sync.WaitGroup{} wg := sync.WaitGroup{}
wg.Add(2) wg.Add(2)
go func() { go func() {
defer wg.Done() defer wg.Done()
copyPacketData(conn1, conn2, sniffing, false, ro, timeout)
buf := bufpool.Get(bufferSize)
defer bufpool.Put(buf)
copyPacketData(conn1, conn2, buf, h.sniffing, false, ro, timeout)
}() }()
go func() { go func() {
defer wg.Done() defer wg.Done()
copyPacketData(conn2, conn1, sniffing, true, ro, timeout)
buf := bufpool.Get(bufferSize)
defer bufpool.Put(buf)
copyPacketData(conn2, conn1, buf, h.sniffing, true, ro, timeout)
}() }()
wg.Wait() wg.Wait()
} }
func copyPacketData(dst, src net.Conn, sniffing bool, c2s bool, ro *xrecorder.HandlerRecorderObject, timeout time.Duration) error { func copyPacketData(dst, src net.Conn, buf []byte, sniffing bool, c2s bool, ro *xrecorder.HandlerRecorderObject, timeout time.Duration) error {
buf := make([]byte, math.MaxUint16/2)
isDNS := false isDNS := false
for { for {
+6
View File
@@ -176,6 +176,8 @@ func (c *conn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
if !c.keepalive { if !c.keepalive {
defer c.Close() defer c.Close()
} }
c.SetIdle(false)
return c.PacketConn.WriteTo(b, addr) return c.PacketConn.WriteTo(b, addr)
} }
@@ -212,6 +214,10 @@ func (c *conn) RemoteAddr() net.Addr {
return c.remoteAddr return c.remoteAddr
} }
func (c *conn) SetReadDeadline(t time.Time) error {
return nil
}
func (c *conn) IsIdle() bool { func (c *conn) IsIdle() bool {
return atomic.LoadInt32(&c.idle) > 0 return atomic.LoadInt32(&c.idle) > 0
} }
+25 -13
View File
@@ -2,23 +2,23 @@ package udp
import ( import (
"context" "context"
"math"
"net" "net"
"github.com/go-gost/core/bypass" "github.com/go-gost/core/bypass"
"github.com/go-gost/core/common/bufpool"
"github.com/go-gost/core/logger" "github.com/go-gost/core/logger"
) )
const ( const (
MaxMessageSize = math.MaxUint16 defaultBufferSize = 4096
) )
type Relay struct { type Relay struct {
pc1 net.PacketConn pc1 net.PacketConn
pc2 net.PacketConn pc2 net.PacketConn
bufferSize int
bypass bypass.Bypass bypass bypass.Bypass
logger logger.Logger logger logger.Logger
} }
func NewRelay(pc1, pc2 net.PacketConn) *Relay { func NewRelay(pc1, pc2 net.PacketConn) *Relay {
@@ -38,14 +38,26 @@ func (r *Relay) WithLogger(logger logger.Logger) *Relay {
return r return r
} }
func (r *Relay) WithBufferSize(n int) *Relay {
r.bufferSize = n
return r
}
func (r *Relay) Run(ctx context.Context) (err error) { func (r *Relay) Run(ctx context.Context) (err error) {
errc := make(chan error, 2) errc := make(chan error, 2)
bufferSize := r.bufferSize
if bufferSize <= 0 {
bufferSize = defaultBufferSize
}
go func() { go func() {
var b [MaxMessageSize]byte b := bufpool.Get(bufferSize)
defer bufpool.Put(b)
for { for {
err := func() error { err := func() error {
n, raddr, err := r.pc1.ReadFrom(b[:]) n, raddr, err := r.pc1.ReadFrom(b)
if err != nil { if err != nil {
return err return err
} }
@@ -64,7 +76,6 @@ func (r *Relay) Run(ctx context.Context) (err error) {
if r.logger != nil { if r.logger != nil {
r.logger.Tracef("%s >>> %s data: %d", r.logger.Tracef("%s >>> %s data: %d",
r.pc2.LocalAddr(), raddr, n) r.pc2.LocalAddr(), raddr, n)
} }
return nil return nil
@@ -78,10 +89,12 @@ func (r *Relay) Run(ctx context.Context) (err error) {
}() }()
go func() { go func() {
var b [MaxMessageSize]byte b := bufpool.Get(bufferSize)
defer bufpool.Put(b)
for { for {
err := func() error { err := func() error {
n, raddr, err := r.pc2.ReadFrom(b[:]) n, raddr, err := r.pc2.ReadFrom(b)
if err != nil { if err != nil {
return err return err
} }
@@ -100,7 +113,6 @@ func (r *Relay) Run(ctx context.Context) (err error) {
if r.logger != nil { if r.logger != nil {
r.logger.Tracef("%s <<< %s data: %d", r.logger.Tracef("%s <<< %s data: %d",
r.pc2.LocalAddr(), raddr, n) r.pc2.LocalAddr(), raddr, n)
} }
return nil return nil
-88
View File
@@ -1,10 +1,8 @@
package relay package relay
import ( import (
"bytes"
"net" "net"
"github.com/go-gost/core/common/bufpool"
"github.com/go-gost/gosocks5" "github.com/go-gost/gosocks5"
"github.com/go-gost/relay" "github.com/go-gost/relay"
) )
@@ -108,89 +106,3 @@ func (c *udpTunConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
func (c *udpTunConn) Write(b []byte) (n int, err error) { func (c *udpTunConn) Write(b []byte) (n int, err error) {
return c.WriteTo(b, c.taddr) return c.WriteTo(b, c.taddr)
} }
var (
DefaultBufferSize = 4096
)
type udpConn struct {
net.PacketConn
raddr net.Addr
taddr net.Addr
bufferSize int
}
func UDPConn(c net.PacketConn, bufferSize int) net.PacketConn {
return &udpConn{
PacketConn: c,
bufferSize: bufferSize,
}
}
// ReadFrom reads an UDP datagram.
// NOTE: for server side,
// the returned addr is the target address the client want to relay to.
func (c *udpConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
rbuf := bufpool.Get(c.bufferSize)
defer bufpool.Put(rbuf)
n, c.raddr, err = c.PacketConn.ReadFrom(rbuf)
if err != nil {
return
}
socksAddr := gosocks5.Addr{}
header := gosocks5.UDPHeader{
Addr: &socksAddr,
}
hlen, err := header.ReadFrom(bytes.NewReader(rbuf[:n]))
if err != nil {
return
}
n = copy(b, rbuf[hlen:n])
addr, err = net.ResolveUDPAddr("udp", socksAddr.String())
return
}
func (c *udpConn) Read(b []byte) (n int, err error) {
n, _, err = c.ReadFrom(b)
return
}
func (c *udpConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
wbuf := bufpool.Get(c.bufferSize)
defer bufpool.Put(wbuf)
socksAddr := gosocks5.Addr{}
if err = socksAddr.ParseFrom(addr.String()); err != nil {
return
}
header := gosocks5.UDPHeader{
Addr: &socksAddr,
}
dgram := gosocks5.UDPDatagram{
Header: &header,
Data: b,
}
buf := bytes.NewBuffer(wbuf[:0])
_, err = dgram.WriteTo(buf)
if err != nil {
return
}
_, err = c.PacketConn.WriteTo(buf.Bytes(), c.raddr)
n = len(b)
return
}
func (c *udpConn) Write(b []byte) (n int, err error) {
return c.WriteTo(b, c.taddr)
}
func (c *udpConn) RemoteAddr() net.Addr {
return c.raddr
}
+21 -14
View File
@@ -2,9 +2,9 @@ package socks
import ( import (
"bytes" "bytes"
"math"
"net" "net"
"github.com/go-gost/core/common/bufpool"
"github.com/go-gost/gosocks5" "github.com/go-gost/gosocks5"
) )
@@ -86,18 +86,23 @@ func (c *udpTunConn) Write(b []byte) (n int, err error) {
} }
const ( const (
MaxMessageSize = math.MaxUint16 defaultBufferSize = 4096
) )
type udpConn struct { type udpConn struct {
net.PacketConn net.PacketConn
raddr net.Addr raddr net.Addr
taddr net.Addr taddr net.Addr
bufferSize int
} }
func UDPConn(c net.PacketConn) net.PacketConn { func UDPConn(c net.PacketConn, bufferSize int) net.PacketConn {
if bufferSize <= 0 {
bufferSize = defaultBufferSize
}
return &udpConn{ return &udpConn{
PacketConn: c, PacketConn: c,
bufferSize: bufferSize,
} }
} }
@@ -105,9 +110,10 @@ func UDPConn(c net.PacketConn) net.PacketConn {
// NOTE: for server side, // NOTE: for server side,
// the returned addr is the target address the client want to relay to. // the returned addr is the target address the client want to relay to.
func (c *udpConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { func (c *udpConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
var rbuf [MaxMessageSize]byte buf := bufpool.Get(c.bufferSize)
defer bufpool.Put(buf)
n, c.raddr, err = c.PacketConn.ReadFrom(rbuf[:]) n, c.raddr, err = c.PacketConn.ReadFrom(buf)
if err != nil { if err != nil {
return return
} }
@@ -116,11 +122,11 @@ func (c *udpConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
header := gosocks5.UDPHeader{ header := gosocks5.UDPHeader{
Addr: &socksAddr, Addr: &socksAddr,
} }
hlen, err := header.ReadFrom(bytes.NewReader(rbuf[:n])) hlen, err := header.ReadFrom(bytes.NewReader(buf[:n]))
if err != nil { if err != nil {
return return
} }
n = copy(b, rbuf[hlen:n]) n = copy(b, buf[hlen:n])
addr, err = net.ResolveUDPAddr("udp", socksAddr.String()) addr, err = net.ResolveUDPAddr("udp", socksAddr.String())
return return
@@ -132,7 +138,6 @@ func (c *udpConn) Read(b []byte) (n int, err error) {
} }
func (c *udpConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { func (c *udpConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
socksAddr := gosocks5.Addr{} socksAddr := gosocks5.Addr{}
if err = socksAddr.ParseFrom(addr.String()); err != nil { if err = socksAddr.ParseFrom(addr.String()); err != nil {
return return
@@ -146,14 +151,16 @@ func (c *udpConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
Data: b, Data: b,
} }
var wbuf [MaxMessageSize]byte buf := bufpool.Get(c.bufferSize)
buf := bytes.NewBuffer(wbuf[:][:0]) defer bufpool.Put(buf)
_, err = dgram.WriteTo(buf)
bw := bytes.NewBuffer(buf[:0])
_, err = dgram.WriteTo(bw)
if err != nil { if err != nil {
return return
} }
_, err = c.PacketConn.WriteTo(buf.Bytes(), c.raddr) _, err = c.PacketConn.WriteTo(bw.Bytes(), c.raddr)
n = len(b) n = len(b)
return return
+28 -15
View File
@@ -2,14 +2,14 @@ package ss
import ( import (
"bytes" "bytes"
"math"
"net" "net"
"github.com/go-gost/core/common/bufpool"
"github.com/go-gost/gosocks5" "github.com/go-gost/gosocks5"
) )
const ( const (
MaxMessageSize = math.MaxUint16 defaultBufferSize = 4096
) )
var ( var (
@@ -19,40 +19,52 @@ var (
type UDPConn struct { type UDPConn struct {
net.PacketConn net.PacketConn
raddr net.Addr raddr net.Addr
taddr net.Addr taddr net.Addr
bufferSize int
} }
func UDPClientConn(c net.PacketConn, remoteAddr, targetAddr net.Addr) *UDPConn { func UDPClientConn(c net.PacketConn, remoteAddr, targetAddr net.Addr, bufferSize int) *UDPConn {
if bufferSize <= 0 {
bufferSize = defaultBufferSize
}
return &UDPConn{ return &UDPConn{
PacketConn: c, PacketConn: c,
raddr: remoteAddr, raddr: remoteAddr,
taddr: targetAddr, taddr: targetAddr,
bufferSize: bufferSize,
} }
} }
func UDPServerConn(c net.PacketConn, remoteAddr net.Addr) *UDPConn { func UDPServerConn(c net.PacketConn, remoteAddr net.Addr, bufferSize int) *UDPConn {
if bufferSize <= 0 {
bufferSize = defaultBufferSize
}
return &UDPConn{ return &UDPConn{
PacketConn: c, PacketConn: c,
raddr: remoteAddr, raddr: remoteAddr,
bufferSize: bufferSize,
} }
} }
func (c *UDPConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) { func (c *UDPConn) ReadFrom(b []byte) (n int, addr net.Addr, err error) {
var rbuf [MaxMessageSize]byte buf := bufpool.Get(c.bufferSize)
defer bufpool.Put(buf)
n, _, err = c.PacketConn.ReadFrom(rbuf[:]) n, _, err = c.PacketConn.ReadFrom(buf)
if err != nil { if err != nil {
return return
} }
saddr := gosocks5.Addr{} saddr := gosocks5.Addr{}
addrLen, err := saddr.ReadFrom(bytes.NewReader(rbuf[:n])) addrLen, err := saddr.ReadFrom(bytes.NewReader(buf[:n]))
if err != nil { if err != nil {
return return
} }
n = copy(b, rbuf[addrLen:n]) n = copy(b, buf[addrLen:n])
addr, err = net.ResolveUDPAddr("udp", saddr.String()) addr, err = net.ResolveUDPAddr("udp", saddr.String())
return return
@@ -64,20 +76,21 @@ func (c *UDPConn) Read(b []byte) (n int, err error) {
} }
func (c *UDPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) { func (c *UDPConn) WriteTo(b []byte, addr net.Addr) (n int, err error) {
var wbuf [MaxMessageSize]byte
socksAddr := gosocks5.Addr{} socksAddr := gosocks5.Addr{}
if err = socksAddr.ParseFrom(addr.String()); err != nil { if err = socksAddr.ParseFrom(addr.String()); err != nil {
return return
} }
addrLen, err := socksAddr.Encode(wbuf[:]) buf := bufpool.Get(c.bufferSize)
defer bufpool.Put(buf)
addrLen, err := socksAddr.Encode(buf)
if err != nil { if err != nil {
return return
} }
n = copy(wbuf[addrLen:], b) n = copy(buf[addrLen:], b)
_, err = c.PacketConn.WriteTo(wbuf[:addrLen+n], c.raddr) _, err = c.PacketConn.WriteTo(buf[:addrLen+n], c.raddr)
return return
} }
+14 -22
View File
@@ -9,47 +9,39 @@ import (
const ( const (
defaultTTL = 5 * time.Second defaultTTL = 5 * time.Second
defaultReadBufferSize = 8192 defaultReadBufferSize = 4096
defaultReadQueueSize = 128 defaultReadQueueSize = 128
defaultBacklog = 128 defaultBacklog = 128
) )
type metadata struct { type metadata struct {
readBufferSize int readBufferSize int
readQueueSize int readQueueSize int
backlog int backlog int
keepalive bool keepalive bool
ttl time.Duration ttl time.Duration
} }
func (l *udpListener) parseMetadata(md mdata.Metadata) (err error) { func (l *udpListener) parseMetadata(md mdata.Metadata) (err error) {
const ( l.md.backlog = mdutil.GetInt(md, "backlog")
readBufferSize = "readBufferSize" if l.md.backlog <= 0 {
readQueueSize = "readQueueSize" l.md.backlog = defaultBacklog
backlog = "backlog" }
keepalive = "keepalive"
ttl = "ttl"
)
l.md.ttl = mdutil.GetDuration(md, ttl) l.md.keepalive = mdutil.GetBool(md, "keepalive")
l.md.ttl = mdutil.GetDuration(md, "ttl", "keepalive.ttl")
if l.md.ttl <= 0 { if l.md.ttl <= 0 {
l.md.ttl = defaultTTL l.md.ttl = defaultTTL
} }
l.md.readBufferSize = mdutil.GetInt(md, readBufferSize) l.md.readBufferSize = mdutil.GetInt(md, "readBufferSize", "udp.bufferSize")
if l.md.readBufferSize <= 0 { if l.md.readBufferSize <= 0 {
l.md.readBufferSize = defaultReadBufferSize l.md.readBufferSize = defaultReadBufferSize
} }
l.md.readQueueSize = mdutil.GetInt(md, readQueueSize) l.md.readQueueSize = mdutil.GetInt(md, "readQueueSize", "recvQueueSize")
if l.md.readQueueSize <= 0 { if l.md.readQueueSize <= 0 {
l.md.readQueueSize = defaultReadQueueSize l.md.readQueueSize = defaultReadQueueSize
} }
l.md.backlog = mdutil.GetInt(md, backlog)
if l.md.backlog <= 0 {
l.md.backlog = defaultBacklog
}
l.md.keepalive = mdutil.GetBool(md, keepalive)
return return
} }