Add UDP timeout route option

This commit is contained in:
世界
2024-11-24 14:45:40 +08:00
parent 093e539d3d
commit 04cc343b2e
14 changed files with 155 additions and 239 deletions

View File

@@ -42,20 +42,21 @@ func (d *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
return nil, os.ErrInvalid
}
// Deprecated
func (d *Outbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
func (d *Outbound) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
metadata.Destination = M.Socksaddr{}
defer conn.Close()
for {
conn.SetReadDeadline(time.Now().Add(C.DNSTimeout))
err := HandleStreamDNSRequest(ctx, d.router, conn, metadata)
if err != nil {
return err
conn.Close()
if onClose != nil {
onClose(err)
}
return
}
}
}
// Deprecated
func (d *Outbound) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
return NewDNSPacketConnection(ctx, d.router, conn, nil, metadata)
func (d *Outbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
NewDNSPacketConnection(ctx, d.router, conn, nil, metadata)
}

View File

@@ -10,6 +10,7 @@ import (
C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option"
"github.com/sagernet/sing/common/atomic"
E "github.com/sagernet/sing/common/exceptions"
"github.com/sagernet/sing/common/logger"
M "github.com/sagernet/sing/common/metadata"
@@ -21,17 +22,22 @@ func RegisterSelector(registry *outbound.Registry) {
outbound.Register[option.SelectorOutboundOptions](registry, C.TypeSelector, NewSelector)
}
var _ adapter.OutboundGroup = (*Selector)(nil)
var (
_ adapter.OutboundGroup = (*Selector)(nil)
_ adapter.ConnectionHandlerEx = (*Selector)(nil)
_ adapter.PacketConnectionHandlerEx = (*Selector)(nil)
)
type Selector struct {
outbound.Adapter
ctx context.Context
outboundManager adapter.OutboundManager
outbound adapter.OutboundManager
connection adapter.ConnectionManager
logger logger.ContextLogger
tags []string
defaultTag string
outbounds map[string]adapter.Outbound
selected adapter.Outbound
selected atomic.TypedValue[adapter.Outbound]
interruptGroup *interrupt.Group
interruptExternalConnections bool
}
@@ -40,7 +46,8 @@ func NewSelector(ctx context.Context, router adapter.Router, logger log.ContextL
outbound := &Selector{
Adapter: outbound.NewAdapter(C.TypeSelector, tag, nil, options.Outbounds),
ctx: ctx,
outboundManager: service.FromContext[adapter.OutboundManager](ctx),
outbound: service.FromContext[adapter.OutboundManager](ctx),
connection: service.FromContext[adapter.ConnectionManager](ctx),
logger: logger,
tags: options.Outbounds,
defaultTag: options.Default,
@@ -55,15 +62,16 @@ func NewSelector(ctx context.Context, router adapter.Router, logger log.ContextL
}
func (s *Selector) Network() []string {
if s.selected == nil {
selected := s.selected.Load()
if selected == nil {
return []string{N.NetworkTCP, N.NetworkUDP}
}
return s.selected.Network()
return selected.Network()
}
func (s *Selector) Start() error {
for i, tag := range s.tags {
detour, loaded := s.outboundManager.Outbound(tag)
detour, loaded := s.outbound.Outbound(tag)
if !loaded {
return E.New("outbound ", i, " not found: ", tag)
}
@@ -77,7 +85,7 @@ func (s *Selector) Start() error {
if selected != "" {
detour, loaded := s.outbounds[selected]
if loaded {
s.selected = detour
s.selected.Store(detour)
return nil
}
}
@@ -89,16 +97,16 @@ func (s *Selector) Start() error {
if !loaded {
return E.New("default outbound not found: ", s.defaultTag)
}
s.selected = detour
s.selected.Store(detour)
return nil
}
s.selected = s.outbounds[s.tags[0]]
s.selected.Store(s.outbounds[s.tags[0]])
return nil
}
func (s *Selector) Now() string {
selected := s.selected
selected := s.selected.Load()
if selected == nil {
return s.tags[0]
}
@@ -114,10 +122,9 @@ func (s *Selector) SelectOutbound(tag string) bool {
if !loaded {
return false
}
if s.selected == detour {
if s.selected.Swap(detour) == detour {
return true
}
s.selected = detour
if s.Tag() != "" {
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
if cacheFile != nil {
@@ -132,7 +139,7 @@ func (s *Selector) SelectOutbound(tag string) bool {
}
func (s *Selector) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
conn, err := s.selected.DialContext(ctx, network, destination)
conn, err := s.selected.Load().DialContext(ctx, network, destination)
if err != nil {
return nil, err
}
@@ -140,32 +147,30 @@ func (s *Selector) DialContext(ctx context.Context, network string, destination
}
func (s *Selector) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
conn, err := s.selected.ListenPacket(ctx, destination)
conn, err := s.selected.Load().ListenPacket(ctx, destination)
if err != nil {
return nil, err
}
return s.interruptGroup.NewPacketConn(conn, interrupt.IsExternalConnectionFromContext(ctx)), nil
}
// TODO
// Deprecated
func (s *Selector) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
func (s *Selector) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
ctx = interrupt.ContextWithIsExternalConnection(ctx)
if legacyHandler, ok := s.selected.(adapter.ConnectionHandler); ok {
return legacyHandler.NewConnection(ctx, conn, metadata)
selected := s.selected.Load()
if outboundHandler, isHandler := selected.(adapter.ConnectionHandlerEx); isHandler {
outboundHandler.NewConnectionEx(ctx, conn, metadata, onClose)
} else {
return outbound.NewConnection(ctx, s.selected, conn, metadata)
s.connection.NewConnection(ctx, selected, conn, metadata, onClose)
}
}
// TODO
// Deprecated
func (s *Selector) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
func (s *Selector) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
ctx = interrupt.ContextWithIsExternalConnection(ctx)
if legacyHandler, ok := s.selected.(adapter.PacketConnectionHandler); ok {
return legacyHandler.NewPacketConnection(ctx, conn, metadata)
selected := s.selected.Load()
if outboundHandler, isHandler := selected.(adapter.PacketConnectionHandlerEx); isHandler {
outboundHandler.NewPacketConnectionEx(ctx, conn, metadata, onClose)
} else {
return outbound.NewPacketConnection(ctx, s.selected, conn, metadata)
s.connection.NewPacketConnection(ctx, selected, conn, metadata, onClose)
}
}

View File

@@ -36,7 +36,8 @@ type URLTest struct {
outbound.Adapter
ctx context.Context
router adapter.Router
outboundManager adapter.OutboundManager
outbound adapter.OutboundManager
connection adapter.ConnectionManager
logger log.ContextLogger
tags []string
link string
@@ -52,7 +53,8 @@ func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLo
Adapter: outbound.NewAdapter(C.TypeURLTest, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.Outbounds),
ctx: ctx,
router: router,
outboundManager: service.FromContext[adapter.OutboundManager](ctx),
outbound: service.FromContext[adapter.OutboundManager](ctx),
connection: service.FromContext[adapter.ConnectionManager](ctx),
logger: logger,
tags: options.Outbounds,
link: options.URL,
@@ -70,13 +72,13 @@ func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLo
func (s *URLTest) Start() error {
outbounds := make([]adapter.Outbound, 0, len(s.tags))
for i, tag := range s.tags {
detour, loaded := s.outboundManager.Outbound(tag)
detour, loaded := s.outbound.Outbound(tag)
if !loaded {
return E.New("outbound ", i, " not found: ", tag)
}
outbounds = append(outbounds, detour)
}
group, err := NewURLTestGroup(s.ctx, s.outboundManager, s.logger, outbounds, s.link, s.interval, s.tolerance, s.idleTimeout, s.interruptExternalConnections)
group, err := NewURLTestGroup(s.ctx, s.outbound, s.logger, outbounds, s.link, s.interval, s.tolerance, s.idleTimeout, s.interruptExternalConnections)
if err != nil {
return err
}
@@ -160,18 +162,14 @@ func (s *URLTest) ListenPacket(ctx context.Context, destination M.Socksaddr) (ne
return nil, err
}
// TODO
// Deprecated
func (s *URLTest) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
func (s *URLTest) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
ctx = interrupt.ContextWithIsExternalConnection(ctx)
return outbound.NewConnection(ctx, s, conn, metadata)
s.connection.NewConnection(ctx, s, conn, metadata, onClose)
}
// TODO
// Deprecated
func (s *URLTest) NewPacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
func (s *URLTest) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
ctx = interrupt.ContextWithIsExternalConnection(ctx)
return outbound.NewPacketConnection(ctx, s, conn, metadata)
s.connection.NewPacketConnection(ctx, s, conn, metadata, onClose)
}
func (s *URLTest) InterfaceUpdated() {