mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-10-19 15:54:24 +00:00
Refactor lifecycle to scoped cleanup
This commit is contained in:
@@ -3,83 +3,42 @@ package certificate
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
)
|
||||
|
||||
var _ adapter.CertificateProviderManager = (*Manager)(nil)
|
||||
|
||||
type Manager struct {
|
||||
logger log.ContextLogger
|
||||
registry adapter.CertificateProviderRegistry
|
||||
access sync.Mutex
|
||||
started bool
|
||||
stage adapter.StartStage
|
||||
providers []adapter.CertificateProviderService
|
||||
providerByTag map[string]adapter.CertificateProviderService
|
||||
}
|
||||
|
||||
func NewManager(logger log.ContextLogger, registry adapter.CertificateProviderRegistry) *Manager {
|
||||
func NewManager(registry adapter.CertificateProviderRegistry) *Manager {
|
||||
return &Manager{
|
||||
logger: logger,
|
||||
registry: registry,
|
||||
providerByTag: make(map[string]adapter.CertificateProviderService),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
m.access.Lock()
|
||||
if m.started && m.stage >= stage {
|
||||
panic("already started")
|
||||
}
|
||||
m.started = true
|
||||
m.stage = stage
|
||||
providers := m.providers
|
||||
m.access.Unlock()
|
||||
for _, provider := range providers {
|
||||
name := "certificate-provider/" + provider.Type() + "[" + provider.Tag() + "]"
|
||||
m.logger.Trace(stage, " ", name)
|
||||
startTime := time.Now()
|
||||
err := provider.Start(stage)
|
||||
err := scope.Start(name, provider, stage)
|
||||
if err != nil {
|
||||
return E.Cause(err, stage, " ", name)
|
||||
return err
|
||||
}
|
||||
m.logger.Trace(stage, " ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
if !m.started {
|
||||
return nil
|
||||
}
|
||||
m.started = false
|
||||
providers := m.providers
|
||||
m.providers = nil
|
||||
monitor := taskmonitor.New(m.logger, C.StopTimeout)
|
||||
var err error
|
||||
for _, provider := range providers {
|
||||
name := "certificate-provider/" + provider.Type() + "[" + provider.Tag() + "]"
|
||||
m.logger.Trace("close ", name)
|
||||
startTime := time.Now()
|
||||
monitor.Start("close ", name)
|
||||
err = E.Append(err, provider.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", name)
|
||||
})
|
||||
monitor.Finish()
|
||||
m.logger.Trace("close ", name, " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)")
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (m *Manager) CertificateProviders() []adapter.CertificateProviderService {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
|
||||
@@ -21,6 +21,7 @@ type EndpointRegistry interface {
|
||||
|
||||
type EndpointManager interface {
|
||||
Lifecycle
|
||||
StartEndpoint(endpoint Endpoint) error
|
||||
Endpoints() []Endpoint
|
||||
Get(tag string) (Endpoint, bool)
|
||||
Create(ctx context.Context, router Router, logger log.ContextLogger, tag string, endpointType string, options any) error
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
@@ -14,69 +12,41 @@ import (
|
||||
var _ adapter.EndpointManager = (*Manager)(nil)
|
||||
|
||||
type Manager struct {
|
||||
logger log.ContextLogger
|
||||
registry adapter.EndpointRegistry
|
||||
access sync.Mutex
|
||||
started bool
|
||||
stage adapter.StartStage
|
||||
scope *adapter.Scope
|
||||
endpoints []adapter.Endpoint
|
||||
endpointByTag map[string]adapter.Endpoint
|
||||
}
|
||||
|
||||
func NewManager(logger log.ContextLogger, registry adapter.EndpointRegistry) *Manager {
|
||||
func NewManager(registry adapter.EndpointRegistry) *Manager {
|
||||
return &Manager{
|
||||
logger: logger,
|
||||
registry: registry,
|
||||
endpointByTag: make(map[string]adapter.Endpoint),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
if m.started && m.stage >= stage {
|
||||
panic("already started")
|
||||
if stage == adapter.StartStateInitialize {
|
||||
m.scope = scope
|
||||
}
|
||||
m.started = true
|
||||
m.stage = stage
|
||||
if stage == adapter.StartStateStart {
|
||||
// started with outbound manager
|
||||
return nil
|
||||
}
|
||||
for _, endpoint := range m.endpoints {
|
||||
name := "endpoint/" + endpoint.Type() + "[" + endpoint.Tag() + "]"
|
||||
done := adapter.LogElapsed(m.logger, stage, " ", name)
|
||||
err := endpoint.Start(stage)
|
||||
done()
|
||||
err := scope.Start(name, endpoint, stage)
|
||||
if err != nil {
|
||||
return E.Cause(err, stage, " ", name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
if !m.started {
|
||||
return nil
|
||||
}
|
||||
m.started = false
|
||||
endpoints := m.endpoints
|
||||
m.endpoints = nil
|
||||
monitor := taskmonitor.New(m.logger, C.StopTimeout)
|
||||
var err error
|
||||
for _, endpoint := range endpoints {
|
||||
name := "endpoint/" + endpoint.Type() + "[" + endpoint.Tag() + "]"
|
||||
done := adapter.LogElapsed(m.logger, "close ", name)
|
||||
monitor.Start("close ", name)
|
||||
err = E.Append(err, endpoint.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", name)
|
||||
})
|
||||
monitor.Finish()
|
||||
done()
|
||||
}
|
||||
return nil
|
||||
func (m *Manager) StartEndpoint(endpoint adapter.Endpoint) error {
|
||||
return m.scope.Start("endpoint/"+endpoint.Type()+"["+endpoint.Tag()+"]", endpoint, adapter.StartStateStart)
|
||||
}
|
||||
|
||||
func (m *Manager) Endpoints() []adapter.Endpoint {
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
@@ -14,70 +12,35 @@ import (
|
||||
var _ adapter.InboundManager = (*Manager)(nil)
|
||||
|
||||
type Manager struct {
|
||||
logger log.ContextLogger
|
||||
registry adapter.InboundRegistry
|
||||
endpoint adapter.EndpointManager
|
||||
access sync.Mutex
|
||||
started bool
|
||||
stage adapter.StartStage
|
||||
inbounds []adapter.Inbound
|
||||
inboundByTag map[string]adapter.Inbound
|
||||
}
|
||||
|
||||
func NewManager(logger log.ContextLogger, registry adapter.InboundRegistry, endpoint adapter.EndpointManager) *Manager {
|
||||
func NewManager(registry adapter.InboundRegistry, endpoint adapter.EndpointManager) *Manager {
|
||||
return &Manager{
|
||||
logger: logger,
|
||||
registry: registry,
|
||||
endpoint: endpoint,
|
||||
inboundByTag: make(map[string]adapter.Inbound),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
m.access.Lock()
|
||||
if m.started && m.stage >= stage {
|
||||
panic("already started")
|
||||
}
|
||||
m.started = true
|
||||
m.stage = stage
|
||||
inbounds := m.inbounds
|
||||
m.access.Unlock()
|
||||
for _, inbound := range inbounds {
|
||||
name := "inbound/" + inbound.Type() + "[" + inbound.Tag() + "]"
|
||||
done := adapter.LogElapsed(m.logger, stage, " ", name)
|
||||
err := inbound.Start(stage)
|
||||
done()
|
||||
err := scope.Start(name, inbound, stage)
|
||||
if err != nil {
|
||||
return E.Cause(err, stage, " ", name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
if !m.started {
|
||||
return nil
|
||||
}
|
||||
m.started = false
|
||||
inbounds := m.inbounds
|
||||
m.inbounds = nil
|
||||
monitor := taskmonitor.New(m.logger, C.StopTimeout)
|
||||
var err error
|
||||
for _, inbound := range inbounds {
|
||||
name := "inbound/" + inbound.Type() + "[" + inbound.Tag() + "]"
|
||||
done := adapter.LogElapsed(m.logger, "close ", name)
|
||||
monitor.Start("close ", name)
|
||||
err = E.Append(err, inbound.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", name)
|
||||
})
|
||||
monitor.Finish()
|
||||
done()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Inbounds() []adapter.Inbound {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
|
||||
+76
-46
@@ -2,10 +2,12 @@ package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"reflect"
|
||||
"strings"
|
||||
"slices"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
@@ -48,8 +50,7 @@ func (s StartStage) String() string {
|
||||
}
|
||||
|
||||
type Lifecycle interface {
|
||||
Start(stage StartStage) error
|
||||
Close() error
|
||||
Start(stage StartStage, scope *Scope) error
|
||||
}
|
||||
|
||||
type LifecycleService interface {
|
||||
@@ -57,55 +58,84 @@ type LifecycleService interface {
|
||||
Lifecycle
|
||||
}
|
||||
|
||||
func getServiceName(service any) string {
|
||||
if named, ok := service.(interface {
|
||||
Type() string
|
||||
Tag() string
|
||||
}); ok {
|
||||
tag := named.Tag()
|
||||
if tag != "" {
|
||||
return named.Type() + "[" + tag + "]"
|
||||
}
|
||||
return named.Type()
|
||||
}
|
||||
t := reflect.TypeOf(service)
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
return strings.ToLower(t.Name())
|
||||
type Scope struct {
|
||||
ctx context.Context
|
||||
cancel context.CancelFunc
|
||||
logger log.ContextLogger
|
||||
access sync.Mutex
|
||||
cleanups []func() error
|
||||
children map[Lifecycle]*Scope
|
||||
}
|
||||
|
||||
func Start(ctx context.Context, logger log.ContextLogger, stage StartStage, services ...Lifecycle) error {
|
||||
for _, service := range services {
|
||||
err := ctx.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
name := getServiceName(service)
|
||||
done := LogElapsed(logger, stage, " ", name)
|
||||
err = service.Start(stage)
|
||||
done()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func NewScope(ctx context.Context, logger log.ContextLogger) *Scope {
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
return &Scope{
|
||||
ctx: ctx,
|
||||
cancel: cancel,
|
||||
logger: logger,
|
||||
children: make(map[Lifecycle]*Scope),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Scope) Context() context.Context {
|
||||
return s.ctx
|
||||
}
|
||||
|
||||
func (s *Scope) Add(cleanup func() error) {
|
||||
s.access.Lock()
|
||||
s.cleanups = append(s.cleanups, cleanup)
|
||||
s.access.Unlock()
|
||||
}
|
||||
|
||||
func (s *Scope) Start(name string, component Lifecycle, stage StartStage) error {
|
||||
s.access.Lock()
|
||||
err := s.ctx.Err()
|
||||
if err != nil {
|
||||
s.access.Unlock()
|
||||
return err
|
||||
}
|
||||
child, loaded := s.children[component]
|
||||
if !loaded {
|
||||
child = NewScope(s.ctx, s.logger)
|
||||
s.children[component] = child
|
||||
s.cleanups = append(s.cleanups, func() error {
|
||||
done := LogElapsed(s.logger, "close ", name)
|
||||
monitor := taskmonitor.New(s.logger, C.StopTimeout)
|
||||
monitor.Start("close ", name)
|
||||
closeErr := child.Close()
|
||||
monitor.Finish()
|
||||
done()
|
||||
if closeErr != nil {
|
||||
return E.Cause(closeErr, "close ", name)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
s.access.Unlock()
|
||||
done := LogElapsed(s.logger, stage, " ", name)
|
||||
monitor := taskmonitor.New(s.logger, C.StartTimeout)
|
||||
monitor.Start(stage, " ", name)
|
||||
err = component.Start(stage, child)
|
||||
monitor.Finish()
|
||||
done()
|
||||
if err != nil {
|
||||
return E.Cause(err, stage, " ", name)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func StartNamed(ctx context.Context, logger log.ContextLogger, stage StartStage, services []LifecycleService) error {
|
||||
for _, service := range services {
|
||||
err := ctx.Err()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
done := LogElapsed(logger, stage, " ", service.Name())
|
||||
err = service.Start(stage)
|
||||
done()
|
||||
if err != nil {
|
||||
return E.Cause(err, stage.String(), " ", service.Name())
|
||||
}
|
||||
func (s *Scope) Close() error {
|
||||
s.access.Lock()
|
||||
s.cancel()
|
||||
cleanups := s.cleanups
|
||||
s.cleanups = nil
|
||||
s.children = nil
|
||||
s.access.Unlock()
|
||||
var err error
|
||||
for _, cleanup := range slices.Backward(cleanups) {
|
||||
err = E.Errors(err, cleanup())
|
||||
}
|
||||
return nil
|
||||
return err
|
||||
}
|
||||
|
||||
func LogElapsed(logger log.ContextLogger, description ...any) func() {
|
||||
|
||||
+22
-71
@@ -2,39 +2,31 @@ package outbound
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
)
|
||||
|
||||
var _ adapter.OutboundManager = (*Manager)(nil)
|
||||
|
||||
type Manager struct {
|
||||
logger log.ContextLogger
|
||||
registry adapter.OutboundRegistry
|
||||
endpoint adapter.EndpointManager
|
||||
defaultTag string
|
||||
access sync.RWMutex
|
||||
started bool
|
||||
stage adapter.StartStage
|
||||
outbounds []adapter.Outbound
|
||||
outboundByTag map[string]adapter.Outbound
|
||||
defaultOutbound adapter.Outbound
|
||||
defaultOutboundFallback func() (adapter.Outbound, error)
|
||||
}
|
||||
|
||||
func NewManager(logger logger.ContextLogger, registry adapter.OutboundRegistry, endpoint adapter.EndpointManager, defaultTag string) *Manager {
|
||||
func NewManager(registry adapter.OutboundRegistry, endpoint adapter.EndpointManager, defaultTag string) *Manager {
|
||||
return &Manager{
|
||||
logger: logger,
|
||||
registry: registry,
|
||||
endpoint: endpoint,
|
||||
defaultTag: defaultTag,
|
||||
@@ -46,13 +38,8 @@ func (m *Manager) Initialize(defaultOutboundFallback func() (adapter.Outbound, e
|
||||
m.defaultOutboundFallback = defaultOutboundFallback
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
m.access.Lock()
|
||||
if m.started && m.stage >= stage {
|
||||
panic("already started")
|
||||
}
|
||||
m.started = true
|
||||
m.stage = stage
|
||||
if stage == adapter.StartStateInitialize {
|
||||
if m.defaultTag != "" && m.defaultOutbound == nil {
|
||||
defaultEndpoint, loaded := m.endpoint.Get(m.defaultTag)
|
||||
@@ -76,26 +63,23 @@ func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
outbounds := m.outbounds
|
||||
m.access.Unlock()
|
||||
if stage == adapter.StartStateStart {
|
||||
return m.startOutbounds(append(outbounds, common.Map(m.endpoint.Endpoints(), func(it adapter.Endpoint) adapter.Outbound { return it })...))
|
||||
return m.startOutbounds(scope, append(outbounds, common.Map(m.endpoint.Endpoints(), func(it adapter.Endpoint) adapter.Outbound { return it })...))
|
||||
}
|
||||
for _, outbound := range outbounds {
|
||||
starter, isStarter := outbound.(adapter.Lifecycle)
|
||||
if !isStarter {
|
||||
lifecycle, isLifecycle := outbound.(adapter.Lifecycle)
|
||||
if !isLifecycle {
|
||||
continue
|
||||
}
|
||||
name := "outbound/" + outbound.Type() + "[" + outbound.Tag() + "]"
|
||||
done := adapter.LogElapsed(m.logger, stage, " ", name)
|
||||
err := starter.Start(stage)
|
||||
done()
|
||||
err := scope.Start(name, lifecycle, stage)
|
||||
if err != nil {
|
||||
return E.Cause(err, stage, " ", name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) startOutbounds(outbounds []adapter.Outbound) error {
|
||||
monitor := taskmonitor.New(m.logger, C.StartTimeout)
|
||||
func (m *Manager) startOutbounds(scope *adapter.Scope, outbounds []adapter.Outbound) error {
|
||||
started := make(map[string]bool)
|
||||
for {
|
||||
canContinue := false
|
||||
@@ -113,27 +97,21 @@ func (m *Manager) startOutbounds(outbounds []adapter.Outbound) error {
|
||||
}
|
||||
started[outboundTag] = true
|
||||
canContinue = true
|
||||
if endpoint, isEndpoint := outboundToStart.(adapter.Endpoint); isEndpoint {
|
||||
err := m.endpoint.StartEndpoint(endpoint)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
lifecycle, isLifecycle := outboundToStart.(adapter.Lifecycle)
|
||||
if !isLifecycle {
|
||||
continue
|
||||
}
|
||||
name := "outbound/" + outboundToStart.Type() + "[" + outboundTag + "]"
|
||||
if starter, isStarter := outboundToStart.(adapter.Lifecycle); isStarter {
|
||||
done := adapter.LogElapsed(m.logger, "start ", name)
|
||||
monitor.Start("start ", name)
|
||||
err := starter.Start(adapter.StartStateStart)
|
||||
monitor.Finish()
|
||||
done()
|
||||
if err != nil {
|
||||
return E.Cause(err, "start ", name)
|
||||
}
|
||||
} else if starter, isStarter := outboundToStart.(interface {
|
||||
Start() error
|
||||
}); isStarter {
|
||||
done := adapter.LogElapsed(m.logger, "start ", name)
|
||||
monitor.Start("start ", name)
|
||||
err := starter.Start()
|
||||
monitor.Finish()
|
||||
done()
|
||||
if err != nil {
|
||||
return E.Cause(err, "start ", name)
|
||||
}
|
||||
err := scope.Start(name, lifecycle, adapter.StartStateStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(started) == len(outbounds) {
|
||||
@@ -166,33 +144,6 @@ func (m *Manager) startOutbounds(outbounds []adapter.Outbound) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
monitor := taskmonitor.New(m.logger, C.StopTimeout)
|
||||
m.access.Lock()
|
||||
if !m.started {
|
||||
m.access.Unlock()
|
||||
return nil
|
||||
}
|
||||
m.started = false
|
||||
outbounds := m.outbounds
|
||||
m.outbounds = nil
|
||||
m.access.Unlock()
|
||||
var err error
|
||||
for _, outbound := range outbounds {
|
||||
if closer, isCloser := outbound.(io.Closer); isCloser {
|
||||
name := "outbound/" + outbound.Type() + "[" + outbound.Tag() + "]"
|
||||
done := adapter.LogElapsed(m.logger, "close ", name)
|
||||
monitor.Start("close ", name)
|
||||
err = E.Append(err, closer.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", name)
|
||||
})
|
||||
monitor.Finish()
|
||||
done()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Outbounds() []adapter.Outbound {
|
||||
m.access.RLock()
|
||||
defer m.access.RUnlock()
|
||||
|
||||
@@ -5,8 +5,6 @@ import (
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
@@ -14,68 +12,33 @@ import (
|
||||
var _ adapter.ServiceManager = (*Manager)(nil)
|
||||
|
||||
type Manager struct {
|
||||
logger log.ContextLogger
|
||||
registry adapter.ServiceRegistry
|
||||
access sync.Mutex
|
||||
started bool
|
||||
stage adapter.StartStage
|
||||
services []adapter.Service
|
||||
serviceByTag map[string]adapter.Service
|
||||
}
|
||||
|
||||
func NewManager(logger log.ContextLogger, registry adapter.ServiceRegistry) *Manager {
|
||||
func NewManager(registry adapter.ServiceRegistry) *Manager {
|
||||
return &Manager{
|
||||
logger: logger,
|
||||
registry: registry,
|
||||
serviceByTag: make(map[string]adapter.Service),
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
m.access.Lock()
|
||||
if m.started && m.stage >= stage {
|
||||
panic("already started")
|
||||
}
|
||||
m.started = true
|
||||
m.stage = stage
|
||||
services := m.services
|
||||
m.access.Unlock()
|
||||
for _, service := range services {
|
||||
name := "service/" + service.Type() + "[" + service.Tag() + "]"
|
||||
done := adapter.LogElapsed(m.logger, stage, " ", name)
|
||||
err := service.Start(stage)
|
||||
done()
|
||||
err := scope.Start(name, service, stage)
|
||||
if err != nil {
|
||||
return E.Cause(err, stage, " ", name)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
if !m.started {
|
||||
return nil
|
||||
}
|
||||
m.started = false
|
||||
services := m.services
|
||||
m.services = nil
|
||||
monitor := taskmonitor.New(m.logger, C.StopTimeout)
|
||||
var err error
|
||||
for _, service := range services {
|
||||
name := "service/" + service.Type() + "[" + service.Tag() + "]"
|
||||
done := adapter.LogElapsed(m.logger, "close ", name)
|
||||
monitor.Start("close ", name)
|
||||
err = E.Append(err, service.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", name)
|
||||
})
|
||||
monitor.Finish()
|
||||
done()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Services() []adapter.Service {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
|
||||
@@ -2,11 +2,7 @@ package box
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
@@ -44,10 +40,8 @@ import (
|
||||
var _ adapter.SimpleLifecycle = (*Box)(nil)
|
||||
|
||||
type Box struct {
|
||||
ctx context.Context
|
||||
createdAt time.Time
|
||||
debugOptions option.DebugOptions
|
||||
debugHTTPServer *http.Server
|
||||
logFactory log.Factory
|
||||
logger log.ContextLogger
|
||||
network *route.NetworkManager
|
||||
@@ -64,7 +58,7 @@ type Box struct {
|
||||
httpClientService adapter.LifecycleService
|
||||
internalService []adapter.LifecycleService
|
||||
ntpService *ntp.Service
|
||||
done chan struct{}
|
||||
scope *adapter.Scope
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
@@ -211,12 +205,12 @@ func New(options Options) (*Box, error) {
|
||||
service.MustRegister[adapter.NetworkNamespaceManager](ctx, netnsManager)
|
||||
internalServices = append(internalServices, netnsManager)
|
||||
dnsOptions := common.PtrValueOrDefault(options.DNS)
|
||||
endpointManager := endpoint.NewManager(logFactory.NewLogger("endpoint"), endpointRegistry)
|
||||
inboundManager := inbound.NewManager(logFactory.NewLogger("inbound"), inboundRegistry, endpointManager)
|
||||
outboundManager := outbound.NewManager(logFactory.NewLogger("outbound"), outboundRegistry, endpointManager, routeOptions.Final)
|
||||
dnsTransportManager := dns.NewTransportManager(logFactory.NewLogger("dns/transport"), dnsTransportRegistry, outboundManager, dnsOptions.Final)
|
||||
serviceManager := boxService.NewManager(logFactory.NewLogger("service"), serviceRegistry)
|
||||
certificateProviderManager := boxCertificate.NewManager(logFactory.NewLogger("certificate-provider"), certificateProviderRegistry)
|
||||
endpointManager := endpoint.NewManager(endpointRegistry)
|
||||
inboundManager := inbound.NewManager(inboundRegistry, endpointManager)
|
||||
outboundManager := outbound.NewManager(outboundRegistry, endpointManager, routeOptions.Final)
|
||||
dnsTransportManager := dns.NewTransportManager(dnsTransportRegistry, outboundManager, dnsOptions.Final)
|
||||
serviceManager := boxService.NewManager(serviceRegistry)
|
||||
certificateProviderManager := boxCertificate.NewManager(certificateProviderRegistry)
|
||||
service.MustRegister[adapter.EndpointManager](ctx, endpointManager)
|
||||
service.MustRegister[adapter.InboundManager](ctx, inboundManager)
|
||||
service.MustRegister[adapter.OutboundManager](ctx, outboundManager)
|
||||
@@ -472,7 +466,6 @@ func New(options Options) (*Box, error) {
|
||||
timeService.TimeService = ntpService
|
||||
}
|
||||
return &Box{
|
||||
ctx: ctx,
|
||||
network: networkManager,
|
||||
endpoint: endpointManager,
|
||||
inbound: inboundManager,
|
||||
@@ -491,22 +484,13 @@ func New(options Options) (*Box, error) {
|
||||
logger: logFactory.Logger(),
|
||||
internalService: internalServices,
|
||||
ntpService: ntpService,
|
||||
done: make(chan struct{}),
|
||||
scope: adapter.NewScope(ctx, logFactory.Logger()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Box) PreStart() error {
|
||||
err := s.preStart()
|
||||
if err != nil {
|
||||
// TODO: remove catch error
|
||||
defer func() {
|
||||
v := recover()
|
||||
if v != nil {
|
||||
println(err.Error())
|
||||
debug.PrintStack()
|
||||
panic("panic on early close: " + fmt.Sprint(v))
|
||||
}
|
||||
}()
|
||||
s.Close()
|
||||
return err
|
||||
}
|
||||
@@ -517,15 +501,6 @@ func (s *Box) PreStart() error {
|
||||
func (s *Box) Start() error {
|
||||
err := s.start()
|
||||
if err != nil {
|
||||
// TODO: remove catch error
|
||||
defer func() {
|
||||
v := recover()
|
||||
if v != nil {
|
||||
println(err.Error())
|
||||
debug.PrintStack()
|
||||
println("panic on early start: " + fmt.Sprint(v))
|
||||
}
|
||||
}()
|
||||
s.Close()
|
||||
return err
|
||||
}
|
||||
@@ -533,6 +508,31 @@ func (s *Box) Start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
type boxComponent struct {
|
||||
name string
|
||||
lifecycle adapter.Lifecycle
|
||||
}
|
||||
|
||||
func (s *Box) startComponents(stage adapter.StartStage, components ...boxComponent) error {
|
||||
for _, component := range components {
|
||||
err := s.scope.Start(component.name, component.lifecycle, stage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Box) startInternalServices(stage adapter.StartStage) error {
|
||||
for _, lifecycleService := range s.internalService {
|
||||
err := s.scope.Start(lifecycleService.Name(), lifecycleService, stage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Box) preStart() error {
|
||||
monitor := taskmonitor.New(s.logger, C.StartTimeout)
|
||||
monitor.Start("start logger")
|
||||
@@ -541,28 +541,44 @@ func (s *Box) preStart() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "start logger")
|
||||
}
|
||||
s.scope.Add(s.logFactory.Close)
|
||||
applyDebugOptions(s.debugOptions)
|
||||
s.debugHTTPServer, err = startDebugHTTPServer(s.debugOptions)
|
||||
debugHTTPServer, err := startDebugHTTPServer(s.debugOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.StartNamed(s.ctx, s.logger, adapter.StartStateInitialize, s.internalService) // cache-file clash-api v2ray-api
|
||||
if debugHTTPServer != nil {
|
||||
s.scope.Add(debugHTTPServer.Close)
|
||||
}
|
||||
err = s.startInternalServices(adapter.StartStateInitialize) // cache-file clash-api v2ray-api
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.Start(s.ctx, s.logger, adapter.StartStateInitialize, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.inbound, s.endpoint, s.service, s.certificateProvider)
|
||||
err = s.startComponents(adapter.StartStateInitialize,
|
||||
boxComponent{s.httpClientService.Name(), s.httpClientService},
|
||||
boxComponent{"network", s.network},
|
||||
boxComponent{"dns-transport", s.dnsTransport},
|
||||
boxComponent{"dns-router", s.dnsRouter},
|
||||
boxComponent{"connection", s.connection},
|
||||
boxComponent{"router", s.router},
|
||||
boxComponent{"outbound", s.outbound},
|
||||
boxComponent{"endpoint", s.endpoint},
|
||||
boxComponent{"certificate-provider", s.certificateProvider},
|
||||
boxComponent{"inbound", s.inbound},
|
||||
boxComponent{"service", s.service},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.Start(s.ctx, s.logger, adapter.StartStateStart, s.outbound, s.dnsTransport, s.network, s.connection)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.StartNamed(s.ctx, s.logger, adapter.StartStateStart, []adapter.LifecycleService{s.httpClientService})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.Start(s.ctx, s.logger, adapter.StartStateStart, s.router, s.dnsRouter)
|
||||
err = s.startComponents(adapter.StartStateStart,
|
||||
boxComponent{"outbound", s.outbound},
|
||||
boxComponent{"dns-transport", s.dnsTransport},
|
||||
boxComponent{"network", s.network},
|
||||
boxComponent{"connection", s.connection},
|
||||
boxComponent{s.httpClientService.Name(), s.httpClientService},
|
||||
boxComponent{"router", s.router},
|
||||
boxComponent{"dns-router", s.dnsRouter},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -574,7 +590,7 @@ func (s *Box) start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.StartNamed(s.ctx, s.logger, adapter.StartStateStart, s.internalService)
|
||||
err = s.startInternalServices(adapter.StartStateStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -585,32 +601,52 @@ func (s *Box) start() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "start ntp service")
|
||||
}
|
||||
s.scope.Add(s.ntpService.Close)
|
||||
}
|
||||
err = adapter.Start(s.ctx, s.logger, adapter.StartStateStart, s.endpoint)
|
||||
err = s.startComponents(adapter.StartStateStart,
|
||||
boxComponent{"endpoint", s.endpoint},
|
||||
boxComponent{"certificate-provider", s.certificateProvider},
|
||||
boxComponent{"inbound", s.inbound},
|
||||
boxComponent{"service", s.service},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.Start(s.ctx, s.logger, adapter.StartStateStart, s.certificateProvider)
|
||||
err = s.startComponents(adapter.StartStatePostStart,
|
||||
boxComponent{"outbound", s.outbound},
|
||||
boxComponent{"network", s.network},
|
||||
boxComponent{"dns-transport", s.dnsTransport},
|
||||
boxComponent{"dns-router", s.dnsRouter},
|
||||
boxComponent{"connection", s.connection},
|
||||
boxComponent{"router", s.router},
|
||||
boxComponent{"endpoint", s.endpoint},
|
||||
boxComponent{"certificate-provider", s.certificateProvider},
|
||||
boxComponent{"inbound", s.inbound},
|
||||
boxComponent{"service", s.service},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.Start(s.ctx, s.logger, adapter.StartStateStart, s.inbound, s.service)
|
||||
err = s.startInternalServices(adapter.StartStatePostStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.Start(s.ctx, s.logger, adapter.StartStatePostStart, s.outbound, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.endpoint, s.certificateProvider, s.inbound, s.service)
|
||||
err = s.startComponents(adapter.StartStateStarted,
|
||||
boxComponent{"network", s.network},
|
||||
boxComponent{"dns-transport", s.dnsTransport},
|
||||
boxComponent{"dns-router", s.dnsRouter},
|
||||
boxComponent{"connection", s.connection},
|
||||
boxComponent{"router", s.router},
|
||||
boxComponent{"outbound", s.outbound},
|
||||
boxComponent{"endpoint", s.endpoint},
|
||||
boxComponent{"certificate-provider", s.certificateProvider},
|
||||
boxComponent{"inbound", s.inbound},
|
||||
boxComponent{"service", s.service},
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.StartNamed(s.ctx, s.logger, adapter.StartStatePostStart, s.internalService)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.Start(s.ctx, s.logger, adapter.StartStateStarted, s.network, s.dnsTransport, s.dnsRouter, s.connection, s.router, s.outbound, s.endpoint, s.certificateProvider, s.inbound, s.service)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.StartNamed(s.ctx, s.logger, adapter.StartStateStarted, s.internalService)
|
||||
err = s.startInternalServices(adapter.StartStateStarted)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -618,68 +654,7 @@ func (s *Box) start() error {
|
||||
}
|
||||
|
||||
func (s *Box) Close() error {
|
||||
select {
|
||||
case <-s.done:
|
||||
return os.ErrClosed
|
||||
default:
|
||||
close(s.done)
|
||||
}
|
||||
var err error
|
||||
if s.debugHTTPServer != nil {
|
||||
err = E.Append(err, s.debugHTTPServer.Close(), func(err error) error {
|
||||
return E.Cause(err, "close debug HTTP server")
|
||||
})
|
||||
s.debugHTTPServer = nil
|
||||
}
|
||||
for _, closeItem := range []struct {
|
||||
name string
|
||||
service adapter.Lifecycle
|
||||
}{
|
||||
{"service", s.service},
|
||||
{"inbound", s.inbound},
|
||||
{"certificate-provider", s.certificateProvider},
|
||||
{"endpoint", s.endpoint},
|
||||
{"outbound", s.outbound},
|
||||
{"router", s.router},
|
||||
{"connection", s.connection},
|
||||
{"dns-router", s.dnsRouter},
|
||||
{"dns-transport", s.dnsTransport},
|
||||
{"network", s.network},
|
||||
} {
|
||||
done := adapter.LogElapsed(s.logger, "close ", closeItem.name)
|
||||
err = E.Append(err, closeItem.service.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", closeItem.name)
|
||||
})
|
||||
done()
|
||||
}
|
||||
if s.httpClientService != nil {
|
||||
s.logger.Trace("close ", s.httpClientService.Name())
|
||||
startTime := time.Now()
|
||||
err = E.Append(err, s.httpClientService.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", s.httpClientService.Name())
|
||||
})
|
||||
s.logger.Trace("close ", s.httpClientService.Name(), " completed (", F.Seconds(time.Since(startTime).Seconds()), "s)")
|
||||
}
|
||||
for _, lifecycleService := range s.internalService {
|
||||
done := adapter.LogElapsed(s.logger, "close ", lifecycleService.Name())
|
||||
err = E.Append(err, lifecycleService.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", lifecycleService.Name())
|
||||
})
|
||||
done()
|
||||
}
|
||||
if s.ntpService != nil {
|
||||
done := adapter.LogElapsed(s.logger, "close ntp service")
|
||||
err = E.Append(err, s.ntpService.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ntp service")
|
||||
})
|
||||
done()
|
||||
}
|
||||
done := adapter.LogElapsed(s.logger, "close logger")
|
||||
err = E.Append(err, s.logFactory.Close(), func(err error) error {
|
||||
return E.Cause(err, "close logger")
|
||||
})
|
||||
done()
|
||||
return err
|
||||
return s.scope.Close()
|
||||
}
|
||||
|
||||
func (s *Box) Network() adapter.NetworkManager {
|
||||
|
||||
+42
-33
@@ -31,6 +31,7 @@ type Store struct {
|
||||
certificatePaths []string
|
||||
certificateDirectoryPaths []string
|
||||
watcher *fswatch.Watcher
|
||||
anchorPEM []byte
|
||||
//nolint:unused // populated only on darwin && cgo via the storePlatform embed.
|
||||
platform storePlatform
|
||||
}
|
||||
@@ -92,10 +93,12 @@ func NewStore(ctx context.Context, logger logger.Logger, options option.Certific
|
||||
}
|
||||
store.watcher = watcher
|
||||
}
|
||||
err := store.update()
|
||||
currentPool, anchorPEM, err := store.load()
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "initializing certificate store")
|
||||
}
|
||||
store.currentPool = currentPool
|
||||
store.anchorPEM = anchorPEM
|
||||
return store, nil
|
||||
}
|
||||
|
||||
@@ -103,31 +106,28 @@ func (s *Store) Name() string {
|
||||
return "certificate"
|
||||
}
|
||||
|
||||
func (s *Store) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
if s.watcher != nil {
|
||||
return s.watcher.Start()
|
||||
func (s *Store) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
s.access.Lock()
|
||||
err := s.updatePlatformLocked(s.anchorPEM)
|
||||
s.access.Unlock()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(s.closePlatform)
|
||||
case adapter.StartStateStart:
|
||||
if s.watcher != nil {
|
||||
err := s.watcher.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(s.watcher.Close)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) Close() error {
|
||||
watcher := s.watcher
|
||||
s.watcher = nil
|
||||
|
||||
var closeErr error
|
||||
if watcher != nil {
|
||||
closeErr = watcher.Close()
|
||||
}
|
||||
platformErr := s.closePlatform()
|
||||
if platformErr != nil {
|
||||
closeErr = platformErr
|
||||
}
|
||||
return closeErr
|
||||
}
|
||||
|
||||
func (s *Store) Pool() *x509.CertPool {
|
||||
s.access.RLock()
|
||||
defer s.access.RUnlock()
|
||||
@@ -143,38 +143,50 @@ func (s *Store) ExclusiveAnchors() bool {
|
||||
}
|
||||
|
||||
func (s *Store) update() error {
|
||||
currentPool, err := s.newBasePool()
|
||||
currentPool, anchorPEM, err := s.load()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.access.Lock()
|
||||
defer s.access.Unlock()
|
||||
s.currentPool = currentPool
|
||||
s.anchorPEM = anchorPEM
|
||||
return s.updatePlatformLocked(anchorPEM)
|
||||
}
|
||||
|
||||
func (s *Store) load() (*x509.CertPool, []byte, error) {
|
||||
currentPool, err := s.newBasePool()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pemBuffer := new(bytes.Buffer)
|
||||
switch s.storeType {
|
||||
case C.CertificateStoreMozilla:
|
||||
pemContent := mozillaIncludedPEM()
|
||||
if !currentPool.AppendCertsFromPEM([]byte(pemContent)) {
|
||||
return E.New("invalid Mozilla included certificate PEM")
|
||||
return nil, nil, E.New("invalid Mozilla included certificate PEM")
|
||||
}
|
||||
appendPEMBlock(pemBuffer, string(pemContent))
|
||||
case C.CertificateStoreChrome:
|
||||
pemContent := chromeIncludedPEM()
|
||||
if !currentPool.AppendCertsFromPEM([]byte(pemContent)) {
|
||||
return E.New("invalid Chrome included certificate PEM")
|
||||
return nil, nil, E.New("invalid Chrome included certificate PEM")
|
||||
}
|
||||
appendPEMBlock(pemBuffer, string(pemContent))
|
||||
}
|
||||
if s.certificate != "" {
|
||||
if !currentPool.AppendCertsFromPEM([]byte(s.certificate)) {
|
||||
return E.New("invalid certificate PEM strings")
|
||||
return nil, nil, E.New("invalid certificate PEM strings")
|
||||
}
|
||||
appendPEMBlock(pemBuffer, s.certificate)
|
||||
}
|
||||
for _, path := range s.certificatePaths {
|
||||
pemContent, err := filemanager.ReadFile(s.ctx, path)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, nil, err
|
||||
}
|
||||
if !currentPool.AppendCertsFromPEM(pemContent) {
|
||||
return E.New("invalid certificate PEM file: ", path)
|
||||
return nil, nil, E.New("invalid certificate PEM file: ", path)
|
||||
}
|
||||
appendPEMBlock(pemBuffer, string(pemContent))
|
||||
}
|
||||
@@ -195,12 +207,9 @@ func (s *Store) update() error {
|
||||
}
|
||||
}
|
||||
if firstErr != nil {
|
||||
return firstErr
|
||||
return nil, nil, firstErr
|
||||
}
|
||||
s.access.Lock()
|
||||
defer s.access.Unlock()
|
||||
s.currentPool = currentPool
|
||||
return s.updatePlatformLocked(pemBuffer.Bytes())
|
||||
return currentPool, pemBuffer.Bytes(), nil
|
||||
}
|
||||
|
||||
func appendPEMBlock(buffer *bytes.Buffer, block string) {
|
||||
|
||||
@@ -61,7 +61,7 @@ func (m *Manager) Name() string {
|
||||
return "http-client"
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -72,6 +72,7 @@ func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
m.defaultTransport = sharedTransport
|
||||
}
|
||||
scope.Add(m.close)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -163,12 +164,9 @@ func (m *Manager) ResetNetwork() {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
func (m *Manager) close() error {
|
||||
m.access.Lock()
|
||||
defer m.access.Unlock()
|
||||
if m.managedTransports == nil {
|
||||
return nil
|
||||
}
|
||||
var err error
|
||||
for _, transport := range m.managedTransports {
|
||||
err = E.Append(err, transport.close(), func(err error) error {
|
||||
|
||||
@@ -89,7 +89,7 @@ func (l *Listener) Start() error {
|
||||
if common.Contains(l.network, N.NetworkUDP) {
|
||||
_, err := l.ListenUDP()
|
||||
if err != nil {
|
||||
return err
|
||||
return E.Errors(err, l.Close())
|
||||
}
|
||||
l.packetOutboundClosed = make(chan struct{})
|
||||
l.packetOutbound = make(chan *N.PacketBuffer, 64)
|
||||
@@ -109,11 +109,11 @@ func (l *Listener) Start() error {
|
||||
}
|
||||
systemProxy, err := settings.NewSystemProxy(l.ctx, M.ParseSocksaddrHostPort(listenAddrString, listenPort), l.systemProxySOCKS, nil)
|
||||
if err != nil {
|
||||
return E.Cause(err, "initialize system proxy")
|
||||
return E.Errors(E.Cause(err, "initialize system proxy"), l.Close())
|
||||
}
|
||||
err = systemProxy.Enable()
|
||||
if err != nil {
|
||||
return E.Errors(E.Cause(err, "set system proxy"), systemProxy.Close())
|
||||
return E.Errors(E.Cause(err, "set system proxy"), systemProxy.Close(), l.Close())
|
||||
}
|
||||
l.systemProxy = systemProxy
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ type Manager struct {
|
||||
namespaces []option.NetworkNamespace
|
||||
holderArgs []string
|
||||
paths map[string]string
|
||||
holders []*holder
|
||||
}
|
||||
|
||||
type holder struct {
|
||||
@@ -64,7 +63,7 @@ func (m *Manager) Name() string {
|
||||
return "netns"
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
@@ -80,7 +79,7 @@ func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
return E.Cause(err, "network namespace[", namespace.Tag, "]")
|
||||
}
|
||||
case C.NetNsTypeUnshare:
|
||||
err := m.startNamespace(namespace)
|
||||
err := m.startNamespace(namespace, scope)
|
||||
if err != nil {
|
||||
return E.Cause(err, "network namespace[", namespace.Tag, "]")
|
||||
}
|
||||
@@ -89,7 +88,7 @@ func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) startNamespace(namespace option.NetworkNamespace) error {
|
||||
func (m *Manager) startNamespace(namespace option.NetworkNamespace, scope *adapter.Scope) error {
|
||||
if len(m.holderArgs) == 0 {
|
||||
return E.New("unshare network namespace is only supported in `sing-box run`")
|
||||
}
|
||||
@@ -97,7 +96,13 @@ func (m *Manager) startNamespace(namespace option.NetworkNamespace) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
m.holders = append(m.holders, created)
|
||||
scope.Add(func() error {
|
||||
created.pipeWriter.Close()
|
||||
if created.pidFile != "" {
|
||||
os.Remove(created.pidFile)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
pid := created.command.Process.Pid
|
||||
if created.pidFile != "" {
|
||||
err = os.WriteFile(created.pidFile, []byte(strconv.Itoa(pid)+"\n"), 0o644)
|
||||
@@ -115,17 +120,6 @@ func (m *Manager) startNamespace(namespace option.NetworkNamespace) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
for _, created := range m.holders {
|
||||
created.pipeWriter.Close()
|
||||
if created.pidFile != "" {
|
||||
os.Remove(created.pidFile)
|
||||
}
|
||||
}
|
||||
m.holders = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) ResolvePath(nameOrPath string) string {
|
||||
path, loaded := m.paths[nameOrPath]
|
||||
if loaded && path != "" {
|
||||
|
||||
@@ -22,11 +22,7 @@ func (m *Manager) Name() string {
|
||||
return "netns"
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@ package netns
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"os"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -12,6 +13,7 @@ import (
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
@@ -39,11 +41,11 @@ func TestUnshareNamespace(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = manager.Start(adapter.StartStateInitialize)
|
||||
scope := adapter.NewScope(context.Background(), log.NewNOPFactory().Logger())
|
||||
err = manager.Start(adapter.StartStateInitialize, scope)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer manager.Close()
|
||||
|
||||
pipeReader.SetReadDeadline(time.Now().Add(10 * time.Second))
|
||||
pidLine, err := bufio.NewReader(pipeReader).ReadString('\n')
|
||||
@@ -71,7 +73,7 @@ func TestUnshareNamespace(t *testing.T) {
|
||||
t.Fatal("holder is in the current netns")
|
||||
}
|
||||
|
||||
err = manager.Close()
|
||||
err = scope.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
+6
-1
@@ -49,9 +49,14 @@ func (w *acmeWrapper) Start() error {
|
||||
Logger: w.zapLogger,
|
||||
})
|
||||
config = certmagic.New(cache, *config)
|
||||
err := config.ManageSync(w.ctx, w.domain)
|
||||
if err != nil {
|
||||
cache.Stop()
|
||||
return err
|
||||
}
|
||||
w.cfg = config
|
||||
w.cache = cache
|
||||
return w.cfg.ManageSync(w.ctx, w.domain)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *acmeWrapper) Close() error {
|
||||
|
||||
@@ -57,21 +57,26 @@ func (p *sharedCertificateProvider) GetACMENextProtos() []string {
|
||||
}
|
||||
|
||||
type inlineCertificateProvider struct {
|
||||
ctx context.Context
|
||||
logger log.ContextLogger
|
||||
provider adapter.CertificateProviderService
|
||||
scope *adapter.Scope
|
||||
}
|
||||
|
||||
func (p *inlineCertificateProvider) Start() error {
|
||||
p.scope = adapter.NewScope(p.ctx, p.logger)
|
||||
name := "certificate-provider/" + p.provider.Type()
|
||||
for _, stage := range adapter.ListStartStages {
|
||||
err := p.provider.Start(stage)
|
||||
err := p.scope.Start(name, p.provider, stage)
|
||||
if err != nil {
|
||||
return err
|
||||
return E.Errors(err, p.scope.Close())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *inlineCertificateProvider) Close() error {
|
||||
return p.provider.Close()
|
||||
return p.scope.Close()
|
||||
}
|
||||
|
||||
func (p *inlineCertificateProvider) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
@@ -548,6 +553,8 @@ func newCertificateProvider(ctx context.Context, logger log.ContextLogger, optio
|
||||
return nil, E.Cause(err, "create inline certificate provider")
|
||||
}
|
||||
return &inlineCertificateProvider{
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
provider: provider,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -45,7 +45,6 @@ type Manager struct {
|
||||
|
||||
eventSubscriber *observable.Subscriber[ConnectionEvent]
|
||||
eventObserver *observable.Observer[ConnectionEvent]
|
||||
cleaner *cleanup.Cleaner
|
||||
}
|
||||
|
||||
func NewManager(outbound adapter.OutboundManager) *Manager {
|
||||
@@ -59,20 +58,15 @@ func (m *Manager) Name() string {
|
||||
return "traffic manager"
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage == adapter.StartStateInitialize {
|
||||
m.eventObserver = observable.NewObserver(m.eventSubscriber, 64)
|
||||
m.cleaner = cleanup.Add(m.Clear)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
if m.cleaner != nil {
|
||||
m.cleaner.Close()
|
||||
}
|
||||
if m.eventObserver != nil {
|
||||
return m.eventObserver.Close()
|
||||
scope.Add(m.eventObserver.Close)
|
||||
cleaner := cleanup.Add(m.Clear)
|
||||
scope.Add(func() error {
|
||||
cleaner.Close()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+10
-15
@@ -129,10 +129,19 @@ func (r *Router) Initialize(rules []option.DNSRule) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Start(stage adapter.StartStage) error {
|
||||
func (r *Router) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
monitor := taskmonitor.New(r.logger, C.StartTimeout)
|
||||
switch stage {
|
||||
case adapter.StartStateStart:
|
||||
scope.Add(func() error {
|
||||
r.rulesAccess.Lock()
|
||||
r.closing = true
|
||||
runtimeRules := r.rules
|
||||
r.rules = nil
|
||||
r.rulesAccess.Unlock()
|
||||
closeRules(runtimeRules)
|
||||
return nil
|
||||
})
|
||||
monitor.Start("initialize DNS client")
|
||||
r.client.Start()
|
||||
monitor.Finish()
|
||||
@@ -163,20 +172,6 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Close() error {
|
||||
r.rulesAccess.Lock()
|
||||
if r.closing {
|
||||
r.rulesAccess.Unlock()
|
||||
return nil
|
||||
}
|
||||
r.closing = true
|
||||
runtimeRules := r.rules
|
||||
r.rules = nil
|
||||
r.rulesAccess.Unlock()
|
||||
closeRules(runtimeRules)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) buildRules(startRules bool) ([]adapter.DNSRule, bool, dnsRuleModeFlags, error) {
|
||||
for i, ruleOptions := range r.rawRules {
|
||||
err := R.ValidateNoNestedDNSRuleActions(ruleOptions)
|
||||
|
||||
+2
-10
@@ -31,11 +31,7 @@ type fakeDNSTransport struct {
|
||||
firstQueried time.Time
|
||||
}
|
||||
|
||||
func (t *fakeDNSTransport) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *fakeDNSTransport) Close() error {
|
||||
func (t *fakeDNSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -90,11 +86,7 @@ type fakeDNSTransportManager struct {
|
||||
defaultTransport adapter.DNSTransport
|
||||
}
|
||||
|
||||
func (m *fakeDNSTransportManager) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *fakeDNSTransportManager) Close() error {
|
||||
func (m *fakeDNSTransportManager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+29
-46
@@ -18,7 +18,6 @@ import (
|
||||
"github.com/sagernet/sing-box/dns/transport"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/buf"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
@@ -27,7 +26,6 @@ import (
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/task"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
"github.com/insomniacslk/dhcp/dhcpv4"
|
||||
@@ -54,7 +52,6 @@ type Transport struct {
|
||||
networkManager adapter.NetworkManager
|
||||
platformInterface adapter.PlatformInterface
|
||||
interfaceName string
|
||||
interfaceCallback *list.Element[tun.DefaultInterfaceUpdateCallback]
|
||||
updateAccess sync.Mutex
|
||||
updateCancel context.CancelFunc
|
||||
refreshAccess sync.Mutex
|
||||
@@ -70,6 +67,7 @@ type transportState struct {
|
||||
search []string
|
||||
servers []M.Socksaddr
|
||||
serverTransports []adapter.DNSTransport
|
||||
serverScope *adapter.Scope
|
||||
}
|
||||
|
||||
func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.DHCPDNSServerOptions) (adapter.DNSTransport, error) {
|
||||
@@ -104,19 +102,29 @@ func NewRawTransport(transportAdapter dns.TransportAdapter, ctx context.Context,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
func (t *Transport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
scope.Add(func() error {
|
||||
t.Reset()
|
||||
return nil
|
||||
})
|
||||
if t.interfaceName == "" {
|
||||
interfaceMonitor := t.networkManager.InterfaceMonitor()
|
||||
if interfaceMonitor == nil {
|
||||
return E.New("missing monitor for auto DHCP, set route.auto_detect_interface")
|
||||
}
|
||||
t.interfaceCallback = interfaceMonitor.RegisterCallback(t.interfaceUpdated)
|
||||
interfaceCallback := interfaceMonitor.RegisterCallback(func(defaultInterface *control.Interface, flags int) {
|
||||
t.interfaceUpdated(scope.Context())
|
||||
})
|
||||
scope.Add(func() error {
|
||||
interfaceMonitor.UnregisterCallback(interfaceCallback)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
go func() {
|
||||
err := t.fetch()
|
||||
err := t.fetch(scope.Context())
|
||||
if err != nil {
|
||||
if errors.Is(err, errInterfaceIsCellular) && t.optional {
|
||||
t.logger.Debug(E.Cause(errInterfaceIsCellular, "dhcp: fetch DNS servers"))
|
||||
@@ -128,32 +136,12 @@ func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
if t.interfaceCallback != nil {
|
||||
t.networkManager.InterfaceMonitor().UnregisterCallback(t.interfaceCallback)
|
||||
}
|
||||
t.updateAccess.Lock()
|
||||
updateCancel := t.updateCancel
|
||||
t.updateCancel = nil
|
||||
t.updateAccess.Unlock()
|
||||
if updateCancel != nil {
|
||||
updateCancel()
|
||||
}
|
||||
t.refreshAccess.Lock()
|
||||
defer t.refreshAccess.Unlock()
|
||||
state := t.savedState.Swap(nil)
|
||||
if state != nil {
|
||||
closeServerTransports(state.serverTransports)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Reset() {
|
||||
t.refreshAccess.Lock()
|
||||
defer t.refreshAccess.Unlock()
|
||||
state := t.savedState.Swap(nil)
|
||||
if state != nil {
|
||||
closeServerTransports(state.serverTransports)
|
||||
if state != nil && state.serverScope != nil {
|
||||
state.serverScope.Close()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,12 +157,6 @@ func (t *Transport) Environment() []string {
|
||||
return append(environment, state.search...)
|
||||
}
|
||||
|
||||
func closeServerTransports(serverTransports []adapter.DNSTransport) {
|
||||
for _, serverTransport := range serverTransports {
|
||||
serverTransport.Close()
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
|
||||
done := make(chan struct{})
|
||||
var (
|
||||
@@ -211,7 +193,7 @@ func (t *Transport) ExchangeAsync(ctx context.Context, message *mDNS.Msg, callba
|
||||
}
|
||||
|
||||
func (t *Transport) exchangeCold(ctx context.Context, message *mDNS.Msg, callback func(response *mDNS.Msg, err error)) {
|
||||
err := t.fetch()
|
||||
err := t.fetch(t.ctx)
|
||||
if err != nil {
|
||||
callback(nil, E.Cause(err, "dhcp: fetch DNS servers"))
|
||||
return
|
||||
@@ -235,7 +217,7 @@ func (t *Transport) Fetch() []M.Socksaddr {
|
||||
return state.servers
|
||||
}
|
||||
|
||||
func (t *Transport) fetch() error {
|
||||
func (t *Transport) fetch(ctx context.Context) error {
|
||||
state := t.savedState.Load()
|
||||
if state != nil {
|
||||
if state.lastError != nil {
|
||||
@@ -256,7 +238,7 @@ func (t *Transport) fetch() error {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return t.updateServersLocked(t.ctx)
|
||||
return t.updateServersLocked(ctx)
|
||||
}
|
||||
|
||||
func (t *Transport) startRefresh() {
|
||||
@@ -342,12 +324,13 @@ func (t *Transport) storeFailureLocked(err error) {
|
||||
newState.search = previousState.search
|
||||
newState.servers = previousState.servers
|
||||
newState.serverTransports = previousState.serverTransports
|
||||
newState.serverScope = previousState.serverScope
|
||||
}
|
||||
t.savedState.Store(newState)
|
||||
}
|
||||
|
||||
func (t *Transport) interfaceUpdated(defaultInterface *control.Interface, flags int) {
|
||||
updateContext, updateCancel := context.WithCancel(t.ctx)
|
||||
func (t *Transport) interfaceUpdated(ctx context.Context) {
|
||||
updateContext, updateCancel := context.WithCancel(ctx)
|
||||
t.updateAccess.Lock()
|
||||
previousCancel := t.updateCancel
|
||||
t.updateCancel = updateCancel
|
||||
@@ -483,25 +466,25 @@ func (t *Transport) recreateServersLocked(iface *control.Interface, dhcpPacket *
|
||||
}
|
||||
if serversUnchanged && previousState.serverTransports != nil {
|
||||
newState.serverTransports = previousState.serverTransports
|
||||
newState.serverScope = previousState.serverScope
|
||||
t.savedState.Store(newState)
|
||||
return nil
|
||||
}
|
||||
serverScope := adapter.NewScope(t.ctx, t.logger)
|
||||
serverTransports := make([]adapter.DNSTransport, 0, len(newState.servers))
|
||||
for _, serverAddr := range newState.servers {
|
||||
serverTransport := transport.NewUDPRaw(t.logger, dns.NewTransportAdapter(C.DNSTypeUDP, "", nil), t.dialer, serverAddr)
|
||||
err := serverTransport.Start(adapter.StartStateStart)
|
||||
err := serverTransport.Start(adapter.StartStateStart, serverScope)
|
||||
if err != nil {
|
||||
for _, startedTransport := range serverTransports {
|
||||
startedTransport.Close()
|
||||
}
|
||||
return E.Cause(err, "initialize transport for ", serverAddr)
|
||||
return E.Errors(E.Cause(err, "initialize transport for ", serverAddr), serverScope.Close())
|
||||
}
|
||||
serverTransports = append(serverTransports, serverTransport)
|
||||
}
|
||||
newState.serverTransports = serverTransports
|
||||
newState.serverScope = serverScope
|
||||
t.savedState.Store(newState)
|
||||
if previousState != nil {
|
||||
closeServerTransports(previousState.serverTransports)
|
||||
if previousState != nil && previousState.serverScope != nil {
|
||||
previousState.serverScope.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -45,15 +45,16 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
func (t *Transport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return t.store.Start()
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
return t.store.Close()
|
||||
err := t.store.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(t.store.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Reset() {
|
||||
|
||||
@@ -58,11 +58,7 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
func (t *Transport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@@ -149,18 +149,17 @@ func NewHTTPSRaw(
|
||||
return transport
|
||||
}
|
||||
|
||||
func (t *HTTPSTransport) Start(stage adapter.StartStage) error {
|
||||
func (t *HTTPSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
scope.Add(func() error {
|
||||
t.Reset()
|
||||
return nil
|
||||
})
|
||||
return dialer.InitializeDetour(t.dialer)
|
||||
}
|
||||
|
||||
func (t *HTTPSTransport) Close() error {
|
||||
t.Reset()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *HTTPSTransport) Reset() {
|
||||
t.transportAccess.Lock()
|
||||
defer t.transportAccess.Unlock()
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/sagernet/sing-box/dns/transport/mdns"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
@@ -39,6 +38,7 @@ type Transport struct {
|
||||
preferGo bool
|
||||
resolved ResolvedResolver
|
||||
mdnsTransport adapter.DNSTransport
|
||||
mdnsScope *adapter.Scope
|
||||
configSource *systemconfig.Source
|
||||
system systemResolver
|
||||
serverSet atomic.Pointer[localServerSet]
|
||||
@@ -65,13 +65,15 @@ func NewTransport(ctx context.Context, logger log.ContextLogger, tag string, opt
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
func (t *Transport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
t.preferredResolver.Start(stage)
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
scope.Add(t.configSource.Close)
|
||||
if !t.preferGo && isSystemdResolvedManaged() {
|
||||
resolvedResolver, err := NewResolvedResolver(t.ctx, t.logger)
|
||||
if err == nil {
|
||||
scope.Add(resolvedResolver.Close)
|
||||
err = resolvedResolver.Start()
|
||||
if err == nil {
|
||||
t.resolved = resolvedResolver
|
||||
@@ -81,13 +83,26 @@ func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
}
|
||||
case adapter.StartStateStart:
|
||||
scope.Add(func() error {
|
||||
t.system.close()
|
||||
return nil
|
||||
})
|
||||
scope.Add(func() error {
|
||||
serverSet := t.serverSet.Swap(nil)
|
||||
if serverSet != nil {
|
||||
return serverSet.serverScope.Close()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if !C.IsDarwin {
|
||||
t.mdnsTransport = mdns.NewRawTransport(t.TransportAdapter, t.ctx, t.logger)
|
||||
t.mdnsScope = adapter.NewScope(t.ctx, t.logger)
|
||||
scope.Add(t.mdnsScope.Close)
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
if t.mdnsTransport != nil {
|
||||
err := t.mdnsTransport.Start(stage)
|
||||
err := t.mdnsTransport.Start(stage, t.mdnsScope)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -96,15 +111,6 @@ func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
serverSet := t.serverSet.Swap(nil)
|
||||
if serverSet != nil {
|
||||
serverSet.Close()
|
||||
}
|
||||
t.system.close()
|
||||
return common.Close(t.resolved, t.mdnsTransport, t.configSource)
|
||||
}
|
||||
|
||||
func (t *Transport) Reset() {
|
||||
serverSet := t.serverSet.Load()
|
||||
if serverSet != nil {
|
||||
|
||||
@@ -66,12 +66,12 @@ type DBusResolvedResolver struct {
|
||||
updateCancel context.CancelFunc
|
||||
updateRunAccess sync.Mutex
|
||||
closed bool
|
||||
closeOnce sync.Once
|
||||
}
|
||||
|
||||
type resolvedServerSet struct {
|
||||
scopes []*resolvedScope
|
||||
signature []string
|
||||
scopes []*resolvedScope
|
||||
signature []string
|
||||
serverScope *adapter.Scope
|
||||
}
|
||||
|
||||
// Match levels of dns_scope_good_domain() in systemd-resolved: a routing or search
|
||||
@@ -198,32 +198,26 @@ func (t *DBusResolvedResolver) Start() error {
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) Close() error {
|
||||
t.updateAccess.Lock()
|
||||
updateCancel := t.updateCancel
|
||||
t.updateCancel = nil
|
||||
t.updateAccess.Unlock()
|
||||
if updateCancel != nil {
|
||||
updateCancel()
|
||||
}
|
||||
t.updateRunAccess.Lock()
|
||||
t.closed = true
|
||||
serverSet := t.savedServerSet.Swap(nil)
|
||||
t.updateRunAccess.Unlock()
|
||||
var closeErr error
|
||||
t.closeOnce.Do(func() {
|
||||
t.updateAccess.Lock()
|
||||
updateCancel := t.updateCancel
|
||||
t.updateCancel = nil
|
||||
t.updateAccess.Unlock()
|
||||
if updateCancel != nil {
|
||||
updateCancel()
|
||||
}
|
||||
t.updateRunAccess.Lock()
|
||||
t.closed = true
|
||||
serverSet := t.savedServerSet.Swap(nil)
|
||||
t.updateRunAccess.Unlock()
|
||||
if serverSet != nil {
|
||||
closeErr = serverSet.Close()
|
||||
}
|
||||
if t.interfaceCallback != nil {
|
||||
t.interfaceMonitor.UnregisterCallback(t.interfaceCallback)
|
||||
}
|
||||
if t.networkCallback != nil {
|
||||
t.networkMonitor.UnregisterCallback(t.networkCallback)
|
||||
}
|
||||
if t.systemBus != nil {
|
||||
_ = t.systemBus.Close()
|
||||
}
|
||||
})
|
||||
if serverSet != nil {
|
||||
closeErr = serverSet.serverScope.Close()
|
||||
}
|
||||
t.interfaceMonitor.UnregisterCallback(t.interfaceCallback)
|
||||
if t.networkCallback != nil {
|
||||
t.networkMonitor.UnregisterCallback(t.networkCallback)
|
||||
}
|
||||
_ = t.systemBus.Close()
|
||||
return closeErr
|
||||
}
|
||||
|
||||
@@ -385,21 +379,6 @@ func (s *resolvedScope) match(name string) int {
|
||||
return resolvedScopeMaybe
|
||||
}
|
||||
|
||||
func (s *resolvedServerSet) Close() error {
|
||||
return E.Errors(common.Map(s.scopes, (*resolvedScope).Close)...)
|
||||
}
|
||||
|
||||
func (s *resolvedScope) Close() error {
|
||||
var errors []error
|
||||
for _, server := range s.servers {
|
||||
errors = append(errors, server.primaryTransport.Close())
|
||||
if server.fallbackTransport != nil {
|
||||
errors = append(errors, server.fallbackTransport.Close())
|
||||
}
|
||||
}
|
||||
return E.Errors(errors...)
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) loopUpdateStatus() {
|
||||
signalChan := make(chan *dbus.Signal, 1)
|
||||
t.systemBus.Signal(signalChan)
|
||||
@@ -457,7 +436,7 @@ func (t *DBusResolvedResolver) updateStatus(ctx context.Context) error {
|
||||
serverSet, err := t.checkResolved(ctx)
|
||||
if t.closed || ctx.Err() != nil {
|
||||
if serverSet != nil {
|
||||
_ = serverSet.Close()
|
||||
_ = serverSet.serverScope.Close()
|
||||
}
|
||||
if t.closed {
|
||||
return os.ErrClosed
|
||||
@@ -466,7 +445,7 @@ func (t *DBusResolvedResolver) updateStatus(ctx context.Context) error {
|
||||
}
|
||||
oldServerSet := t.savedServerSet.Swap(serverSet)
|
||||
if oldServerSet != nil {
|
||||
_ = oldServerSet.Close()
|
||||
_ = oldServerSet.serverScope.Close()
|
||||
}
|
||||
if err != nil {
|
||||
var dbusErr dbus.Error
|
||||
@@ -579,11 +558,13 @@ func (t *DBusResolvedResolver) checkResolved(ctx context.Context) (*resolvedServ
|
||||
if len(scopeSpecifications) == 0 {
|
||||
return nil, E.New("no DNS servers configured")
|
||||
}
|
||||
serverSet := &resolvedServerSet{}
|
||||
serverSet := &resolvedServerSet{
|
||||
serverScope: adapter.NewScope(t.ctx, t.logger),
|
||||
}
|
||||
for _, scopeSpecification := range scopeSpecifications {
|
||||
scope, createErr := t.createResolvedScope(scopeSpecification)
|
||||
scope, createErr := t.createResolvedScope(serverSet.serverScope, scopeSpecification)
|
||||
if createErr != nil {
|
||||
_ = serverSet.Close()
|
||||
_ = serverSet.serverScope.Close()
|
||||
return nil, createErr
|
||||
}
|
||||
serverSet.scopes = append(serverSet.scopes, scope)
|
||||
@@ -630,7 +611,7 @@ func (t *DBusResolvedResolver) loadResolvedLinkScope(ctx context.Context, manage
|
||||
return linkScope, true, nil
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) createResolvedScope(scopeSpecification resolvedScopeSpecification) (*resolvedScope, error) {
|
||||
func (t *DBusResolvedResolver) createResolvedScope(serverScope *adapter.Scope, scopeSpecification resolvedScopeSpecification) (*resolvedScope, error) {
|
||||
scope := &resolvedScope{
|
||||
domains: scopeSpecification.domains,
|
||||
defaultRoute: scopeSpecification.defaultRoute,
|
||||
@@ -646,9 +627,8 @@ func (t *DBusResolvedResolver) createResolvedScope(scopeSpecification resolvedSc
|
||||
return nil, err
|
||||
}
|
||||
for _, serverSpecification := range scopeSpecification.servers {
|
||||
server, createErr := t.createResolvedServer(serverDialer, scopeSpecification.dnsOverTLSMode, serverSpecification)
|
||||
server, createErr := t.createResolvedServer(serverScope, serverDialer, scopeSpecification.dnsOverTLSMode, serverSpecification)
|
||||
if createErr != nil {
|
||||
_ = scope.Close()
|
||||
return nil, createErr
|
||||
}
|
||||
scope.servers = append(scope.servers, server)
|
||||
@@ -656,9 +636,9 @@ func (t *DBusResolvedResolver) createResolvedScope(scopeSpecification resolvedSc
|
||||
return scope, nil
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) createResolvedServer(serverDialer N.Dialer, dnsOverTLSMode string, serverSpecification resolvedServerSpecification) (resolvedServer, error) {
|
||||
func (t *DBusResolvedResolver) createResolvedServer(serverScope *adapter.Scope, serverDialer N.Dialer, dnsOverTLSMode string, serverSpecification resolvedServerSpecification) (resolvedServer, error) {
|
||||
if dnsOverTLSMode == "yes" {
|
||||
primaryTransport, err := t.createResolvedTransport(serverDialer, serverSpecification, true)
|
||||
primaryTransport, err := t.createResolvedTransport(serverScope, serverDialer, serverSpecification, true)
|
||||
if err != nil {
|
||||
return resolvedServer{}, err
|
||||
}
|
||||
@@ -667,13 +647,12 @@ func (t *DBusResolvedResolver) createResolvedServer(serverDialer N.Dialer, dnsOv
|
||||
}, nil
|
||||
}
|
||||
if dnsOverTLSMode == "opportunistic" {
|
||||
primaryTransport, err := t.createResolvedTransport(serverDialer, serverSpecification, true)
|
||||
primaryTransport, err := t.createResolvedTransport(serverScope, serverDialer, serverSpecification, true)
|
||||
if err != nil {
|
||||
return resolvedServer{}, err
|
||||
}
|
||||
fallbackTransport, err := t.createResolvedTransport(serverDialer, serverSpecification, false)
|
||||
fallbackTransport, err := t.createResolvedTransport(serverScope, serverDialer, serverSpecification, false)
|
||||
if err != nil {
|
||||
_ = primaryTransport.Close()
|
||||
return resolvedServer{}, err
|
||||
}
|
||||
return resolvedServer{
|
||||
@@ -681,7 +660,7 @@ func (t *DBusResolvedResolver) createResolvedServer(serverDialer N.Dialer, dnsOv
|
||||
fallbackTransport: fallbackTransport,
|
||||
}, nil
|
||||
}
|
||||
primaryTransport, err := t.createResolvedTransport(serverDialer, serverSpecification, false)
|
||||
primaryTransport, err := t.createResolvedTransport(serverScope, serverDialer, serverSpecification, false)
|
||||
if err != nil {
|
||||
return resolvedServer{}, err
|
||||
}
|
||||
@@ -690,7 +669,7 @@ func (t *DBusResolvedResolver) createResolvedServer(serverDialer N.Dialer, dnsOv
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *DBusResolvedResolver) createResolvedTransport(serverDialer N.Dialer, serverSpecification resolvedServerSpecification, useTLS bool) (adapter.DNSTransport, error) {
|
||||
func (t *DBusResolvedResolver) createResolvedTransport(serverScope *adapter.Scope, serverDialer N.Dialer, serverSpecification resolvedServerSpecification, useTLS bool) (adapter.DNSTransport, error) {
|
||||
serverAddress := M.SocksaddrFrom(serverSpecification.address, resolvedServerPort(serverSpecification.port, useTLS))
|
||||
if useTLS {
|
||||
tlsAddress := serverSpecification.address
|
||||
@@ -709,17 +688,15 @@ func (t *DBusResolvedResolver) createResolvedTransport(serverDialer N.Dialer, se
|
||||
return nil, err
|
||||
}
|
||||
serverTransport := dnsTransport.NewTLSRaw(t.logger, dns.NewTransportAdapter(C.DNSTypeTLS, "", nil), serverDialer, serverAddress, tlsConfig)
|
||||
err = serverTransport.Start(adapter.StartStateStart)
|
||||
err = serverTransport.Start(adapter.StartStateStart, serverScope)
|
||||
if err != nil {
|
||||
_ = serverTransport.Close()
|
||||
return nil, err
|
||||
}
|
||||
return serverTransport, nil
|
||||
}
|
||||
serverTransport := dnsTransport.NewUDPRaw(t.logger, dns.NewTransportAdapter(C.DNSTypeUDP, "", nil), serverDialer, serverAddress)
|
||||
err := serverTransport.Start(adapter.StartStateStart)
|
||||
err := serverTransport.Start(adapter.StartStateStart, serverScope)
|
||||
if err != nil {
|
||||
_ = serverTransport.Close()
|
||||
return nil, err
|
||||
}
|
||||
return serverTransport, nil
|
||||
|
||||
@@ -14,14 +14,9 @@ import (
|
||||
)
|
||||
|
||||
type localServerSet struct {
|
||||
config *systemconfig.Config
|
||||
transports []adapter.DNSTransport
|
||||
}
|
||||
|
||||
func (s *localServerSet) Close() {
|
||||
for _, serverTransport := range s.transports {
|
||||
serverTransport.Close()
|
||||
}
|
||||
config *systemconfig.Config
|
||||
transports []adapter.DNSTransport
|
||||
serverScope *adapter.Scope
|
||||
}
|
||||
|
||||
func (t *Transport) serverSetFor(systemConfig *systemconfig.Config) (*localServerSet, error) {
|
||||
@@ -35,6 +30,7 @@ func (t *Transport) serverSetFor(systemConfig *systemconfig.Config) (*localServe
|
||||
if serverSet != nil && serverSet.config == systemConfig {
|
||||
return serverSet, nil
|
||||
}
|
||||
serverScope := adapter.NewScope(t.ctx, t.logger)
|
||||
transports := make([]adapter.DNSTransport, 0, len(systemConfig.Servers))
|
||||
for _, serverAddr := range systemConfig.Servers {
|
||||
var serverTransport adapter.DNSTransport
|
||||
@@ -43,22 +39,20 @@ func (t *Transport) serverSetFor(systemConfig *systemconfig.Config) (*localServe
|
||||
} else {
|
||||
serverTransport = transport.NewUDPRaw(t.logger, dns.NewTransportAdapter(C.DNSTypeUDP, "", nil), t.dialer, serverAddr)
|
||||
}
|
||||
err := serverTransport.Start(adapter.StartStateStart)
|
||||
err := serverTransport.Start(adapter.StartStateStart, serverScope)
|
||||
if err != nil {
|
||||
for _, startedTransport := range transports {
|
||||
startedTransport.Close()
|
||||
}
|
||||
return nil, E.Cause(err, "initialize transport for ", serverAddr)
|
||||
return nil, E.Errors(E.Cause(err, "initialize transport for ", serverAddr), serverScope.Close())
|
||||
}
|
||||
transports = append(transports, serverTransport)
|
||||
}
|
||||
newServerSet := &localServerSet{
|
||||
config: systemConfig,
|
||||
transports: transports,
|
||||
config: systemConfig,
|
||||
transports: transports,
|
||||
serverScope: serverScope,
|
||||
}
|
||||
oldServerSet := t.serverSet.Swap(newServerSet)
|
||||
if oldServerSet != nil {
|
||||
oldServerSet.Close()
|
||||
oldServerSet.serverScope.Close()
|
||||
}
|
||||
return newServerSet, nil
|
||||
}
|
||||
|
||||
@@ -93,13 +93,9 @@ func NewRawTransport(transportAdapter dns.TransportAdapter, ctx context.Context,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
if t.configSource != nil {
|
||||
return t.configSource.Close()
|
||||
func (t *Transport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage == adapter.StartStateInitialize && t.configSource != nil {
|
||||
scope.Add(t.configSource.Close)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -9,9 +9,11 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/dialer"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
boxDNS "github.com/sagernet/sing-box/dns"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
|
||||
@@ -114,7 +116,16 @@ func newTestTCPTransport(t *testing.T, listener net.Listener) *TCPTransport {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return NewTCPRaw(boxDNS.NewTransportAdapter(C.DNSTypeTCP, "test", nil), transportDialer, M.SocksaddrFromNet(listener.Addr()))
|
||||
transport := NewTCPRaw(boxDNS.NewTransportAdapter(C.DNSTypeTCP, "test", nil), transportDialer, M.SocksaddrFromNet(listener.Addr()))
|
||||
scope := adapter.NewScope(context.Background(), log.NewNOPFactory().Logger())
|
||||
err = transport.Start(adapter.StartStateStart, scope)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
scope.Close()
|
||||
})
|
||||
return transport
|
||||
}
|
||||
|
||||
func testExchange(transport *TCPTransport, questionName string) error {
|
||||
@@ -155,7 +166,6 @@ func TestTCPTransportSingleQueryServer(t *testing.T) {
|
||||
}()
|
||||
|
||||
transport := newTestTCPTransport(t, listener)
|
||||
defer transport.Close()
|
||||
|
||||
const queryCount = 8
|
||||
results := make(chan error, queryCount)
|
||||
@@ -221,7 +231,6 @@ func TestTCPTransportProbeEnablesReuse(t *testing.T) {
|
||||
}()
|
||||
|
||||
transport := newTestTCPTransport(t, listener)
|
||||
defer transport.Close()
|
||||
|
||||
deadline := time.Now().Add(3 * time.Second)
|
||||
for maxServedOnConn.Load() < 3 {
|
||||
@@ -284,7 +293,6 @@ func TestTCPTransportDemotesBrokenReuse(t *testing.T) {
|
||||
}()
|
||||
|
||||
transport := newTestTCPTransport(t, listener)
|
||||
defer transport.Close()
|
||||
|
||||
deadline := time.Now().Add(3 * time.Second)
|
||||
for {
|
||||
@@ -364,7 +372,6 @@ func TestTCPTransportSilentPipelineServer(t *testing.T) {
|
||||
}()
|
||||
|
||||
transport := newTestTCPTransport(t, listener)
|
||||
defer transport.Close()
|
||||
|
||||
const queryCount = 5
|
||||
results := make(chan error, queryCount)
|
||||
|
||||
@@ -137,19 +137,18 @@ func (t *HTTP3Transport) newTransport() *http3.Transport {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *HTTP3Transport) Start(stage adapter.StartStage) error {
|
||||
func (t *HTTP3Transport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
scope.Add(func() error {
|
||||
t.transportAccess.Lock()
|
||||
defer t.transportAccess.Unlock()
|
||||
return t.transport.Close()
|
||||
})
|
||||
return dialer.InitializeDetour(t.dialer)
|
||||
}
|
||||
|
||||
func (t *HTTP3Transport) Close() error {
|
||||
t.transportAccess.Lock()
|
||||
defer t.transportAccess.Unlock()
|
||||
return t.transport.Close()
|
||||
}
|
||||
|
||||
func (t *HTTP3Transport) Reset() {
|
||||
t.transportAccess.Lock()
|
||||
defer t.transportAccess.Unlock()
|
||||
|
||||
@@ -79,17 +79,14 @@ func NewQUIC(ctx context.Context, logger log.ContextLogger, tag string, options
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Transport) Start(stage adapter.StartStage) error {
|
||||
func (t *Transport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
scope.Add(t.connection.Close)
|
||||
return dialer.InitializeDetour(t.dialer)
|
||||
}
|
||||
|
||||
func (t *Transport) Close() error {
|
||||
return t.connection.Close()
|
||||
}
|
||||
|
||||
func (t *Transport) Reset() {
|
||||
t.connection.Reset()
|
||||
}
|
||||
|
||||
@@ -79,17 +79,14 @@ func NewTCPRaw(adapter dns.TransportAdapter, dialer N.Dialer, serverAddr M.Socks
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TCPTransport) Start(stage adapter.StartStage) error {
|
||||
func (t *TCPTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
scope.Add(t.multiplexer.Close)
|
||||
return dialer.InitializeDetour(t.dialer)
|
||||
}
|
||||
|
||||
func (t *TCPTransport) Close() error {
|
||||
return t.multiplexer.Close()
|
||||
}
|
||||
|
||||
func (t *TCPTransport) Reset() {
|
||||
t.multiplexer.Reset()
|
||||
}
|
||||
|
||||
@@ -85,17 +85,14 @@ func NewTLSRaw(logger logger.ContextLogger, adapter dns.TransportAdapter, dialer
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *TLSTransport) Start(stage adapter.StartStage) error {
|
||||
func (t *TLSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
scope.Add(t.multiplexer.Close)
|
||||
return dialer.InitializeDetour(t.dialer)
|
||||
}
|
||||
|
||||
func (t *TLSTransport) Close() error {
|
||||
return t.multiplexer.Close()
|
||||
}
|
||||
|
||||
func (t *TLSTransport) Reset() {
|
||||
t.multiplexer.Reset()
|
||||
}
|
||||
|
||||
@@ -79,17 +79,14 @@ func NewUDPRaw(logger logger.ContextLogger, adapter dns.TransportAdapter, dialer
|
||||
return t
|
||||
}
|
||||
|
||||
func (t *UDPTransport) Start(stage adapter.StartStage) error {
|
||||
func (t *UDPTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
scope.Add(t.multiplexer.Close)
|
||||
return dialer.InitializeDetour(t.dialer)
|
||||
}
|
||||
|
||||
func (t *UDPTransport) Close() error {
|
||||
return t.multiplexer.Close()
|
||||
}
|
||||
|
||||
func (t *UDPTransport) Reset() {
|
||||
t.multiplexer.Reset()
|
||||
}
|
||||
|
||||
+11
-50
@@ -2,30 +2,24 @@ package dns
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/taskmonitor"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
)
|
||||
|
||||
var _ adapter.DNSTransportManager = (*TransportManager)(nil)
|
||||
|
||||
type TransportManager struct {
|
||||
logger log.ContextLogger
|
||||
registry adapter.DNSTransportRegistry
|
||||
outbound adapter.OutboundManager
|
||||
defaultTag string
|
||||
access sync.RWMutex
|
||||
started bool
|
||||
stage adapter.StartStage
|
||||
transports []adapter.DNSTransport
|
||||
transportByTag map[string]adapter.DNSTransport
|
||||
defaultTransport adapter.DNSTransport
|
||||
@@ -33,9 +27,8 @@ type TransportManager struct {
|
||||
fakeIPTransport adapter.FakeIPTransport
|
||||
}
|
||||
|
||||
func NewTransportManager(logger logger.ContextLogger, registry adapter.DNSTransportRegistry, outbound adapter.OutboundManager, defaultTag string) *TransportManager {
|
||||
func NewTransportManager(registry adapter.DNSTransportRegistry, outbound adapter.OutboundManager, defaultTag string) *TransportManager {
|
||||
return &TransportManager{
|
||||
logger: logger,
|
||||
registry: registry,
|
||||
outbound: outbound,
|
||||
defaultTag: defaultTag,
|
||||
@@ -47,13 +40,8 @@ func (m *TransportManager) Initialize(defaultTransportFallback func() (adapter.D
|
||||
m.defaultTransportFallback = defaultTransportFallback
|
||||
}
|
||||
|
||||
func (m *TransportManager) Start(stage adapter.StartStage) error {
|
||||
func (m *TransportManager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
m.access.Lock()
|
||||
if m.started && m.stage >= stage {
|
||||
panic("already started")
|
||||
}
|
||||
m.started = true
|
||||
m.stage = stage
|
||||
if stage == adapter.StartStateInitialize {
|
||||
if m.defaultTag != "" && m.defaultTransport == nil {
|
||||
m.access.Unlock()
|
||||
@@ -73,19 +61,19 @@ func (m *TransportManager) Start(stage adapter.StartStage) error {
|
||||
transports := m.transports
|
||||
m.access.Unlock()
|
||||
if stage == adapter.StartStateStart {
|
||||
return m.startTransports(transports)
|
||||
return m.startTransports(scope, transports)
|
||||
}
|
||||
for _, transport := range transports {
|
||||
err := transport.Start(stage)
|
||||
name := "dns/" + transport.Type() + "[" + transport.Tag() + "]"
|
||||
err := scope.Start(name, transport, stage)
|
||||
if err != nil {
|
||||
return E.Cause(err, stage, " dns/", transport.Type(), "[", transport.Tag(), "]")
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TransportManager) startTransports(transports []adapter.DNSTransport) error {
|
||||
monitor := taskmonitor.New(m.logger, C.StartTimeout)
|
||||
func (m *TransportManager) startTransports(scope *adapter.Scope, transports []adapter.DNSTransport) error {
|
||||
started := make(map[string]bool)
|
||||
for {
|
||||
canContinue := false
|
||||
@@ -103,13 +91,10 @@ func (m *TransportManager) startTransports(transports []adapter.DNSTransport) er
|
||||
}
|
||||
started[transportTag] = true
|
||||
canContinue = true
|
||||
if starter, isStarter := transportToStart.(adapter.Lifecycle); isStarter {
|
||||
monitor.Start("start dns/", transportToStart.Type(), "[", transportTag, "]")
|
||||
err := starter.Start(adapter.StartStateStart)
|
||||
monitor.Finish()
|
||||
if err != nil {
|
||||
return E.Cause(err, "start dns/", transportToStart.Type(), "[", transportTag, "]")
|
||||
}
|
||||
name := "dns/" + transportToStart.Type() + "[" + transportTag + "]"
|
||||
err := scope.Start(name, transportToStart, adapter.StartStateStart)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(started) == len(transports) {
|
||||
@@ -142,30 +127,6 @@ func (m *TransportManager) startTransports(transports []adapter.DNSTransport) er
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TransportManager) Close() error {
|
||||
monitor := taskmonitor.New(m.logger, C.StopTimeout)
|
||||
m.access.Lock()
|
||||
if !m.started {
|
||||
m.access.Unlock()
|
||||
return nil
|
||||
}
|
||||
m.started = false
|
||||
transports := m.transports
|
||||
m.transports = nil
|
||||
m.access.Unlock()
|
||||
var err error
|
||||
for _, transport := range transports {
|
||||
if closer, isCloser := transport.(io.Closer); isCloser {
|
||||
monitor.Start("close server/", transport.Type(), "[", transport.Tag(), "]")
|
||||
err = E.Append(err, closer.Close(), func(err error) error {
|
||||
return E.Cause(err, "close server/", transport.Type(), "[", transport.Tag(), "]")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *TransportManager) Transports() []adapter.DNSTransport {
|
||||
m.access.RLock()
|
||||
defer m.access.RUnlock()
|
||||
|
||||
@@ -140,10 +140,16 @@ func (c *CacheFile) SetDisableExpire(disableExpire bool) {
|
||||
c.disableExpire = disableExpire
|
||||
}
|
||||
|
||||
func (c *CacheFile) Start(stage adapter.StartStage) error {
|
||||
func (c *CacheFile) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
return c.start()
|
||||
err := c.start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(func() error {
|
||||
return c.database().Close()
|
||||
})
|
||||
case adapter.StartStateStart:
|
||||
c.startCacheCleanup()
|
||||
}
|
||||
@@ -239,16 +245,6 @@ func (c *CacheFile) start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *CacheFile) Close() error {
|
||||
c.dbAccess.RLock()
|
||||
db := c.DB
|
||||
c.dbAccess.RUnlock()
|
||||
if db == nil {
|
||||
return nil
|
||||
}
|
||||
return db.Close()
|
||||
}
|
||||
|
||||
func checkDatabase(db *bbolt.DB) error {
|
||||
return db.View(func(tx *bbolt.Tx) error {
|
||||
var checkErr error
|
||||
|
||||
@@ -21,7 +21,6 @@ import (
|
||||
"github.com/sagernet/sing-box/experimental/clashmode"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/service"
|
||||
@@ -147,7 +146,7 @@ func (s *Server) Name() string {
|
||||
return "clash server"
|
||||
}
|
||||
|
||||
func (s *Server) Start(stage adapter.StartStage) error {
|
||||
func (s *Server) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStarted {
|
||||
return nil
|
||||
}
|
||||
@@ -168,6 +167,7 @@ func (s *Server) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "external controller listen error")
|
||||
}
|
||||
scope.Add(s.httpServer.Close)
|
||||
s.logger.Info("restful api listening at ", listener.Addr())
|
||||
go func() {
|
||||
err = s.httpServer.Serve(listener)
|
||||
@@ -179,12 +179,6 @@ func (s *Server) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
return common.Close(
|
||||
common.PtrOrNil(s.httpServer),
|
||||
)
|
||||
}
|
||||
|
||||
func authentication(serverSecret string) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
fn := func(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -43,7 +43,7 @@ func (m *Manager) Name() string {
|
||||
return "clash mode manager"
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
func (m *Manager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -59,10 +59,6 @@ func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Mode() string {
|
||||
return m.mode
|
||||
}
|
||||
|
||||
@@ -46,15 +46,11 @@ func newPlatformTransport(ctx context.Context, logger log.ContextLogger, iif Loc
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *platformTransport) Start(stage adapter.StartStage) error {
|
||||
func (p *platformTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
p.preferredResolver.Start(stage)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *platformTransport) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *platformTransport) Reset() {
|
||||
}
|
||||
|
||||
|
||||
@@ -18,8 +18,10 @@ import (
|
||||
"strconv"
|
||||
"sync"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/certificate"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/bufio"
|
||||
@@ -69,10 +71,10 @@ var (
|
||||
)
|
||||
|
||||
type httpClient struct {
|
||||
tls tls.Config
|
||||
client http.Client
|
||||
transport http.Transport
|
||||
store *certificate.Store
|
||||
tls tls.Config
|
||||
client http.Client
|
||||
transport http.Transport
|
||||
storeScope *adapter.Scope
|
||||
}
|
||||
|
||||
func NewHTTPClient() HTTPClient {
|
||||
@@ -87,6 +89,11 @@ func NewHTTPClient() HTTPClient {
|
||||
if err != nil {
|
||||
panic(E.Cause(err, "initialize certificate store"))
|
||||
}
|
||||
client.storeScope = adapter.NewScope(context.Background(), log.NewNOPFactory().Logger())
|
||||
err = store.Start(adapter.StartStateInitialize, client.storeScope)
|
||||
if err != nil {
|
||||
panic(E.Cause(err, "initialize certificate store"))
|
||||
}
|
||||
client.tls.RootCAs = store.Pool()
|
||||
}
|
||||
return client
|
||||
@@ -161,8 +168,8 @@ func (c *httpClient) NewRequest() HTTPRequest {
|
||||
}
|
||||
|
||||
func (c *httpClient) Close() {
|
||||
if c.store != nil {
|
||||
c.store.Close()
|
||||
if c.storeScope != nil {
|
||||
c.storeScope.Close()
|
||||
}
|
||||
c.transport.CloseIdleConnections()
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ var _ adapter.V2RayServer = (*Server)(nil)
|
||||
type Server struct {
|
||||
logger log.Logger
|
||||
listen string
|
||||
tcpListener net.Listener
|
||||
grpcServer *grpc.Server
|
||||
statsService *StatsService
|
||||
}
|
||||
@@ -48,33 +47,27 @@ func (s *Server) Name() string {
|
||||
return "v2ray server"
|
||||
}
|
||||
|
||||
func (s *Server) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStatePostStart {
|
||||
return nil
|
||||
}
|
||||
listener, err := net.Listen("tcp", s.listen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
s.logger.Info("grpc server started at ", listener.Addr())
|
||||
s.tcpListener = listener
|
||||
go func() {
|
||||
err = s.grpcServer.Serve(listener)
|
||||
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
s.logger.Error(err)
|
||||
func (s *Server) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
scope.Add(func() error {
|
||||
s.grpcServer.Stop()
|
||||
return nil
|
||||
})
|
||||
case adapter.StartStatePostStart:
|
||||
listener, err := net.Listen("tcp", s.listen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) Close() error {
|
||||
if s.grpcServer != nil {
|
||||
s.grpcServer.Stop()
|
||||
s.logger.Info("grpc server started at ", listener.Addr())
|
||||
go func() {
|
||||
err = s.grpcServer.Serve(listener)
|
||||
if err != nil && !errors.Is(err, http.ErrServerClosed) {
|
||||
s.logger.Error(err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
return common.Close(
|
||||
common.PtrOrNil(s.grpcServer),
|
||||
s.tcpListener,
|
||||
)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) StatsService() adapter.ConnectionTracker {
|
||||
|
||||
@@ -46,7 +46,7 @@ require (
|
||||
github.com/sagernet/nftables v0.3.0-mod.4
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.9
|
||||
github.com/sagernet/sing v0.9.7-0.20260929150544-0ad23b637bd4
|
||||
github.com/sagernet/sing-cloudflared v0.1.4-0.20260929150702-b3a1e8f3018c
|
||||
github.com/sagernet/sing-cloudflared v0.1.4-0.20261002084126-c1255ae368f2
|
||||
github.com/sagernet/sing-mux v0.3.10-0.20260929204512-caf09fe32475
|
||||
github.com/sagernet/sing-openconnect v0.1.1-0.20260929151225-cbd68c45de58
|
||||
github.com/sagernet/sing-openvpn v0.1.1-0.20260929151220-7c3045dbddce
|
||||
|
||||
@@ -320,8 +320,8 @@ github.com/sagernet/quic-go v0.61.0-sing-box-mod.9 h1:Lojx77uC63TxZO38Z1OSo6aOoB
|
||||
github.com/sagernet/quic-go v0.61.0-sing-box-mod.9/go.mod h1:hmLC8GJPp+BrpBgrgJnacvI4fZGIhasuy1ROJJ8GR4E=
|
||||
github.com/sagernet/sing v0.9.7-0.20260929150544-0ad23b637bd4 h1:d4WT3KO4zhp9qzPHUZCKqCP+ZmP1GXBsAmReqlnE4zA=
|
||||
github.com/sagernet/sing v0.9.7-0.20260929150544-0ad23b637bd4/go.mod h1:K3Owt3xPhHugvlnlPPxZJ/exXdaJfEPOTNorGk4AXjo=
|
||||
github.com/sagernet/sing-cloudflared v0.1.4-0.20260929150702-b3a1e8f3018c h1:36zXD/qnDk7sh/J4zSEJsnHf4W3TYNCbmjo9MNIlrE4=
|
||||
github.com/sagernet/sing-cloudflared v0.1.4-0.20260929150702-b3a1e8f3018c/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg=
|
||||
github.com/sagernet/sing-cloudflared v0.1.4-0.20261002084126-c1255ae368f2 h1:+AfbAXGEV8tezIYHeShzwHm7IMUE5kYGVFLo0ly7W24=
|
||||
github.com/sagernet/sing-cloudflared v0.1.4-0.20261002084126-c1255ae368f2/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg=
|
||||
github.com/sagernet/sing-mux v0.3.10-0.20260929204512-caf09fe32475 h1:aG0DqHEOjax7DyfE1GTAXZotOg3QGVCz3/8rCSua2kg=
|
||||
github.com/sagernet/sing-mux v0.3.10-0.20260929204512-caf09fe32475/go.mod h1:jricpwCOndDsTEM1TM3piJvhL/2Mm7OhLkm+JadJJ1Q=
|
||||
github.com/sagernet/sing-openconnect v0.1.1-0.20260929151225-cbd68c45de58 h1:WOPVlvbw3zGl4IzpRcfqB901blgDKuiplVrpptf/TOY=
|
||||
|
||||
@@ -79,7 +79,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -88,12 +88,14 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(h.listener, h.tlsConfig)
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
|
||||
@@ -36,7 +36,6 @@ type Outbound struct {
|
||||
tlsConfig tls.Config
|
||||
clientOptions anytls.ClientConfig
|
||||
clientMetadata string
|
||||
client *anytls.Client
|
||||
sessionClient *session.Client
|
||||
uotClient *uot.Client
|
||||
logger log.ContextLogger
|
||||
@@ -89,7 +88,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
return outbound, nil
|
||||
}
|
||||
|
||||
func (h *Outbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
@@ -97,7 +96,7 @@ func (h *Outbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.client = client
|
||||
scope.Add(client.Close)
|
||||
h.sessionClient = sessionClientOf(client)
|
||||
h.uotClient = &uot.Client{
|
||||
Dialer: anytlsDialer(h.createProxy),
|
||||
@@ -160,7 +159,3 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
h.logger.InfoContext(ctx, "outbound UoT packet connection to ", destination)
|
||||
return h.uotClient.ListenPacket(ctx, destination)
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return common.Close(common.PtrOrNil(h.client))
|
||||
}
|
||||
|
||||
+12
-18
@@ -41,16 +41,13 @@ type backendBase struct {
|
||||
returnAccess sync.Mutex
|
||||
returnPaths []tun.Return
|
||||
|
||||
egressAccess sync.Mutex
|
||||
forwardingRestore []sysctlState
|
||||
unregister func()
|
||||
egressAccess sync.Mutex
|
||||
|
||||
session adapter.BridgeSession
|
||||
currentEgress string
|
||||
|
||||
closeOnce sync.Once
|
||||
closed chan struct{}
|
||||
readDone chan struct{}
|
||||
closed <-chan struct{}
|
||||
readGroup sync.WaitGroup
|
||||
}
|
||||
|
||||
func (b *backendBase) init(ctx context.Context, logger logger.ContextLogger, networkManager adapter.NetworkManager, tag string, options option.BridgeOutboundOptions) error {
|
||||
@@ -100,12 +97,14 @@ func (b *backendBase) DetachReturn(returnPath tun.Return) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendBase) registerMonitors(syncFunc func()) {
|
||||
var unregisterFuncs []func()
|
||||
func (b *backendBase) registerMonitors(scope *adapter.Scope, syncFunc func()) {
|
||||
networkMonitor := b.networkManager.NetworkMonitor()
|
||||
if networkMonitor != nil {
|
||||
networkElement := networkMonitor.RegisterCallback(syncFunc)
|
||||
unregisterFuncs = append(unregisterFuncs, func() { networkMonitor.UnregisterCallback(networkElement) })
|
||||
scope.Add(func() error {
|
||||
networkMonitor.UnregisterCallback(networkElement)
|
||||
return nil
|
||||
})
|
||||
} else if b.boundInterface != "" {
|
||||
b.logger.Debug("network monitor unavailable, pinned egress will not track interface changes")
|
||||
}
|
||||
@@ -113,14 +112,10 @@ func (b *backendBase) registerMonitors(syncFunc func()) {
|
||||
interfaceMonitor := b.networkManager.InterfaceMonitor()
|
||||
if interfaceMonitor != nil {
|
||||
interfaceElement := interfaceMonitor.RegisterCallback(func(_ *control.Interface, _ int) { syncFunc() })
|
||||
unregisterFuncs = append(unregisterFuncs, func() { interfaceMonitor.UnregisterCallback(interfaceElement) })
|
||||
}
|
||||
}
|
||||
if len(unregisterFuncs) > 0 {
|
||||
b.unregister = func() {
|
||||
for _, unregisterFunc := range unregisterFuncs {
|
||||
unregisterFunc()
|
||||
}
|
||||
scope.Add(func() error {
|
||||
interfaceMonitor.UnregisterCallback(interfaceElement)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -166,7 +161,6 @@ func (b *backendBase) resolveEgress() string {
|
||||
}
|
||||
|
||||
func (b *backendBase) readLoop() {
|
||||
defer close(b.readDone)
|
||||
buffer := make([]byte, tun.PacketOffset+bridgeTunMTU)
|
||||
for {
|
||||
n, err := b.tunInterface.Read(buffer)
|
||||
|
||||
@@ -72,24 +72,30 @@ func newBackend(ctx context.Context, logger logger.ContextLogger, networkManager
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (b *backendDarwin) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
err := b.start()
|
||||
if err != nil {
|
||||
b.Close()
|
||||
return err
|
||||
func (b *backendDarwin) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
scope.Add(func() error {
|
||||
releaseBridgeIndex(b.index)
|
||||
return nil
|
||||
})
|
||||
case adapter.StartStateStart:
|
||||
b.closed = scope.Context().Done()
|
||||
if b.platform != nil {
|
||||
return b.startPlatform(scope)
|
||||
}
|
||||
return b.start(scope)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendDarwin) start() error {
|
||||
if b.platform != nil {
|
||||
return b.startPlatform()
|
||||
}
|
||||
func (b *backendDarwin) start(scope *adapter.Scope) error {
|
||||
b.tunName = tun.CalculateInterfaceName(b.bridgeName)
|
||||
b.anchorName = "com.apple/sing-box-" + b.tunName
|
||||
scope.Add(func() error {
|
||||
b.readGroup.Wait()
|
||||
return nil
|
||||
})
|
||||
tunInterface, err := tun.New(tun.Options{
|
||||
Name: b.tunName,
|
||||
MTU: bridgeTunMTUDarwin,
|
||||
@@ -102,12 +108,17 @@ func (b *backendDarwin) start() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create bridge tun")
|
||||
}
|
||||
scope.Add(tunInterface.Close)
|
||||
b.tunInterface = tunInterface
|
||||
err = tunInterface.Start()
|
||||
if err != nil {
|
||||
return E.Cause(err, "start bridge tun")
|
||||
}
|
||||
b.forwardingRestore = enableDarwinForwarding(b.logger, b.inet4Port.IsValid(), b.inet6Port.IsValid())
|
||||
forwardingRestore := enableDarwinForwarding(b.logger, b.inet4Port.IsValid(), b.inet6Port.IsValid())
|
||||
scope.Add(func() error {
|
||||
restoreDarwinForwarding(forwardingRestore)
|
||||
return nil
|
||||
})
|
||||
err = assignBridgePortAddress(b.tunName, b.inet4Local, b.inet4Port)
|
||||
if err != nil {
|
||||
return E.Cause(err, "add bridge route")
|
||||
@@ -121,23 +132,31 @@ func (b *backendDarwin) start() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "enable pf")
|
||||
}
|
||||
scope.Add(func() error {
|
||||
_ = b.pfDevice.StopReference(b.pfToken)
|
||||
return b.pfDevice.Close()
|
||||
})
|
||||
dropRules := bridgeDropRules(b.tunName, b.inet4Port, b.inet6Port)
|
||||
err = b.pfDevice.LoadAnchor(b.anchorName, dropRules)
|
||||
if err != nil {
|
||||
return E.Cause(err, "initialize bridge pf rules")
|
||||
}
|
||||
scope.Add(func() error {
|
||||
b.egressAccess.Lock()
|
||||
_ = b.pfDevice.LoadAnchor(b.anchorName, nil)
|
||||
b.egressAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
b.currentRules = dropRules
|
||||
b.batchTUN = tunInterface.(tun.DarwinTUN)
|
||||
b.closed = make(chan struct{})
|
||||
b.readDone = make(chan struct{})
|
||||
b.registerMonitors(b.syncEgress)
|
||||
b.registerMonitors(scope, b.syncEgress)
|
||||
b.syncEgress()
|
||||
go b.batchReadLoop()
|
||||
b.readGroup.Go(b.batchReadLoop)
|
||||
b.logger.Info("bridge started at ", b.tunName, " (masquerade, egress ", b.egressLabel(), ")")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendDarwin) startPlatform() error {
|
||||
func (b *backendDarwin) startPlatform(scope *adapter.Scope) error {
|
||||
session, err := b.platform.CreateBridge(adapter.BridgeOptions{
|
||||
BridgeName: b.bridgeName,
|
||||
MTU: bridgeTunMTUDarwin,
|
||||
@@ -148,11 +167,16 @@ func (b *backendDarwin) startPlatform() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create bridge")
|
||||
}
|
||||
scope.Add(session.Close)
|
||||
b.session = session
|
||||
b.tunName = session.Name()
|
||||
if !session.Inet6Active() {
|
||||
b.inet6Port = netip.Addr{}
|
||||
}
|
||||
scope.Add(func() error {
|
||||
b.readGroup.Wait()
|
||||
return nil
|
||||
})
|
||||
tunInterface, err := tun.New(tun.Options{
|
||||
Name: b.tunName,
|
||||
MTU: bridgeTunMTUDarwin,
|
||||
@@ -164,17 +188,16 @@ func (b *backendDarwin) startPlatform() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create bridge tun")
|
||||
}
|
||||
scope.Add(tunInterface.Close)
|
||||
b.tunInterface = tunInterface
|
||||
err = tunInterface.Start()
|
||||
if err != nil {
|
||||
return E.Cause(err, "start bridge tun")
|
||||
}
|
||||
b.batchTUN = tunInterface.(tun.DarwinTUN)
|
||||
b.closed = make(chan struct{})
|
||||
b.readDone = make(chan struct{})
|
||||
b.registerMonitors(b.syncSessionEgress)
|
||||
b.registerMonitors(scope, b.syncSessionEgress)
|
||||
b.syncSessionEgress()
|
||||
go b.batchReadLoop()
|
||||
b.readGroup.Go(b.batchReadLoop)
|
||||
b.logger.Info("bridge started at ", b.tunName, " (platform, egress ", b.egressLabel(), ")")
|
||||
return nil
|
||||
}
|
||||
@@ -186,41 +209,6 @@ func (b *backendDarwin) egressLabel() string {
|
||||
return "auto"
|
||||
}
|
||||
|
||||
func (b *backendDarwin) Close() error {
|
||||
b.closeOnce.Do(func() {
|
||||
if b.closed != nil {
|
||||
close(b.closed)
|
||||
}
|
||||
if b.unregister != nil {
|
||||
b.unregister()
|
||||
}
|
||||
if b.pfDevice != nil && b.anchorName != "" {
|
||||
b.egressAccess.Lock()
|
||||
_ = b.pfDevice.LoadAnchor(b.anchorName, nil)
|
||||
b.egressAccess.Unlock()
|
||||
}
|
||||
restoreDarwinForwarding(b.forwardingRestore)
|
||||
b.forwardingRestore = nil
|
||||
if b.pfDevice != nil {
|
||||
if b.pfToken != 0 {
|
||||
_ = b.pfDevice.StopReference(b.pfToken)
|
||||
}
|
||||
_ = b.pfDevice.Close()
|
||||
}
|
||||
if b.tunInterface != nil {
|
||||
b.tunInterface.Close()
|
||||
}
|
||||
if b.readDone != nil {
|
||||
<-b.readDone
|
||||
}
|
||||
if b.session != nil {
|
||||
_ = b.session.Close()
|
||||
}
|
||||
releaseBridgeIndex(b.index)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendDarwin) PortMTU() uint32 {
|
||||
return bridgeTunMTUDarwin
|
||||
}
|
||||
@@ -247,7 +235,6 @@ func (b *backendDarwin) WritePackets(packets [][]byte) error {
|
||||
}
|
||||
|
||||
func (b *backendDarwin) batchReadLoop() {
|
||||
defer close(b.readDone)
|
||||
headroom := -1
|
||||
var buffers [][]byte
|
||||
var batch [][]byte
|
||||
|
||||
@@ -63,24 +63,30 @@ func newBackend(ctx context.Context, logger logger.ContextLogger, networkManager
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (b *backendLinux) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
err := b.start()
|
||||
if err != nil {
|
||||
b.Close()
|
||||
return err
|
||||
func (b *backendLinux) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
scope.Add(func() error {
|
||||
releaseBridgeIndex(b.index)
|
||||
return nil
|
||||
})
|
||||
case adapter.StartStateStart:
|
||||
b.closed = scope.Context().Done()
|
||||
if b.platform != nil {
|
||||
return b.startPlatform(scope)
|
||||
}
|
||||
return b.start(scope)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendLinux) start() error {
|
||||
if b.platform != nil {
|
||||
return b.startPlatform()
|
||||
}
|
||||
func (b *backendLinux) start(scope *adapter.Scope) error {
|
||||
b.tunName = tun.CalculateInterfaceName(b.bridgeName)
|
||||
b.nftTableName = "sing-box-" + b.tunName
|
||||
scope.Add(func() error {
|
||||
b.readGroup.Wait()
|
||||
return nil
|
||||
})
|
||||
tunInterface, err := tun.New(tun.Options{
|
||||
Name: b.tunName,
|
||||
MTU: bridgeTunMTU,
|
||||
@@ -92,6 +98,7 @@ func (b *backendLinux) start() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create bridge tun")
|
||||
}
|
||||
scope.Add(tunInterface.Close)
|
||||
b.tunInterface = tunInterface
|
||||
err = tunInterface.Start()
|
||||
if err != nil {
|
||||
@@ -112,13 +119,38 @@ func (b *backendLinux) start() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "set up bridge netfilter")
|
||||
}
|
||||
scope.Add(func() error {
|
||||
b.egressAccess.Lock()
|
||||
cleanupBridgeNetfilter(b.nftTableName)
|
||||
b.egressAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
if !inet6Active {
|
||||
b.inet6Port = netip.Addr{}
|
||||
}
|
||||
b.forwardingRestore = enableBridgeForwarding(b.logger, b.tunName, b.inet4Port.IsValid(), b.inet6Port.IsValid())
|
||||
forwardingRestore := enableBridgeForwarding(b.logger, b.tunName, b.inet4Port.IsValid(), b.inet6Port.IsValid())
|
||||
scope.Add(func() error {
|
||||
restoreBridgeForwarding(forwardingRestore)
|
||||
return nil
|
||||
})
|
||||
if b.routeTable != 0 {
|
||||
scope.Add(func() error {
|
||||
b.egressAccess.Lock()
|
||||
flushBridgeRouteTable(b.routeTable)
|
||||
b.egressAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if b.boundInterface != "" {
|
||||
b.syncEgress()
|
||||
}
|
||||
scope.Add(func() error {
|
||||
b.egressAccess.Lock()
|
||||
removeBridgeFamily(b.tunName, b.ruleIndex, b.routeTable, unix.AF_INET, b.inet4Port)
|
||||
removeBridgeFamily(b.tunName, b.ruleIndex, b.routeTable, unix.AF_INET6, b.inet6Port)
|
||||
b.egressAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
err = setupBridgeFamily(b.tunName, b.ruleIndex, b.routeTable, unix.AF_INET, b.inet4Port)
|
||||
if err != nil {
|
||||
return E.Cause(err, "set up bridge routing")
|
||||
@@ -129,12 +161,10 @@ func (b *backendLinux) start() error {
|
||||
removeBridgeFamily(b.tunName, b.ruleIndex, b.routeTable, unix.AF_INET6, b.inet6Port)
|
||||
b.inet6Port = netip.Addr{}
|
||||
}
|
||||
b.closed = make(chan struct{})
|
||||
b.readDone = make(chan struct{})
|
||||
if b.batchTUN != nil {
|
||||
go b.batchReadLoop()
|
||||
b.readGroup.Go(b.batchReadLoop)
|
||||
} else {
|
||||
go b.readLoop()
|
||||
b.readGroup.Go(b.readLoop)
|
||||
}
|
||||
egress := "auto"
|
||||
if b.boundInterface != "" {
|
||||
@@ -142,7 +172,10 @@ func (b *backendLinux) start() error {
|
||||
monitor := b.networkManager.NetworkMonitor()
|
||||
if monitor != nil {
|
||||
element := monitor.RegisterCallback(func() { b.syncEgress() })
|
||||
b.unregister = func() { monitor.UnregisterCallback(element) }
|
||||
scope.Add(func() error {
|
||||
monitor.UnregisterCallback(element)
|
||||
return nil
|
||||
})
|
||||
} else {
|
||||
b.logger.Debug("network monitor unavailable, pinned egress will not track interface changes")
|
||||
}
|
||||
@@ -151,7 +184,10 @@ func (b *backendLinux) start() error {
|
||||
monitor := b.networkManager.InterfaceMonitor()
|
||||
if monitor != nil {
|
||||
element := monitor.RegisterCallback(func(_ *control.Interface, _ int) { b.updateClamp() })
|
||||
b.unregister = func() { monitor.UnregisterCallback(element) }
|
||||
scope.Add(func() error {
|
||||
monitor.UnregisterCallback(element)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
b.updateClamp()
|
||||
}
|
||||
@@ -163,7 +199,7 @@ func (b *backendLinux) start() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendLinux) startPlatform() error {
|
||||
func (b *backendLinux) startPlatform(scope *adapter.Scope) error {
|
||||
session, err := b.platform.CreateBridge(adapter.BridgeOptions{
|
||||
BridgeName: b.bridgeName,
|
||||
MTU: bridgeTunMTU,
|
||||
@@ -175,11 +211,16 @@ func (b *backendLinux) startPlatform() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create bridge")
|
||||
}
|
||||
scope.Add(session.Close)
|
||||
b.session = session
|
||||
b.tunName = session.Name()
|
||||
if !session.Inet6Active() {
|
||||
b.inet6Port = netip.Addr{}
|
||||
}
|
||||
scope.Add(func() error {
|
||||
b.readGroup.Wait()
|
||||
return nil
|
||||
})
|
||||
tunInterface, err := tun.New(tun.Options{
|
||||
Name: b.tunName,
|
||||
MTU: bridgeTunMTU,
|
||||
@@ -190,6 +231,7 @@ func (b *backendLinux) startPlatform() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create bridge tun")
|
||||
}
|
||||
scope.Add(tunInterface.Close)
|
||||
b.tunInterface = tunInterface
|
||||
err = tunInterface.Start()
|
||||
if err != nil {
|
||||
@@ -204,17 +246,18 @@ func (b *backendLinux) startPlatform() error {
|
||||
b.writeBuffers[i] = make([]byte, b.writeHeadroom+maxPacketLength)
|
||||
}
|
||||
}
|
||||
b.closed = make(chan struct{})
|
||||
b.readDone = make(chan struct{})
|
||||
if b.batchTUN != nil {
|
||||
go b.batchReadLoop()
|
||||
b.readGroup.Go(b.batchReadLoop)
|
||||
} else {
|
||||
go b.readLoop()
|
||||
b.readGroup.Go(b.readLoop)
|
||||
}
|
||||
monitor := b.networkManager.InterfaceMonitor()
|
||||
if monitor != nil {
|
||||
element := monitor.RegisterCallback(func(_ *control.Interface, _ int) { b.syncSessionEgress() })
|
||||
b.unregister = func() { monitor.UnregisterCallback(element) }
|
||||
scope.Add(func() error {
|
||||
monitor.UnregisterCallback(element)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
b.syncSessionEgress()
|
||||
egress := "auto"
|
||||
@@ -225,41 +268,6 @@ func (b *backendLinux) startPlatform() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendLinux) Close() error {
|
||||
b.closeOnce.Do(func() {
|
||||
if b.closed != nil {
|
||||
close(b.closed)
|
||||
}
|
||||
if b.unregister != nil {
|
||||
b.unregister()
|
||||
}
|
||||
if b.tunInterface != nil {
|
||||
b.tunInterface.Close()
|
||||
}
|
||||
if b.readDone != nil {
|
||||
<-b.readDone
|
||||
}
|
||||
if b.session != nil {
|
||||
_ = b.session.Close()
|
||||
} else {
|
||||
b.egressAccess.Lock()
|
||||
if b.tunName != "" {
|
||||
cleanupBridgeNetfilter(b.nftTableName)
|
||||
removeBridgeFamily(b.tunName, b.ruleIndex, b.routeTable, unix.AF_INET, b.inet4Port)
|
||||
removeBridgeFamily(b.tunName, b.ruleIndex, b.routeTable, unix.AF_INET6, b.inet6Port)
|
||||
}
|
||||
if b.routeTable != 0 {
|
||||
flushBridgeRouteTable(b.routeTable)
|
||||
}
|
||||
b.egressAccess.Unlock()
|
||||
restoreBridgeForwarding(b.forwardingRestore)
|
||||
b.forwardingRestore = nil
|
||||
}
|
||||
releaseBridgeIndex(b.index)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendLinux) PortMTU() uint32 {
|
||||
return 0
|
||||
}
|
||||
@@ -308,7 +316,6 @@ func (b *backendLinux) WritePackets(packets [][]byte) error {
|
||||
// BatchRead completes any kernel-deferred checksums while splitting GRO frames
|
||||
// (virtio NEEDS_CSUM), so unlike readLoop no checksum fix is needed here.
|
||||
func (b *backendLinux) batchReadLoop() {
|
||||
defer close(b.readDone)
|
||||
batchSize := b.batchTUN.BatchSize()
|
||||
sizes := make([]int, batchSize)
|
||||
batch := make([][]byte, 0, batchSize)
|
||||
|
||||
@@ -140,20 +140,21 @@ func newBackend(ctx context.Context, logger logger.ContextLogger, networkManager
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
func (b *backendWindows) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
err := b.start()
|
||||
if err != nil {
|
||||
b.Close()
|
||||
return err
|
||||
func (b *backendWindows) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
scope.Add(func() error {
|
||||
releaseBridgeIndex(b.index)
|
||||
return nil
|
||||
})
|
||||
case adapter.StartStateStart:
|
||||
return b.start(scope)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *backendWindows) start() error {
|
||||
b.closed = make(chan struct{})
|
||||
func (b *backendWindows) start(scope *adapter.Scope) error {
|
||||
b.closed = scope.Context().Done()
|
||||
|
||||
state := b.currentEgressState()
|
||||
b.egress.Store(state)
|
||||
@@ -162,11 +163,16 @@ func (b *backendWindows) start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(func() error {
|
||||
b.reservation.Close()
|
||||
return nil
|
||||
})
|
||||
|
||||
injectHandle, err := windivert.Open(nil, windivert.LayerNetwork, windivert.PriorityHighest, windivert.FlagSendOnly)
|
||||
if err != nil {
|
||||
return E.Cause(err, "bridge: open injection handle (Administrator required)")
|
||||
}
|
||||
scope.Add(injectHandle.Close)
|
||||
b.injectHandle = injectHandle
|
||||
b.sendBuffer = make([]byte, 0, bridgeBatchBufferSize)
|
||||
b.sendAddrs = make([]windivert.Address, 0, windivert.BatchMax)
|
||||
@@ -177,8 +183,14 @@ func (b *backendWindows) start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(func() error {
|
||||
b.egressAccess.Lock()
|
||||
b.closeDivertersLocked()
|
||||
b.egressAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
|
||||
b.registerMonitors(b.syncEgress)
|
||||
b.registerMonitors(scope, b.syncEgress)
|
||||
b.syncEgress()
|
||||
state = b.egress.Load()
|
||||
if !state.inet4.IsValid() && !state.inet6.IsValid() {
|
||||
@@ -799,27 +811,6 @@ func sortSegments(segments []localSegment) {
|
||||
})
|
||||
}
|
||||
|
||||
func (b *backendWindows) Close() error {
|
||||
b.closeOnce.Do(func() {
|
||||
if b.closed != nil {
|
||||
close(b.closed)
|
||||
}
|
||||
if b.unregister != nil {
|
||||
b.unregister()
|
||||
}
|
||||
b.egressAccess.Lock()
|
||||
b.closeDivertersLocked()
|
||||
b.egressAccess.Unlock()
|
||||
if b.injectHandle != nil {
|
||||
b.injectHandle.Close()
|
||||
}
|
||||
b.reservation.Close()
|
||||
b.reservation = nil
|
||||
releaseBridgeIndex(b.index)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
type transportInfo struct {
|
||||
protocol tcpip.TransportProtocolNumber
|
||||
transport []byte
|
||||
|
||||
@@ -57,12 +57,8 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (o *Outbound) Start(stage adapter.StartStage) error {
|
||||
return o.backend.Start(stage)
|
||||
}
|
||||
|
||||
func (o *Outbound) Close() error {
|
||||
return o.backend.Close()
|
||||
func (o *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
return o.backend.Start(stage, scope)
|
||||
}
|
||||
|
||||
func (o *Outbound) PreferredDomain(metadata *adapter.InboundContext, domain string) bool {
|
||||
|
||||
@@ -92,15 +92,16 @@ type Inbound struct {
|
||||
references []string
|
||||
}
|
||||
|
||||
func (i *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (i *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return i.service.Start()
|
||||
}
|
||||
|
||||
func (i *Inbound) Close() error {
|
||||
return i.service.Close()
|
||||
err := i.service.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(i.service.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
type routerDialer struct {
|
||||
|
||||
@@ -70,21 +70,22 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (i *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (i *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return i.listener.Start()
|
||||
err := i.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(i.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (i *Inbound) InterfaceUpdated(ctx context.Context) {
|
||||
i.udpNat.Purge()
|
||||
}
|
||||
|
||||
func (i *Inbound) Close() error {
|
||||
return i.listener.Close()
|
||||
}
|
||||
|
||||
func (i *Inbound) NewPacket(buffer *buf.Buffer, source M.Socksaddr) {
|
||||
i.udpNat.NewPacket([][]byte{buffer.Bytes()}, source, i.listener.UDPAddr(), nil)
|
||||
}
|
||||
|
||||
@@ -88,8 +88,12 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
return outbound, nil
|
||||
}
|
||||
|
||||
func (h *Outbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
if h.icmpPort != nil {
|
||||
scope.Add(h.icmpPort.Close)
|
||||
}
|
||||
case adapter.StartStatePostStart, adapter.StartStateStarted:
|
||||
if len(h.myAddresses.Load()) == 0 {
|
||||
h.fetchMyAddresses()
|
||||
@@ -205,13 +209,6 @@ func (h *Outbound) WritePackets(packets [][]byte) error {
|
||||
return h.icmpPort.WritePackets(packets)
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
if h.icmpPort != nil {
|
||||
return h.icmpPort.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Outbound) DialParallel(ctx context.Context, network string, destination M.Socksaddr, destinationAddresses []netip.Addr) (net.Conn, error) {
|
||||
if h.isMyLoopbackAddress(destinationAddresses...) {
|
||||
return nil, E.New("loopback connection to TUN range")
|
||||
|
||||
@@ -73,7 +73,10 @@ func (s *Selector) Network() []string {
|
||||
return selected.Network()
|
||||
}
|
||||
|
||||
func (s *Selector) Start() error {
|
||||
func (s *Selector) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
for i, tag := range s.tags {
|
||||
detour, loaded := s.outbound.Outbound(tag)
|
||||
if !loaded {
|
||||
|
||||
@@ -71,7 +71,7 @@ func NewURLTest(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return outbound, nil
|
||||
}
|
||||
|
||||
func (s *URLTest) Start(stage adapter.StartStage) error {
|
||||
func (s *URLTest) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateStart:
|
||||
outbounds := make([]adapter.Outbound, 0, len(s.tags))
|
||||
@@ -89,16 +89,11 @@ func (s *URLTest) Start(stage adapter.StartStage) error {
|
||||
s.group = group
|
||||
case adapter.StartStateStarted:
|
||||
s.group.PostStart()
|
||||
scope.Add(s.group.Close)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *URLTest) Close() error {
|
||||
return common.Close(
|
||||
common.PtrOrNil(s.group),
|
||||
)
|
||||
}
|
||||
|
||||
func (s *URLTest) Now() string {
|
||||
if s.group.selectedOutboundTCP != nil {
|
||||
return s.group.selectedOutboundTCP.Tag()
|
||||
|
||||
@@ -66,7 +66,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -75,15 +75,14 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create TLS config")
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(
|
||||
h.listener,
|
||||
h.tlsConfig,
|
||||
)
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
|
||||
@@ -147,7 +147,7 @@ func (h *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
|
||||
h.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose)
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -156,18 +156,17 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
packetConn, err := h.listener.ListenUDP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return h.service.Start(packetConn)
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(
|
||||
h.listener,
|
||||
h.tlsConfig,
|
||||
common.PtrOrNil(h.service),
|
||||
)
|
||||
scope.Add(h.listener.Close)
|
||||
err = h.service.Start(packetConn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.service.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -131,6 +131,12 @@ func (h *Outbound) CloseIdleConnections() {
|
||||
h.client.CloseIdleConnections()
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return h.client.CloseWithError(os.ErrClosed)
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
scope.Add(func() error {
|
||||
return h.client.CloseWithError(os.ErrClosed)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ func (h *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
|
||||
h.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose)
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -277,22 +277,21 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
packetConn, err := h.listener.ListenUDP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return h.service.Start(packetConn)
|
||||
scope.Add(h.listener.Close)
|
||||
err = h.service.Start(packetConn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.service.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) InterfaceUpdated(ctx context.Context) {
|
||||
h.service.Reset()
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(
|
||||
h.listener,
|
||||
h.tlsConfig,
|
||||
common.PtrOrNil(h.service),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -223,6 +223,12 @@ func (h *Outbound) CloseIdleConnections() {
|
||||
h.client.CloseIdleConnections()
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return h.client.CloseWithError(os.ErrClosed)
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
scope.Add(func() error {
|
||||
return h.client.CloseWithError(os.ErrClosed)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
+15
-11
@@ -122,7 +122,14 @@ func NewRealmService(ctx context.Context, logger log.ContextLogger, tag string,
|
||||
return s, nil
|
||||
}
|
||||
|
||||
func (s *RealmService) Start(stage adapter.StartStage) error {
|
||||
func (s *RealmService) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage == adapter.StartStateInitialize {
|
||||
scope.Add(func() error {
|
||||
s.cancel()
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -131,11 +138,17 @@ func (s *RealmService) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create TLS config")
|
||||
}
|
||||
scope.Add(s.tlsConfig.Close)
|
||||
}
|
||||
tcpListener, err := s.listener.ListenTCP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(s.listener.Close)
|
||||
scope.Add(func() error {
|
||||
s.server.closeAll()
|
||||
return nil
|
||||
})
|
||||
if s.tlsConfig != nil {
|
||||
if !common.Contains(s.tlsConfig.NextProtos(), http2.NextProtoTLS) {
|
||||
s.tlsConfig.SetNextProtos(append([]string{"h2"}, s.tlsConfig.NextProtos()...))
|
||||
@@ -148,15 +161,6 @@ func (s *RealmService) Start(stage adapter.StartStage) error {
|
||||
s.logger.Error("serve error: ", err)
|
||||
}
|
||||
}()
|
||||
scope.Add(s.httpServer.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RealmService) Close() error {
|
||||
s.cancel()
|
||||
err := common.Close(common.PtrOrNil(s.httpServer))
|
||||
s.server.closeAll()
|
||||
return E.Errors(err, common.Close(
|
||||
common.PtrOrNil(s.listener),
|
||||
s.tlsConfig,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -88,15 +88,14 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create TLS config")
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(
|
||||
h.listener,
|
||||
h.tlsConfig,
|
||||
)
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
|
||||
@@ -52,7 +52,6 @@ type Inbound struct {
|
||||
authenticator *auth.Authenticator
|
||||
tlsConfig tls.ServerConfig
|
||||
httpServer *http.Server
|
||||
h3Server io.Closer
|
||||
}
|
||||
|
||||
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.NaiveInboundOptions) (adapter.Inbound, error) {
|
||||
@@ -89,7 +88,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (n *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (n *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -98,7 +97,9 @@ func (n *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create TLS config")
|
||||
}
|
||||
scope.Add(n.tlsConfig.Close)
|
||||
}
|
||||
scope.Add(n.listener.Close)
|
||||
if common.Contains(n.network, N.NetworkTCP) {
|
||||
tcpListener, err := n.listener.ListenTCP()
|
||||
if err != nil {
|
||||
@@ -126,12 +127,13 @@ func (n *Inbound) Start(stage adapter.StartStage) error {
|
||||
n.logger.Error("http server serve error: ", sErr)
|
||||
}
|
||||
}()
|
||||
scope.Add(n.httpServer.Close)
|
||||
}
|
||||
|
||||
if common.Contains(n.network, N.NetworkUDP) {
|
||||
http3Server, err := ConfigureHTTP3ListenerFunc(n.ctx, n.logger, n.listener, n, n.tlsConfig, n.options)
|
||||
if err == nil {
|
||||
n.h3Server = http3Server
|
||||
scope.Add(http3Server.Close)
|
||||
} else if len(n.network) > 1 {
|
||||
n.logger.Warn(E.Cause(err, "naive http3 disabled"))
|
||||
} else {
|
||||
@@ -142,15 +144,6 @@ func (n *Inbound) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (n *Inbound) Close() error {
|
||||
return common.Close(
|
||||
n.listener,
|
||||
common.PtrOrNil(n.httpServer),
|
||||
n.h3Server,
|
||||
n.tlsConfig,
|
||||
)
|
||||
}
|
||||
|
||||
func (n *Inbound) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
|
||||
ctx := log.ContextWithNewID(request.Context())
|
||||
if request.Method != "CONNECT" {
|
||||
|
||||
@@ -221,7 +221,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *Outbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -229,6 +229,7 @@ func (h *Outbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.client.Close)
|
||||
h.logger.Info("NaiveProxy started, version: ", h.client.Engine().Version())
|
||||
return nil
|
||||
}
|
||||
@@ -260,10 +261,6 @@ func (h *Outbound) InterfaceUpdated(ctx context.Context) {
|
||||
h.client.CloseAllConnections()
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return h.client.Close()
|
||||
}
|
||||
|
||||
func (h *Outbound) Client() *cronet.NaiveClient {
|
||||
return h.client
|
||||
}
|
||||
|
||||
@@ -43,25 +43,22 @@ var (
|
||||
|
||||
type Endpoint struct {
|
||||
endpointBase
|
||||
loopContext context.Context
|
||||
cancelLoop context.CancelFunc
|
||||
dnsRouter adapter.DNSRouter
|
||||
client *openconnect.Client
|
||||
device openconnecttransport.Device
|
||||
server string
|
||||
flavor string
|
||||
stateAccess sync.Mutex
|
||||
state atomic.Pointer[clientState]
|
||||
dnsTransportAccess sync.Mutex
|
||||
dnsTransport *DNSTransport
|
||||
deviceStarted bool
|
||||
readLoopDone chan struct{}
|
||||
statusAccess sync.Mutex
|
||||
statusUpdated chan struct{}
|
||||
terminalError string
|
||||
authFormLoopDone chan struct{}
|
||||
activeTransportLoopDone chan struct{}
|
||||
hotpCounter atomic.Uint64
|
||||
loopContext context.Context
|
||||
cancelLoop context.CancelFunc
|
||||
dnsRouter adapter.DNSRouter
|
||||
client *openconnect.Client
|
||||
device openconnecttransport.Device
|
||||
server string
|
||||
flavor string
|
||||
stateAccess sync.Mutex
|
||||
state atomic.Pointer[clientState]
|
||||
dnsTransportAccess sync.Mutex
|
||||
dnsTransport *DNSTransport
|
||||
deviceStarted bool
|
||||
statusAccess sync.Mutex
|
||||
statusUpdated chan struct{}
|
||||
terminalError string
|
||||
hotpCounter atomic.Uint64
|
||||
}
|
||||
|
||||
type clientState struct {
|
||||
@@ -418,34 +415,60 @@ func (e *Endpoint) updateState(update func(state *clientState)) {
|
||||
e.state.Store(&newState)
|
||||
}
|
||||
|
||||
func (e *Endpoint) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStatePostStart {
|
||||
return nil
|
||||
func (e *Endpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
scope.Add(func() error {
|
||||
e.notifyStatusUpdated()
|
||||
return nil
|
||||
})
|
||||
scope.Add(e.device.Close)
|
||||
scope.Add(func() error {
|
||||
e.cancelLoop()
|
||||
return nil
|
||||
})
|
||||
case adapter.StartStatePostStart:
|
||||
var loopGroup sync.WaitGroup
|
||||
scope.Add(func() error {
|
||||
loopGroup.Wait()
|
||||
return nil
|
||||
})
|
||||
err := e.client.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(e.client.Close)
|
||||
e.stateAccess.Lock()
|
||||
e.updateState(func(state *clientState) {
|
||||
state.started = true
|
||||
})
|
||||
e.stateAccess.Unlock()
|
||||
scope.Add(func() error {
|
||||
e.stateAccess.Lock()
|
||||
e.updateState(func(state *clientState) {
|
||||
state.started = false
|
||||
})
|
||||
e.stateAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
loopGroup.Go(func() {
|
||||
e.readLoop(scope.Context())
|
||||
})
|
||||
loopGroup.Go(func() {
|
||||
e.watchAuthForms(scope.Context())
|
||||
})
|
||||
loopGroup.Go(func() {
|
||||
e.watchActiveTransport(scope.Context())
|
||||
})
|
||||
}
|
||||
err := e.client.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.stateAccess.Lock()
|
||||
e.updateState(func(state *clientState) {
|
||||
state.started = true
|
||||
})
|
||||
e.readLoopDone = make(chan struct{})
|
||||
e.authFormLoopDone = make(chan struct{})
|
||||
e.activeTransportLoopDone = make(chan struct{})
|
||||
e.stateAccess.Unlock()
|
||||
go e.readLoop()
|
||||
go e.watchAuthForms()
|
||||
go e.watchActiveTransport()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *Endpoint) readLoop() {
|
||||
defer close(e.readLoopDone)
|
||||
func (e *Endpoint) readLoop(ctx context.Context) {
|
||||
for {
|
||||
packetBuffers, err := e.client.ReadDataPackets(e.loopContext)
|
||||
packetBuffers, err := e.client.ReadDataPackets(ctx)
|
||||
if err != nil {
|
||||
if E.IsClosedOrCanceled(err) || e.loopContext.Err() != nil {
|
||||
if E.IsClosedOrCanceled(err) || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
e.logger.Error(E.Cause(err, "client terminated"))
|
||||
@@ -463,30 +486,6 @@ func (e *Endpoint) readLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Endpoint) Close() error {
|
||||
e.stateAccess.Lock()
|
||||
e.updateState(func(state *clientState) {
|
||||
state.started = false
|
||||
})
|
||||
readLoopDone := e.readLoopDone
|
||||
authFormLoopDone := e.authFormLoopDone
|
||||
activeTransportLoopDone := e.activeTransportLoopDone
|
||||
e.stateAccess.Unlock()
|
||||
e.cancelLoop()
|
||||
err := E.Errors(e.client.Close(), e.device.Close())
|
||||
if readLoopDone != nil {
|
||||
<-readLoopDone
|
||||
}
|
||||
if authFormLoopDone != nil {
|
||||
<-authFormLoopDone
|
||||
}
|
||||
if activeTransportLoopDone != nil {
|
||||
<-activeTransportLoopDone
|
||||
}
|
||||
e.notifyStatusUpdated()
|
||||
return err
|
||||
}
|
||||
|
||||
func (e *Endpoint) InterfaceUpdated(ctx context.Context) {
|
||||
e.client.RestartSession()
|
||||
}
|
||||
|
||||
@@ -30,18 +30,19 @@ func RegisterDNSTransport(registry *dns.TransportRegistry) {
|
||||
|
||||
type DNSTransport struct {
|
||||
dns.TransportAdapter
|
||||
ctx context.Context
|
||||
logger logger.ContextLogger
|
||||
endpointTag string
|
||||
acceptDefaultResolvers bool
|
||||
acceptSearchDomain bool
|
||||
endpointManager adapter.EndpointManager
|
||||
endpoint *Endpoint
|
||||
dialer N.Dialer
|
||||
access sync.RWMutex
|
||||
closed bool
|
||||
routes []openConnectDNSRoute
|
||||
searchDomains []string
|
||||
defaultResolvers []adapter.DNSTransport
|
||||
resolverScope *adapter.Scope
|
||||
}
|
||||
|
||||
type openConnectDNSRoute struct {
|
||||
@@ -55,6 +56,7 @@ func NewDNSTransport(ctx context.Context, logger log.ContextLogger, tag string,
|
||||
}
|
||||
return &DNSTransport{
|
||||
TransportAdapter: dns.NewTransportAdapter(C.DNSTypeOpenConnect, tag, nil),
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
endpointTag: options.Endpoint,
|
||||
acceptDefaultResolvers: options.AcceptDefaultResolvers,
|
||||
@@ -63,7 +65,7 @@ func NewDNSTransport(ctx context.Context, logger log.ContextLogger, tag string,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *DNSTransport) Start(stage adapter.StartStage) error {
|
||||
func (t *DNSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
@@ -75,13 +77,34 @@ func (t *DNSTransport) Start(stage adapter.StartStage) error {
|
||||
if !isOpenConnect {
|
||||
return E.New("endpoint is not OpenConnect: ", t.endpointTag)
|
||||
}
|
||||
scope.Add(func() error {
|
||||
t.access.Lock()
|
||||
resolverScope := t.resolverScope
|
||||
t.closed = true
|
||||
t.routes = nil
|
||||
t.searchDomains = nil
|
||||
t.defaultResolvers = nil
|
||||
t.resolverScope = nil
|
||||
t.access.Unlock()
|
||||
if resolverScope != nil {
|
||||
return resolverScope.Close()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
openConnectEndpoint.dnsTransportAccess.Lock()
|
||||
if openConnectEndpoint.dnsTransport != nil && openConnectEndpoint.dnsTransport.Tag() != t.Tag() {
|
||||
openConnectEndpoint.dnsTransportAccess.Unlock()
|
||||
return E.New("only one DNS server is allowed for an endpoint")
|
||||
}
|
||||
openConnectEndpoint.dnsTransport = t
|
||||
t.endpoint = openConnectEndpoint
|
||||
scope.Add(func() error {
|
||||
openConnectEndpoint.dnsTransportAccess.Lock()
|
||||
if openConnectEndpoint.dnsTransport == t {
|
||||
openConnectEndpoint.dnsTransport = nil
|
||||
}
|
||||
openConnectEndpoint.dnsTransportAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
t.dialer = openConnectEndpoint
|
||||
state := openConnectEndpoint.state.Load()
|
||||
if state.started && state.tunnelConfigured && openConnectEndpoint.client.Ready() {
|
||||
@@ -176,32 +199,29 @@ func (t *DNSTransport) updateConfiguration(configuration openconnecttransport.Co
|
||||
defaultResolvers = nil
|
||||
}
|
||||
|
||||
resolverScope := adapter.NewScope(t.ctx, t.logger)
|
||||
for _, resolver := range resolverByAddress {
|
||||
err := resolver.Start(adapter.StartStateStart, resolverScope)
|
||||
if err != nil {
|
||||
resolverScope.Close()
|
||||
t.logger.Error(E.Cause(err, "start DNS resolver"))
|
||||
return
|
||||
}
|
||||
}
|
||||
t.access.Lock()
|
||||
if t.closed {
|
||||
t.access.Unlock()
|
||||
for _, resolver := range resolverByAddress {
|
||||
_ = resolver.Close()
|
||||
}
|
||||
resolverScope.Close()
|
||||
return
|
||||
}
|
||||
oldResolvers := t.collectResolversLocked()
|
||||
oldResolverScope := t.resolverScope
|
||||
t.routes = routes
|
||||
t.searchDomains = searchDomains
|
||||
t.defaultResolvers = defaultResolvers
|
||||
activeResolvers := t.collectResolversLocked()
|
||||
t.resolverScope = resolverScope
|
||||
t.access.Unlock()
|
||||
|
||||
for _, resolver := range oldResolvers {
|
||||
_ = resolver.Close()
|
||||
}
|
||||
activeResolverSet := make(map[adapter.DNSTransport]bool, len(activeResolvers))
|
||||
for _, resolver := range activeResolvers {
|
||||
activeResolverSet[resolver] = true
|
||||
}
|
||||
for _, resolver := range resolverByAddress {
|
||||
if !activeResolverSet[resolver] {
|
||||
_ = resolver.Close()
|
||||
}
|
||||
if oldResolverScope != nil {
|
||||
oldResolverScope.Close()
|
||||
}
|
||||
if len(resolverByAddress) > 0 {
|
||||
t.logger.Info("updated ", len(routes), " DNS routes and ", len(resolverByAddress), " resolvers")
|
||||
@@ -219,28 +239,6 @@ func (t *DNSTransport) Reset() {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DNSTransport) Close() error {
|
||||
if t.endpoint != nil {
|
||||
t.endpoint.dnsTransportAccess.Lock()
|
||||
if t.endpoint.dnsTransport == t {
|
||||
t.endpoint.dnsTransport = nil
|
||||
}
|
||||
t.endpoint.dnsTransportAccess.Unlock()
|
||||
}
|
||||
t.access.Lock()
|
||||
resolvers := t.collectResolversLocked()
|
||||
t.closed = true
|
||||
t.routes = nil
|
||||
t.searchDomains = nil
|
||||
t.defaultResolvers = nil
|
||||
t.access.Unlock()
|
||||
var closeErr error
|
||||
for _, resolver := range resolvers {
|
||||
closeErr = E.Errors(closeErr, resolver.Close())
|
||||
}
|
||||
return closeErr
|
||||
}
|
||||
|
||||
func (t *DNSTransport) PreferredDomain(domain string) bool {
|
||||
canonicalDomain := mDNS.Fqdn(canonicalOpenConnectDomain(domain))
|
||||
t.access.RLock()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package openconnect
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"slices"
|
||||
|
||||
@@ -132,8 +133,7 @@ func (e *Endpoint) setTerminalError(err error) {
|
||||
e.statusAccess.Unlock()
|
||||
}
|
||||
|
||||
func (e *Endpoint) watchAuthForms() {
|
||||
defer close(e.authFormLoopDone)
|
||||
func (e *Endpoint) watchAuthForms(ctx context.Context) {
|
||||
var loggedAuthChallengeID string
|
||||
for {
|
||||
authChallengeUpdated := e.client.AuthChallengeUpdated()
|
||||
@@ -148,15 +148,14 @@ func (e *Endpoint) watchAuthForms() {
|
||||
}
|
||||
e.notifyStatusUpdated()
|
||||
select {
|
||||
case <-e.loopContext.Done():
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-authChallengeUpdated:
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (e *Endpoint) watchActiveTransport() {
|
||||
defer close(e.activeTransportLoopDone)
|
||||
func (e *Endpoint) watchActiveTransport(ctx context.Context) {
|
||||
for {
|
||||
transportUpdated := e.client.ActiveTransportUpdated()
|
||||
transport := e.client.ActiveTransport()
|
||||
@@ -167,7 +166,7 @@ func (e *Endpoint) watchActiveTransport() {
|
||||
e.stateAccess.Unlock()
|
||||
e.notifyStatusUpdated()
|
||||
select {
|
||||
case <-e.loopContext.Done():
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-transportUpdated:
|
||||
}
|
||||
|
||||
+60
-57
@@ -42,23 +42,21 @@ var (
|
||||
|
||||
type ClientEndpoint struct {
|
||||
endpointBase
|
||||
ctx context.Context
|
||||
loopContext context.Context
|
||||
cancelLoop context.CancelFunc
|
||||
dnsRouter adapter.DNSRouter
|
||||
outboundDialer N.Dialer
|
||||
queryOptions adapter.DNSQueryOptions
|
||||
client *ovpn.Client
|
||||
device ovpntransport.Device
|
||||
stateAccess sync.Mutex
|
||||
state atomic.Pointer[clientState]
|
||||
dnsTransport *DNSTransport
|
||||
deviceStarted bool
|
||||
readLoopDone chan struct{}
|
||||
statusAccess sync.Mutex
|
||||
statusUpdated chan struct{}
|
||||
terminalError string
|
||||
challengeLoopDone chan struct{}
|
||||
ctx context.Context
|
||||
loopContext context.Context
|
||||
cancelLoop context.CancelFunc
|
||||
dnsRouter adapter.DNSRouter
|
||||
outboundDialer N.Dialer
|
||||
queryOptions adapter.DNSQueryOptions
|
||||
client *ovpn.Client
|
||||
device ovpntransport.Device
|
||||
stateAccess sync.Mutex
|
||||
state atomic.Pointer[clientState]
|
||||
dnsTransport *DNSTransport
|
||||
deviceStarted bool
|
||||
statusAccess sync.Mutex
|
||||
statusUpdated chan struct{}
|
||||
terminalError string
|
||||
}
|
||||
|
||||
type clientState struct {
|
||||
@@ -596,32 +594,57 @@ func (c *ClientEndpoint) uninstallDNSTransport(dnsTransport *DNSTransport) {
|
||||
c.stateAccess.Unlock()
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStatePostStart {
|
||||
return nil
|
||||
func (c *ClientEndpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
scope.Add(func() error {
|
||||
c.notifyStatusUpdated()
|
||||
return nil
|
||||
})
|
||||
scope.Add(c.device.Close)
|
||||
scope.Add(func() error {
|
||||
c.cancelLoop()
|
||||
return nil
|
||||
})
|
||||
case adapter.StartStatePostStart:
|
||||
var loopGroup sync.WaitGroup
|
||||
scope.Add(func() error {
|
||||
loopGroup.Wait()
|
||||
return nil
|
||||
})
|
||||
err := c.client.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(c.client.Close)
|
||||
c.stateAccess.Lock()
|
||||
c.updateState(func(state *clientState) {
|
||||
state.started = true
|
||||
})
|
||||
c.stateAccess.Unlock()
|
||||
scope.Add(func() error {
|
||||
c.stateAccess.Lock()
|
||||
c.updateState(func(state *clientState) {
|
||||
state.started = false
|
||||
})
|
||||
c.stateAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
loopGroup.Go(func() {
|
||||
c.readLoop(scope.Context())
|
||||
})
|
||||
loopGroup.Go(func() {
|
||||
c.watchChallenges(scope.Context())
|
||||
})
|
||||
}
|
||||
err := c.client.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.stateAccess.Lock()
|
||||
c.updateState(func(state *clientState) {
|
||||
state.started = true
|
||||
})
|
||||
c.readLoopDone = make(chan struct{})
|
||||
c.challengeLoopDone = make(chan struct{})
|
||||
c.stateAccess.Unlock()
|
||||
go c.readLoop()
|
||||
go c.watchChallenges()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) readLoop() {
|
||||
defer close(c.readLoopDone)
|
||||
func (c *ClientEndpoint) readLoop(ctx context.Context) {
|
||||
for {
|
||||
packetBuffers, err := c.client.ReadDataPackets(c.loopContext)
|
||||
packetBuffers, err := c.client.ReadDataPackets(ctx)
|
||||
if err != nil {
|
||||
if E.IsClosedOrCanceled(err) || c.loopContext.Err() != nil {
|
||||
if E.IsClosedOrCanceled(err) || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
c.logger.Error(E.Cause(err, "client terminated"))
|
||||
@@ -639,26 +662,6 @@ func (c *ClientEndpoint) readLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) Close() error {
|
||||
c.stateAccess.Lock()
|
||||
c.updateState(func(state *clientState) {
|
||||
state.started = false
|
||||
})
|
||||
readLoopDone := c.readLoopDone
|
||||
challengeLoopDone := c.challengeLoopDone
|
||||
c.stateAccess.Unlock()
|
||||
c.cancelLoop()
|
||||
err := E.Errors(c.client.Close(), c.device.Close())
|
||||
if readLoopDone != nil {
|
||||
<-readLoopDone
|
||||
}
|
||||
if challengeLoopDone != nil {
|
||||
<-challengeLoopDone
|
||||
}
|
||||
c.notifyStatusUpdated()
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) InterfaceUpdated(ctx context.Context) {
|
||||
c.client.RestartSession()
|
||||
}
|
||||
|
||||
@@ -43,7 +43,6 @@ type DNSTransport struct {
|
||||
acceptDefaultResolvers bool
|
||||
acceptSearchDomain bool
|
||||
endpointManager adapter.EndpointManager
|
||||
endpoint *ClientEndpoint
|
||||
dialer N.Dialer
|
||||
updateAccess sync.Mutex
|
||||
access sync.RWMutex
|
||||
@@ -51,6 +50,7 @@ type DNSTransport struct {
|
||||
routes map[string][]adapter.DNSTransport
|
||||
searchDomains []string
|
||||
defaultResolvers []adapter.DNSTransport
|
||||
resolverScope *adapter.Scope
|
||||
}
|
||||
|
||||
func NewDNSTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.OpenVPNDNSServerOptions) (adapter.DNSTransport, error) {
|
||||
@@ -68,7 +68,7 @@ func NewDNSTransport(ctx context.Context, logger log.ContextLogger, tag string,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *DNSTransport) Start(stage adapter.StartStage) error {
|
||||
func (t *DNSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
@@ -80,14 +80,31 @@ func (t *DNSTransport) Start(stage adapter.StartStage) error {
|
||||
if !isOpenVPN {
|
||||
return E.New("endpoint is not an OpenVPN client: ", t.endpointTag)
|
||||
}
|
||||
t.endpoint = endpoint
|
||||
t.dialer = endpoint
|
||||
scope.Add(func() error {
|
||||
t.updateAccess.Lock()
|
||||
t.access.Lock()
|
||||
resolverScope := t.resolverScope
|
||||
t.closed = true
|
||||
t.routes = nil
|
||||
t.searchDomains = nil
|
||||
t.defaultResolvers = nil
|
||||
t.resolverScope = nil
|
||||
t.access.Unlock()
|
||||
t.updateAccess.Unlock()
|
||||
if resolverScope != nil {
|
||||
return resolverScope.Close()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
err := endpoint.installDNSTransport(t)
|
||||
if err != nil {
|
||||
t.endpoint = nil
|
||||
t.dialer = nil
|
||||
return err
|
||||
}
|
||||
scope.Add(func() error {
|
||||
endpoint.uninstallDNSTransport(t)
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -110,7 +127,7 @@ func (t *DNSTransport) updateResolvers(configuration ovpntransport.Configuration
|
||||
routes := make(map[string][]adapter.DNSTransport)
|
||||
searchDomains := normalizeOpenVPNDomains(configuration.SearchDomains)
|
||||
var defaultResolvers []adapter.DNSTransport
|
||||
var newResolvers []adapter.DNSTransport
|
||||
resolverScope := adapter.NewScope(t.ctx, t.logger)
|
||||
servers := slices.Clone(configuration.DNSServers)
|
||||
slices.SortFunc(servers, func(left ovpntransport.DNSServer, right ovpntransport.DNSServer) int {
|
||||
return left.Priority - right.Priority
|
||||
@@ -119,18 +136,21 @@ func (t *DNSTransport) updateResolvers(configuration ovpntransport.Configuration
|
||||
if len(servers) > 0 {
|
||||
server := servers[0]
|
||||
if server.DNSSEC == "yes" {
|
||||
return t.failResolverUpdate(newResolvers, E.New("DNSSEC validation is required but is not supported"))
|
||||
return t.failResolverUpdate(resolverScope, E.New("DNSSEC validation is required but is not supported"))
|
||||
}
|
||||
for _, address := range server.Addresses {
|
||||
resolver, err := t.createResolver(server, address)
|
||||
if err != nil {
|
||||
return t.failResolverUpdate(newResolvers, err)
|
||||
return t.failResolverUpdate(resolverScope, err)
|
||||
}
|
||||
err = resolver.Start(adapter.StartStateStart, resolverScope)
|
||||
if err != nil {
|
||||
return t.failResolverUpdate(resolverScope, err)
|
||||
}
|
||||
selectedResolvers = append(selectedResolvers, resolver)
|
||||
newResolvers = append(newResolvers, resolver)
|
||||
}
|
||||
if len(selectedResolvers) == 0 {
|
||||
return t.failResolverUpdate(newResolvers, E.New("DNS server ", server.Priority, " has no addresses"))
|
||||
return t.failResolverUpdate(resolverScope, E.New("DNS server ", server.Priority, " has no addresses"))
|
||||
}
|
||||
if len(server.ResolveDomains) == 0 {
|
||||
defaultResolvers = slices.Clone(selectedResolvers)
|
||||
@@ -145,12 +165,15 @@ func (t *DNSTransport) updateResolvers(configuration ovpntransport.Configuration
|
||||
} else {
|
||||
for _, address := range configuration.DNS {
|
||||
resolver := dnsTransport.NewUDPRaw(t.logger, t.TransportAdapter, t.dialer, M.SocksaddrFrom(address, 53))
|
||||
err := resolver.Start(adapter.StartStateStart, resolverScope)
|
||||
if err != nil {
|
||||
return t.failResolverUpdate(resolverScope, err)
|
||||
}
|
||||
selectedResolvers = append(selectedResolvers, resolver)
|
||||
newResolvers = append(newResolvers, resolver)
|
||||
}
|
||||
if len(configuration.DNSRoutes) > 0 {
|
||||
if len(selectedResolvers) == 0 {
|
||||
return t.failResolverUpdate(newResolvers, E.New("DOMAIN-ROUTE requires traditional pushed DNS servers"))
|
||||
return t.failResolverUpdate(resolverScope, E.New("DOMAIN-ROUTE requires traditional pushed DNS servers"))
|
||||
}
|
||||
for _, domain := range configuration.DNSRoutes {
|
||||
normalizedDomain := normalizeOpenVPNDomain(domain)
|
||||
@@ -163,32 +186,40 @@ func (t *DNSTransport) updateResolvers(configuration ovpntransport.Configuration
|
||||
}
|
||||
}
|
||||
if len(searchDomains) > 0 && len(selectedResolvers) == 0 {
|
||||
return t.failResolverUpdate(newResolvers, E.New("search domains require pushed DNS servers"))
|
||||
return t.failResolverUpdate(resolverScope, E.New("search domains require pushed DNS servers"))
|
||||
}
|
||||
for _, searchDomain := range searchDomains {
|
||||
routes[searchDomain] = slices.Clone(selectedResolvers)
|
||||
}
|
||||
|
||||
t.access.Lock()
|
||||
oldResolvers := t.collectResolversLocked()
|
||||
oldResolverScope := t.resolverScope
|
||||
t.routes = routes
|
||||
t.searchDomains = searchDomains
|
||||
t.defaultResolvers = defaultResolvers
|
||||
t.resolverScope = resolverScope
|
||||
t.access.Unlock()
|
||||
closeErr := closeDNSTransports(oldResolvers)
|
||||
var closeErr error
|
||||
if oldResolverScope != nil {
|
||||
closeErr = oldResolverScope.Close()
|
||||
}
|
||||
t.logger.Info("updated ", len(routes), " DNS routes, ", len(searchDomains), " search domains and ", len(defaultResolvers), " default resolvers")
|
||||
return closeErr
|
||||
}
|
||||
|
||||
func (t *DNSTransport) failResolverUpdate(newResolvers []adapter.DNSTransport, updateErr error) error {
|
||||
newCloseErr := closeDNSTransports(newResolvers)
|
||||
func (t *DNSTransport) failResolverUpdate(resolverScope *adapter.Scope, updateErr error) error {
|
||||
newCloseErr := resolverScope.Close()
|
||||
t.access.Lock()
|
||||
oldResolvers := t.collectResolversLocked()
|
||||
oldResolverScope := t.resolverScope
|
||||
t.routes = nil
|
||||
t.searchDomains = nil
|
||||
t.defaultResolvers = nil
|
||||
t.resolverScope = nil
|
||||
t.access.Unlock()
|
||||
oldCloseErr := closeDNSTransports(oldResolvers)
|
||||
var oldCloseErr error
|
||||
if oldResolverScope != nil {
|
||||
oldCloseErr = oldResolverScope.Close()
|
||||
}
|
||||
return E.Errors(updateErr, newCloseErr, oldCloseErr)
|
||||
}
|
||||
|
||||
@@ -255,24 +286,6 @@ func (t *DNSTransport) Reset() {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *DNSTransport) Close() error {
|
||||
if t.endpoint != nil {
|
||||
t.endpoint.uninstallDNSTransport(t)
|
||||
}
|
||||
t.updateAccess.Lock()
|
||||
t.access.Lock()
|
||||
resolvers := t.collectResolversLocked()
|
||||
t.closed = true
|
||||
t.routes = nil
|
||||
t.searchDomains = nil
|
||||
t.defaultResolvers = nil
|
||||
t.access.Unlock()
|
||||
t.endpoint = nil
|
||||
t.dialer = nil
|
||||
t.updateAccess.Unlock()
|
||||
return closeDNSTransports(resolvers)
|
||||
}
|
||||
|
||||
func (t *DNSTransport) Raw() bool {
|
||||
return true
|
||||
}
|
||||
@@ -384,16 +397,6 @@ func (t *DNSTransport) collectResolversLocked() []adapter.DNSTransport {
|
||||
return common.Uniq(resolvers)
|
||||
}
|
||||
|
||||
func closeDNSTransports(resolvers []adapter.DNSTransport) error {
|
||||
var err error
|
||||
for _, resolver := range common.Uniq(resolvers) {
|
||||
err = E.Append(err, resolver.Close(), func(closeErr error) error {
|
||||
return E.Cause(closeErr, "close DNS resolver")
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func normalizeOpenVPNDomain(domain string) string {
|
||||
normalized := strings.TrimSpace(strings.ToLower(domain))
|
||||
if normalized == "." {
|
||||
|
||||
+27
-37
@@ -6,6 +6,7 @@ import (
|
||||
"net/netip"
|
||||
"slices"
|
||||
"strconv"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
@@ -35,7 +36,6 @@ var (
|
||||
type ServerEndpoint struct {
|
||||
endpointBase
|
||||
ctx context.Context
|
||||
loopContext context.Context
|
||||
cancelLoop context.CancelFunc
|
||||
options option.OpenVPNServerEndpointOptions
|
||||
serverOptions ovpn.ServerOptions
|
||||
@@ -45,7 +45,6 @@ type ServerEndpoint struct {
|
||||
device ovpntransport.Device
|
||||
localAddresses []netip.Prefix
|
||||
started atomic.Bool
|
||||
readLoopDone chan struct{}
|
||||
}
|
||||
|
||||
type udpEgressPacketConn struct {
|
||||
@@ -80,7 +79,6 @@ func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
logger: logger,
|
||||
},
|
||||
ctx: ctx,
|
||||
loopContext: loopContext,
|
||||
cancelLoop: cancelLoop,
|
||||
options: options,
|
||||
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
|
||||
@@ -161,7 +159,15 @@ func validateServerTopology(topology string) error {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) Start(stage adapter.StartStage) error {
|
||||
func (s *ServerEndpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage == adapter.StartStateInitialize {
|
||||
scope.Add(s.device.Close)
|
||||
scope.Add(func() error {
|
||||
s.cancelLoop()
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -225,6 +231,7 @@ func (s *ServerEndpoint) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(s.listener.Close)
|
||||
serverOptions := s.serverOptions
|
||||
if streamListener != nil {
|
||||
serverOptions.Transport.ListenAddress = streamListener.Addr().String()
|
||||
@@ -238,26 +245,31 @@ func (s *ServerEndpoint) Start(stage adapter.StartStage) error {
|
||||
if packetConn != nil {
|
||||
_ = packetConn.Close()
|
||||
}
|
||||
s.listener.Close()
|
||||
return err
|
||||
}
|
||||
s.server = server
|
||||
var loopGroup sync.WaitGroup
|
||||
scope.Add(func() error {
|
||||
loopGroup.Wait()
|
||||
return nil
|
||||
})
|
||||
scope.Add(server.Close)
|
||||
err = s.device.Start()
|
||||
if err != nil {
|
||||
s.listener.Close()
|
||||
server.Close()
|
||||
return err
|
||||
}
|
||||
err = server.Start()
|
||||
if err != nil {
|
||||
s.device.Close()
|
||||
s.listener.Close()
|
||||
server.Close()
|
||||
return err
|
||||
}
|
||||
s.started.Store(true)
|
||||
s.readLoopDone = make(chan struct{})
|
||||
go s.readLoop()
|
||||
scope.Add(func() error {
|
||||
s.started.Store(false)
|
||||
return nil
|
||||
})
|
||||
loopGroup.Go(func() {
|
||||
s.readLoop(scope.Context())
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -598,12 +610,11 @@ func applyServerPushOptions(serverOptions *ovpn.ServerOptions, options option.Op
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) readLoop() {
|
||||
defer close(s.readLoopDone)
|
||||
func (s *ServerEndpoint) readLoop(ctx context.Context) {
|
||||
for {
|
||||
serverPacketBuffers, err := s.server.ReadDataPackets(s.loopContext)
|
||||
serverPacketBuffers, err := s.server.ReadDataPackets(ctx)
|
||||
if err != nil {
|
||||
if E.IsClosedOrCanceled(err) || s.loopContext.Err() != nil {
|
||||
if E.IsClosedOrCanceled(err) || ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
s.logger.Error(E.Cause(err, "server terminated"))
|
||||
@@ -622,27 +633,6 @@ func (s *ServerEndpoint) readLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) Close() error {
|
||||
s.started.Store(false)
|
||||
s.cancelLoop()
|
||||
var serverErr error
|
||||
if s.server != nil {
|
||||
serverErr = s.server.Close()
|
||||
}
|
||||
if s.readLoopDone != nil {
|
||||
<-s.readLoopDone
|
||||
}
|
||||
var deviceErr error
|
||||
if s.device != nil {
|
||||
deviceErr = s.device.Close()
|
||||
}
|
||||
var listenerErr error
|
||||
if s.listener != nil {
|
||||
listenerErr = s.listener.Close()
|
||||
}
|
||||
return E.Errors(serverErr, deviceErr, listenerErr)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction {
|
||||
return adapter.PreMatchFlow
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package openvpn
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
@@ -81,8 +82,7 @@ func (c *ClientEndpoint) setTerminalError(err error) {
|
||||
c.statusAccess.Unlock()
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) watchChallenges() {
|
||||
defer close(c.challengeLoopDone)
|
||||
func (c *ClientEndpoint) watchChallenges(ctx context.Context) {
|
||||
var loggedChallengeID string
|
||||
for {
|
||||
challengeUpdated := c.client.ChallengeUpdated()
|
||||
@@ -93,7 +93,7 @@ func (c *ClientEndpoint) watchChallenges() {
|
||||
}
|
||||
c.notifyStatusUpdated()
|
||||
select {
|
||||
case <-c.loopContext.Done():
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-challengeUpdated:
|
||||
}
|
||||
|
||||
@@ -42,15 +42,16 @@ func NewRedirect(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
return redirect, nil
|
||||
}
|
||||
|
||||
func (h *Redirect) Start(stage adapter.StartStage) error {
|
||||
func (h *Redirect) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *Redirect) Close() error {
|
||||
return h.listener.Close()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Redirect) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
|
||||
@@ -70,7 +70,7 @@ func NewTProxy(ctx context.Context, router adapter.Router, logger log.ContextLog
|
||||
return tproxy, nil
|
||||
}
|
||||
|
||||
func (t *TProxy) Start(stage adapter.StartStage) error {
|
||||
func (t *TProxy) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -78,22 +78,19 @@ func (t *TProxy) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(t.udpNat.Close)
|
||||
err = t.listener.Start()
|
||||
if err != nil {
|
||||
_ = t.udpNat.Close()
|
||||
return err
|
||||
}
|
||||
return err
|
||||
scope.Add(t.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *TProxy) InterfaceUpdated(ctx context.Context) {
|
||||
t.udpNat.Purge()
|
||||
}
|
||||
|
||||
func (t *TProxy) Close() error {
|
||||
_ = t.udpNat.Close()
|
||||
return t.listener.Close()
|
||||
}
|
||||
|
||||
func (t *TProxy) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
metadata.Inbound = t.Tag()
|
||||
metadata.InboundType = t.Type()
|
||||
|
||||
@@ -95,15 +95,16 @@ func newInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, err
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return h.listener.Close()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:staticcheck
|
||||
|
||||
@@ -109,15 +109,16 @@ func newMultiInbound(ctx context.Context, router adapter.Router, logger log.Cont
|
||||
return inbound, err
|
||||
}
|
||||
|
||||
func (h *MultiInbound) Start(stage adapter.StartStage) error {
|
||||
func (h *MultiInbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *MultiInbound) Close() error {
|
||||
return h.listener.Close()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *MultiInbound) SetTracker(tracker adapter.SSMTracker) {
|
||||
|
||||
@@ -86,15 +86,16 @@ func newRelayInbound(ctx context.Context, router adapter.Router, logger log.Cont
|
||||
return inbound, err
|
||||
}
|
||||
|
||||
func (h *RelayInbound) Start(stage adapter.StartStage) error {
|
||||
func (h *RelayInbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *RelayInbound) Close() error {
|
||||
return h.listener.Close()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:staticcheck
|
||||
|
||||
@@ -152,8 +152,14 @@ func (h *Outbound) CloseIdleConnections() {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return common.Close(common.PtrOrNil(h.multiplexDialer))
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
if h.multiplexDialer != nil {
|
||||
scope.Add(h.multiplexDialer.Close)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var _ N.Dialer = (*shadowsocksDialer)(nil)
|
||||
|
||||
@@ -104,15 +104,16 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return h.listener.Close()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
|
||||
@@ -119,15 +119,16 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return h.listener.Close()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
|
||||
@@ -163,6 +163,10 @@ func (h *Outbound) CloseIdleConnections() {
|
||||
h.client.CloseIdleConnections()
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return h.client.Close()
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
scope.Add(h.client.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -60,15 +60,16 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
return h.listener.Start()
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return h.listener.Close()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
|
||||
@@ -260,8 +260,14 @@ func (s *Outbound) releaseStream(client *ssh.Client, keepSession bool) {
|
||||
common.Close(clientConn)
|
||||
}
|
||||
|
||||
func (s *Outbound) Close() error {
|
||||
return common.Close(s.clientConn)
|
||||
func (s *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
scope.Add(func() error {
|
||||
return common.Close(s.clientConn)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
|
||||
@@ -63,7 +63,7 @@ func NewCertificateProvider(ctx context.Context, _ log.ContextLogger, tag string
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (p *CertificateProvider) Start(stage adapter.StartStage) error {
|
||||
func (p *CertificateProvider) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -82,10 +82,6 @@ func (p *CertificateProvider) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *CertificateProvider) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *CertificateProvider) GetCertificate(clientHello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
localClient := p.localClient
|
||||
if localClient == nil {
|
||||
|
||||
@@ -59,6 +59,7 @@ type DNSTransport struct {
|
||||
magicHosts nDNSResolver.MagicDNSHosts
|
||||
searchDomains []string
|
||||
defaultResolvers []adapter.DNSTransport
|
||||
resolverScope *adapter.Scope
|
||||
}
|
||||
|
||||
func NewDNSTransport(ctx context.Context, logger log.ContextLogger, tag string, options option.TailscaleDNSServerOptions) (adapter.DNSTransport, error) {
|
||||
@@ -77,7 +78,7 @@ func NewDNSTransport(ctx context.Context, logger log.ContextLogger, tag string,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *DNSTransport) Start(stage adapter.StartStage) error {
|
||||
func (t *DNSTransport) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
@@ -94,6 +95,21 @@ func (t *DNSTransport) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
ep.onReconfigHook = t.onReconfig
|
||||
t.endpoint = ep
|
||||
scope.Add(func() error {
|
||||
t.access.Lock()
|
||||
resolverScope := t.resolverScope
|
||||
t.routePrefixes = nil
|
||||
t.routes = nil
|
||||
t.hosts = nil
|
||||
t.magicHosts = nil
|
||||
t.defaultResolvers = nil
|
||||
t.resolverScope = nil
|
||||
t.access.Unlock()
|
||||
if resolverScope != nil {
|
||||
return resolverScope.Close()
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -119,13 +135,14 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
|
||||
directDialer := common.Must1(dialer.NewDefault(t.ctx, option.DialerOptions{}))
|
||||
return &DNSDialer{transport: t, fallbackDialer: directDialer}
|
||||
})
|
||||
resolverScope := adapter.NewScope(t.ctx, t.logger)
|
||||
routes := make(map[string][]adapter.DNSTransport)
|
||||
for domain, resolvers := range dnsConfig.Routes {
|
||||
var myResolvers []adapter.DNSTransport
|
||||
for _, resolver := range resolvers {
|
||||
myResolver, err := t.createResolver(directDialerOnce, resolver)
|
||||
myResolver, err := t.createResolver(resolverScope, directDialerOnce, resolver)
|
||||
if err != nil {
|
||||
return err
|
||||
return E.Errors(err, resolverScope.Close())
|
||||
}
|
||||
myResolvers = append(myResolvers, myResolver)
|
||||
}
|
||||
@@ -140,25 +157,26 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
|
||||
})
|
||||
var defaultResolvers []adapter.DNSTransport
|
||||
for _, resolver := range dnsConfig.DefaultResolvers {
|
||||
myResolver, err := t.createResolver(directDialerOnce, resolver)
|
||||
myResolver, err := t.createResolver(resolverScope, directDialerOnce, resolver)
|
||||
if err != nil {
|
||||
return err
|
||||
return E.Errors(err, resolverScope.Close())
|
||||
}
|
||||
defaultResolvers = append(defaultResolvers, myResolver)
|
||||
}
|
||||
|
||||
t.access.Lock()
|
||||
oldResolvers := t.collectResolversLocked()
|
||||
oldResolverScope := t.resolverScope
|
||||
t.routePrefixes = routePrefixes
|
||||
t.routes = routes
|
||||
t.hosts = hosts
|
||||
t.magicHosts = t.endpoint.server.ExportLocalBackend().ExportMagicDNSHosts()
|
||||
t.searchDomains = searchDomains
|
||||
t.defaultResolvers = defaultResolvers
|
||||
t.resolverScope = resolverScope
|
||||
t.access.Unlock()
|
||||
|
||||
for _, transport := range oldResolvers {
|
||||
transport.Close()
|
||||
if oldResolverScope != nil {
|
||||
oldResolverScope.Close()
|
||||
}
|
||||
|
||||
if len(defaultResolvers) > 0 {
|
||||
@@ -170,7 +188,7 @@ func (t *DNSTransport) updateDNSServers(routeConfig *router.Config, dnsConfig *n
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dnstype.Resolver) (adapter.DNSTransport, error) {
|
||||
func (t *DNSTransport) createResolver(resolverScope *adapter.Scope, directDialer func() N.Dialer, resolver *dnstype.Resolver) (adapter.DNSTransport, error) {
|
||||
serverURL, parseURLErr := url.Parse(resolver.Addr)
|
||||
isHTTPScheme := parseURLErr == nil && (serverURL.Scheme == "http" || serverURL.Scheme == "https")
|
||||
var myDialer N.Dialer
|
||||
@@ -181,6 +199,10 @@ func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dn
|
||||
}
|
||||
if len(resolver.BootstrapResolution) > 0 {
|
||||
bootstrapTransport := transport.NewUDPRaw(t.logger, t.TransportAdapter, myDialer, M.SocksaddrFrom(resolver.BootstrapResolution[0], 53))
|
||||
err := bootstrapTransport.Start(adapter.StartStateStart, resolverScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
myDialer = dialer.NewResolveDialer(t.ctx, myDialer, false, "", adapter.DNSQueryOptions{Transport: bootstrapTransport}, 0)
|
||||
} else {
|
||||
myDialer = dialer.NewResolveDialer(t.ctx, myDialer, false, "", t.endpoint.queryOptions, 0)
|
||||
@@ -202,12 +224,22 @@ func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dn
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create TLS config for resolver ", resolver.Addr)
|
||||
}
|
||||
return transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, tlsConfig), nil
|
||||
httpsTransport := transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, tlsConfig)
|
||||
err = httpsTransport.Start(adapter.StartStateStart, resolverScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return httpsTransport, nil
|
||||
case "http":
|
||||
if serverAddr.Port == 0 {
|
||||
serverAddr.Port = 80
|
||||
}
|
||||
return transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, nil), nil
|
||||
httpTransport := transport.NewHTTPSRaw(t.TransportAdapter, t.logger, myDialer, serverURL, http.Header{}, serverAddr, nil)
|
||||
err := httpTransport.Start(adapter.StartStateStart, resolverScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return httpTransport, nil
|
||||
}
|
||||
}
|
||||
serverAddr := M.ParseSocksaddr(resolver.Addr)
|
||||
@@ -220,7 +252,12 @@ func (t *DNSTransport) createResolver(directDialer func() N.Dialer, resolver *dn
|
||||
if serverAddr.Port == 0 {
|
||||
serverAddr.Port = 53
|
||||
}
|
||||
return transport.NewUDPRaw(t.logger, t.TransportAdapter, myDialer, serverAddr), nil
|
||||
udpTransport := transport.NewUDPRaw(t.logger, t.TransportAdapter, myDialer, serverAddr)
|
||||
err := udpTransport.Start(adapter.StartStateStart, resolverScope)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return udpTransport, nil
|
||||
}
|
||||
|
||||
func buildRoutePrefixes(routeConfig *router.Config) []netip.Prefix {
|
||||
@@ -244,26 +281,6 @@ func buildRoutePrefixes(routeConfig *router.Config) []netip.Prefix {
|
||||
return ipSet.Prefixes()
|
||||
}
|
||||
|
||||
func (t *DNSTransport) Close() error {
|
||||
t.access.Lock()
|
||||
transports := t.collectResolversLocked()
|
||||
t.routePrefixes = nil
|
||||
t.routes = nil
|
||||
t.hosts = nil
|
||||
t.magicHosts = nil
|
||||
t.defaultResolvers = nil
|
||||
t.access.Unlock()
|
||||
|
||||
var err error
|
||||
for _, transport := range transports {
|
||||
name := "resolver/" + transport.Type() + "[" + transport.Tag() + "]"
|
||||
err = E.Append(err, transport.Close(), func(err error) error {
|
||||
return E.Cause(err, "close ", name)
|
||||
})
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *DNSTransport) Raw() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ import (
|
||||
tailscaleroot "github.com/sagernet/tailscale"
|
||||
_ "github.com/sagernet/tailscale/feature/relayserver"
|
||||
"github.com/sagernet/tailscale/ipn"
|
||||
"github.com/sagernet/tailscale/ipn/ipnlocal"
|
||||
tsDNS "github.com/sagernet/tailscale/net/dns"
|
||||
"github.com/sagernet/tailscale/net/netmon"
|
||||
"github.com/sagernet/tailscale/net/netns"
|
||||
@@ -93,7 +92,6 @@ type Endpoint struct {
|
||||
detour string
|
||||
server *tsnet.Server
|
||||
stack *stack.Stack
|
||||
icmpForwarder *tun.ICMPForwarder
|
||||
returnAccess sync.Mutex
|
||||
returnPath tun.Return
|
||||
wgEngine wgengine.ExportedUserspaceEngine
|
||||
@@ -122,17 +120,13 @@ type Endpoint struct {
|
||||
sshServerInstance *tailssh.Server
|
||||
sshServerOptions *option.TailscaleSSHServerOptions
|
||||
taildrop *taildropManager
|
||||
localBackend *ipnlocal.LocalBackend
|
||||
|
||||
systemInterface bool
|
||||
systemInterfaceName string
|
||||
systemInterfaceMTU uint32
|
||||
keyAuth bool
|
||||
serverStarted bool
|
||||
started atomic.Bool
|
||||
systemTun tun.Tun
|
||||
systemDialer *dialer.DefaultDialer
|
||||
fallbackTCPCloser func()
|
||||
}
|
||||
|
||||
func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TailscaleEndpointOptions) (adapter.Endpoint, error) {
|
||||
@@ -261,7 +255,7 @@ func (t *Endpoint) References() []string {
|
||||
return []string{t.detour}
|
||||
}
|
||||
|
||||
func (t *Endpoint) Start(stage adapter.StartStage) error {
|
||||
func (t *Endpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
mkdirErr := filemanager.MkdirAll(t.ctx, t.server.Dir, 0o700)
|
||||
@@ -276,14 +270,14 @@ func (t *Endpoint) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
t.server.PeerDNSQueryHandler = (*peerDNSQueryHandler)(t)
|
||||
case adapter.StartStateStart:
|
||||
return t.start()
|
||||
return t.start(scope)
|
||||
case adapter.StartStatePostStart:
|
||||
return t.postStart()
|
||||
return t.postStart(scope)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Endpoint) start() error {
|
||||
func (t *Endpoint) start(scope *adapter.Scope) error {
|
||||
if t.platformInterface != nil && t.platformInterface.UsePlatformNetworkInterfaces() {
|
||||
err := t.network.UpdateInterfaces()
|
||||
if err != nil {
|
||||
@@ -308,6 +302,10 @@ func (t *Endpoint) start() error {
|
||||
}
|
||||
}), nil
|
||||
})
|
||||
scope.Add(func() error {
|
||||
netmon.RegisterInterfaceGetter(nil)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
if t.systemInterface {
|
||||
mtu := t.systemInterfaceMTU
|
||||
@@ -333,14 +331,13 @@ func (t *Endpoint) start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(systemTun.Close)
|
||||
err = systemTun.Start()
|
||||
if err != nil {
|
||||
_ = systemTun.Close()
|
||||
return err
|
||||
}
|
||||
wgTunDevice, err := newTunDeviceAdapter(systemTun, int(mtu), t.logger)
|
||||
if err != nil {
|
||||
_ = systemTun.Close()
|
||||
return err
|
||||
}
|
||||
systemDialer, err := dialer.NewDefault(t.ctx, option.DialerOptions{
|
||||
@@ -349,15 +346,17 @@ func (t *Endpoint) start() error {
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
_ = systemTun.Close()
|
||||
return err
|
||||
}
|
||||
t.systemTun = systemTun
|
||||
t.systemDialer = systemDialer
|
||||
t.server.Tun = wgTunDevice
|
||||
}
|
||||
if t.network.AutoRedirectOutputMark() != 0 {
|
||||
netns.SetControlFunc(t.network.AutoRedirectOutputMarkFunc())
|
||||
scope.Add(func() error {
|
||||
netns.SetControlFunc(nil)
|
||||
return nil
|
||||
})
|
||||
} else if t.platformInterface != nil && t.platformInterface.UsePlatformNetworkInterfaces() {
|
||||
if t.platformInterface.UsePlatformAutoDetectInterfaceControl() {
|
||||
netns.SetControlFunc(func(network, address string, conn syscall.RawConn) error {
|
||||
@@ -365,6 +364,10 @@ func (t *Endpoint) start() error {
|
||||
return t.platformInterface.AutoDetectInterfaceControl(int(fileDescriptor))
|
||||
})
|
||||
})
|
||||
scope.Add(func() error {
|
||||
netns.SetControlFunc(nil)
|
||||
return nil
|
||||
})
|
||||
} else {
|
||||
// NEPacketTunnelProvider sockets are excluded from tunnel routes by
|
||||
// NECP; the empty override only suppresses tailscale's own
|
||||
@@ -372,12 +375,21 @@ func (t *Endpoint) start() error {
|
||||
netns.SetControlFunc(func(string, string, syscall.RawConn) error {
|
||||
return nil
|
||||
})
|
||||
scope.Add(func() error {
|
||||
netns.SetControlFunc(nil)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
} else {
|
||||
bindFunc := t.network.AutoDetectInterfaceFunc()
|
||||
if bindFunc != nil {
|
||||
netns.SetControlFunc(bindFunc)
|
||||
netns.SetListenPacketFunc(t.listenPacket)
|
||||
scope.Add(func() error {
|
||||
netns.SetControlFunc(nil)
|
||||
netns.SetListenPacketFunc(nil)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -408,29 +420,35 @@ func (t *Endpoint) listenPacket(ctx context.Context, network string, address str
|
||||
return tun.NewUDPEgressConn(udpConn, egressPool), nil
|
||||
}
|
||||
|
||||
func (t *Endpoint) postStart() error {
|
||||
func (t *Endpoint) postStart(scope *adapter.Scope) error {
|
||||
err := t.server.Start()
|
||||
if err != nil {
|
||||
if t.systemTun != nil {
|
||||
_ = t.systemTun.Close()
|
||||
}
|
||||
return err
|
||||
}
|
||||
t.serverStarted = true
|
||||
if t.fallbackTCPCloser == nil {
|
||||
t.fallbackTCPCloser = t.server.RegisterFallbackTCPHandler(func(src, dst netip.AddrPort) (handler func(net.Conn), intercept bool) {
|
||||
return func(conn net.Conn) {
|
||||
ctx := log.ContextWithNewID(t.ctx)
|
||||
source := M.SocksaddrFrom(src.Addr(), src.Port())
|
||||
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
|
||||
t.NewConnectionEx(ctx, conn, source, destination, nil)
|
||||
}, true
|
||||
})
|
||||
}
|
||||
scope.Add(t.server.Close)
|
||||
fallbackTCPCloser := t.server.RegisterFallbackTCPHandler(func(src, dst netip.AddrPort) (handler func(net.Conn), intercept bool) {
|
||||
return func(conn net.Conn) {
|
||||
ctx := log.ContextWithNewID(t.ctx)
|
||||
source := M.SocksaddrFrom(src.Addr(), src.Port())
|
||||
destination := M.SocksaddrFrom(dst.Addr(), dst.Port())
|
||||
t.NewConnectionEx(ctx, conn, source, destination, nil)
|
||||
}, true
|
||||
})
|
||||
scope.Add(func() error {
|
||||
fallbackTCPCloser()
|
||||
return nil
|
||||
})
|
||||
localBackend := t.server.ExportLocalBackend()
|
||||
t.localBackend = localBackend
|
||||
scope.Add(func() error {
|
||||
t.taildrop.close()
|
||||
return nil
|
||||
})
|
||||
if !version.IsAppleTV() {
|
||||
registerTaildropEndpoint(localBackend, t)
|
||||
scope.Add(func() error {
|
||||
unregisterTaildropEndpoint(localBackend)
|
||||
return nil
|
||||
})
|
||||
go t.taildrop.start()
|
||||
}
|
||||
wgEngine := localBackend.ExportEngine().(wgengine.ExportedUserspaceEngine)
|
||||
@@ -447,10 +465,10 @@ func (t *Endpoint) postStart() error {
|
||||
return gonet.TranslateNetstackError(gErr)
|
||||
}
|
||||
icmpForwarder := tun.NewICMPForwarder(ipStack, t, t.logger)
|
||||
scope.Add(icmpForwarder.Close)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber4, icmpForwarder.HandlePacket)
|
||||
ipStack.SetTransportProtocolHandler(icmp.ProtocolNumber6, icmpForwarder.HandlePacket)
|
||||
t.stack = ipStack
|
||||
t.icmpForwarder = icmpForwarder
|
||||
netstack := t.server.ExportNetstack()
|
||||
if netstack != nil {
|
||||
previousTCP := netstack.GetTCPHandlerForFlow
|
||||
@@ -510,15 +528,20 @@ func (t *Endpoint) postStart() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "start SSH server")
|
||||
}
|
||||
scope.Add(sshServer.Close)
|
||||
t.sshReconfigHook = sshServer.OnReconfig
|
||||
t.sshServerInstance = sshServer
|
||||
}
|
||||
go t.watchState()
|
||||
go t.watchState(scope.Context())
|
||||
t.started.Store(true)
|
||||
scope.Add(func() error {
|
||||
t.started.Store(false)
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Endpoint) watchState() {
|
||||
func (t *Endpoint) watchState(ctx context.Context) {
|
||||
localBackend := t.server.ExportLocalBackend()
|
||||
var reportedAuthURL string
|
||||
exitNodePending := t.exitNode != ""
|
||||
@@ -533,7 +556,7 @@ func (t *Endpoint) watchState() {
|
||||
}
|
||||
for {
|
||||
var busError string
|
||||
localBackend.WatchNotifications(t.ctx, ipn.NotifyInitialState|ipn.NotifyPeerPatches, nil, func(roNotify *ipn.Notify) (keepGoing bool) {
|
||||
localBackend.WatchNotifications(ctx, ipn.NotifyInitialState|ipn.NotifyPeerPatches, nil, func(roNotify *ipn.Notify) (keepGoing bool) {
|
||||
if roNotify.ErrMessage != nil {
|
||||
busError = *roNotify.ErrMessage
|
||||
return false
|
||||
@@ -578,7 +601,7 @@ func (t *Endpoint) watchState() {
|
||||
}
|
||||
return true
|
||||
})
|
||||
if t.ctx.Err() != nil {
|
||||
if ctx.Err() != nil {
|
||||
return
|
||||
}
|
||||
if busError != "" {
|
||||
@@ -587,7 +610,7 @@ func (t *Endpoint) watchState() {
|
||||
t.logger.Warn("state watcher stopped unexpectedly, restarting")
|
||||
}
|
||||
select {
|
||||
case <-t.ctx.Done():
|
||||
case <-ctx.Done():
|
||||
return
|
||||
case <-time.After(time.Second):
|
||||
}
|
||||
@@ -719,38 +742,6 @@ func (t *Endpoint) Logout(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Endpoint) Close() error {
|
||||
var err error
|
||||
t.started.Store(false)
|
||||
if t.localBackend != nil {
|
||||
unregisterTaildropEndpoint(t.localBackend)
|
||||
t.localBackend = nil
|
||||
}
|
||||
t.taildrop.close()
|
||||
if t.icmpForwarder != nil {
|
||||
t.icmpForwarder.Close()
|
||||
t.icmpForwarder = nil
|
||||
}
|
||||
common.Close(common.PtrOrNil(t.sshServerInstance))
|
||||
t.sshServerInstance = nil
|
||||
if t.serverStarted {
|
||||
err = common.Close(common.PtrOrNil(t.server))
|
||||
t.serverStarted = false
|
||||
}
|
||||
netmon.RegisterInterfaceGetter(nil)
|
||||
netns.SetControlFunc(nil)
|
||||
netns.SetListenPacketFunc(nil)
|
||||
if t.fallbackTCPCloser != nil {
|
||||
t.fallbackTCPCloser()
|
||||
t.fallbackTCPCloser = nil
|
||||
}
|
||||
if t.systemTun != nil {
|
||||
t.systemTun.Close()
|
||||
t.systemTun = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Endpoint) InterfaceUpdated(ctx context.Context) {
|
||||
if !t.started.Load() {
|
||||
return
|
||||
|
||||
+10
-22
@@ -40,7 +40,6 @@ type Outbound struct {
|
||||
startConf *tor.StartConf
|
||||
options map[string]string
|
||||
events chan control.Event
|
||||
instance *tor.Tor
|
||||
socksClient *socks.Client
|
||||
}
|
||||
|
||||
@@ -96,7 +95,7 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Outbound) Start(stage adapter.StartStage) error {
|
||||
func (t *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
if t.startConf.DataDir == "" {
|
||||
@@ -127,11 +126,8 @@ func (t *Outbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = t.start()
|
||||
if err != nil {
|
||||
t.Close()
|
||||
return err
|
||||
}
|
||||
scope.Add(proxy.Close)
|
||||
return t.start(scope)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -144,13 +140,17 @@ var torLogEvents = []control.EventCode{
|
||||
control.EventCodeLogWarn,
|
||||
}
|
||||
|
||||
func (t *Outbound) start() error {
|
||||
func (t *Outbound) start(scope *adapter.Scope) error {
|
||||
t.events = make(chan control.Event, 8)
|
||||
scope.Add(func() error {
|
||||
close(t.events)
|
||||
return nil
|
||||
})
|
||||
torInstance, err := tor.Start(t.ctx, t.startConf)
|
||||
if err != nil {
|
||||
return E.New(strings.ToLower(err.Error()))
|
||||
}
|
||||
t.instance = torInstance
|
||||
t.events = make(chan control.Event, 8)
|
||||
scope.Add(torInstance.Close)
|
||||
err = torInstance.Control.AddEventListener(t.events, torLogEvents...)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -225,18 +225,6 @@ func (t *Outbound) recvLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Outbound) Close() error {
|
||||
err := common.Close(
|
||||
common.PtrOrNil(t.proxy),
|
||||
common.PtrOrNil(t.instance),
|
||||
)
|
||||
if t.events != nil {
|
||||
close(t.events)
|
||||
t.events = nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (t *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
t.logger.InfoContext(ctx, "outbound connection to ", destination)
|
||||
return t.socksClient.DialContext(ctx, network, destination)
|
||||
|
||||
+10
-10
@@ -120,7 +120,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -129,10 +129,18 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "create TLS config")
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
if h.transport == nil {
|
||||
return h.listener.Start()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
scope.Add(h.transport.Close)
|
||||
scope.Add(h.listener.Close)
|
||||
if common.Contains(h.transport.Network(), N.NetworkTCP) {
|
||||
tcpListener, err := h.listener.ListenTCP()
|
||||
if err != nil {
|
||||
@@ -160,14 +168,6 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(
|
||||
h.listener,
|
||||
h.tlsConfig,
|
||||
h.transport,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
if h.tlsConfig != nil && h.transport == nil {
|
||||
tlsConn, err := tls.ServerHandshake(ctx, conn, h.tlsConfig)
|
||||
|
||||
@@ -150,8 +150,17 @@ func (h *Outbound) CloseIdleConnections() {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
if h.transport != nil {
|
||||
scope.Add(h.transport.Close)
|
||||
}
|
||||
if h.multiplexDialer != nil {
|
||||
scope.Add(h.multiplexDialer.Close)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type trojanDialer Outbound
|
||||
|
||||
@@ -153,7 +153,7 @@ func (h *Inbound) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
|
||||
h.router.RoutePacketConnectionEx(ctx, conn, metadata, onClose)
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -162,18 +162,17 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
packetConn, err := h.listener.ListenUDP()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return h.server.Start(packetConn)
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(
|
||||
h.listener,
|
||||
h.tlsConfig,
|
||||
common.PtrOrNil(h.server),
|
||||
)
|
||||
scope.Add(h.listener.Close)
|
||||
err = h.server.Start(packetConn)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.server.Close)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -161,6 +161,12 @@ func (h *Outbound) CloseIdleConnections() {
|
||||
h.client.CloseIdleConnections()
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return h.client.CloseWithError(os.ErrClosed)
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
scope.Add(func() error {
|
||||
return h.client.CloseWithError(os.ErrClosed)
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
+38
-38
@@ -25,7 +25,6 @@ import (
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/ranges"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
"go4.org/netipx"
|
||||
@@ -36,29 +35,27 @@ func RegisterInbound(registry *inbound.Registry) {
|
||||
}
|
||||
|
||||
type Inbound struct {
|
||||
tag string
|
||||
ctx context.Context
|
||||
router adapter.Router
|
||||
networkManager adapter.NetworkManager
|
||||
logger log.ContextLogger
|
||||
tunOptions tun.Options
|
||||
udpTimeout time.Duration
|
||||
udpMapping tun.NATMapping
|
||||
udpFiltering tun.NATFiltering
|
||||
udpNATMax uint32
|
||||
dnsHijackAddress []netip.Addr
|
||||
stack string
|
||||
tunIf tun.Tun
|
||||
tunStack tun.Stack
|
||||
platformInterface adapter.PlatformInterface
|
||||
platformOptions option.TunPlatformOptions
|
||||
autoRedirect tun.AutoRedirect
|
||||
routeRuleSet []adapter.RuleSet
|
||||
routeRuleSetCallback []*list.Element[adapter.RuleSetUpdateCallback]
|
||||
routeExcludeRuleSet []adapter.RuleSet
|
||||
routeExcludeRuleSetCallback []*list.Element[adapter.RuleSetUpdateCallback]
|
||||
routeAddressSet []*netipx.IPSet
|
||||
routeExcludeAddressSet []*netipx.IPSet
|
||||
tag string
|
||||
ctx context.Context
|
||||
router adapter.Router
|
||||
networkManager adapter.NetworkManager
|
||||
logger log.ContextLogger
|
||||
tunOptions tun.Options
|
||||
udpTimeout time.Duration
|
||||
udpMapping tun.NATMapping
|
||||
udpFiltering tun.NATFiltering
|
||||
udpNATMax uint32
|
||||
dnsHijackAddress []netip.Addr
|
||||
stack string
|
||||
tunIf tun.Tun
|
||||
tunStack tun.Stack
|
||||
platformInterface adapter.PlatformInterface
|
||||
platformOptions option.TunPlatformOptions
|
||||
autoRedirect tun.AutoRedirect
|
||||
routeRuleSet []adapter.RuleSet
|
||||
routeExcludeRuleSet []adapter.RuleSet
|
||||
routeAddressSet []*netipx.IPSet
|
||||
routeExcludeAddressSet []*netipx.IPSet
|
||||
}
|
||||
|
||||
func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TunInboundOptions) (adapter.Inbound, error) {
|
||||
@@ -328,9 +325,12 @@ func (t *Inbound) Tag() string {
|
||||
return t.tag
|
||||
}
|
||||
|
||||
func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (t *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
if t.autoRedirect != nil {
|
||||
scope.Add(t.autoRedirect.Close)
|
||||
}
|
||||
if t.tunOptions.DNSModeOrDefault() != tun.DNSModeDisabled && len(t.tunOptions.DNSAddress) == 0 {
|
||||
inet4DNSAddress, _ := t.tunOptions.Inet4DNSAddress()
|
||||
inet6DNSAddress, _ := t.tunOptions.Inet6DNSAddress()
|
||||
@@ -383,7 +383,11 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
routeRuleSet.IncRef()
|
||||
t.routeAddressSet = append(t.routeAddressSet, ipSets...)
|
||||
if t.autoRedirect != nil {
|
||||
t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
||||
callback := routeRuleSet.RegisterCallback(t.updateRouteAddressSet)
|
||||
scope.Add(func() error {
|
||||
routeRuleSet.UnregisterCallback(callback)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
|
||||
@@ -394,7 +398,11 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
routeExcludeRuleSet.IncRef()
|
||||
t.routeExcludeAddressSet = append(t.routeExcludeAddressSet, ipSets...)
|
||||
if t.autoRedirect != nil {
|
||||
t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
||||
callback := routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet)
|
||||
scope.Add(func() error {
|
||||
routeExcludeRuleSet.UnregisterCallback(callback)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -435,14 +443,13 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "configure tun interface")
|
||||
}
|
||||
scope.Add(tunInterface.Close)
|
||||
t.logger.Trace("creating stack")
|
||||
t.tunIf = tunInterface
|
||||
if t.platformInterface != nil {
|
||||
err = t.platformInterface.ProcessPlatformOptions(t.platformOptions)
|
||||
if err != nil {
|
||||
closeError := t.tunIf.Close()
|
||||
t.tunIf = nil
|
||||
return E.Errors(E.Cause(err, "process platform options"), closeError)
|
||||
return E.Cause(err, "process platform options")
|
||||
}
|
||||
}
|
||||
var includeAllNetworks bool
|
||||
@@ -467,6 +474,7 @@ func (t *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(tunStack.Close)
|
||||
t.tunStack = tunStack
|
||||
t.logger.Info("started at ", t.tunOptions.Name)
|
||||
case adapter.StartStatePostStart:
|
||||
@@ -512,14 +520,6 @@ func (t *Inbound) InterfaceUpdated(ctx context.Context) {
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Inbound) Close() error {
|
||||
return common.Close(
|
||||
t.tunStack,
|
||||
t.tunIf,
|
||||
t.autoRedirect,
|
||||
)
|
||||
}
|
||||
|
||||
func (t *Inbound) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
if slices.Contains(t.dnsHijackAddress, destination.Addr()) {
|
||||
if network == uint8(header.UDPProtocolNumber) {
|
||||
|
||||
+10
-11
@@ -102,7 +102,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -111,10 +111,18 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
if h.transport == nil {
|
||||
return h.listener.Start()
|
||||
err := h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
scope.Add(h.transport.Close)
|
||||
scope.Add(h.listener.Close)
|
||||
if common.Contains(h.transport.Network(), N.NetworkTCP) {
|
||||
tcpListener, err := h.listener.ListenTCP()
|
||||
if err != nil {
|
||||
@@ -142,15 +150,6 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(
|
||||
h.service,
|
||||
h.listener,
|
||||
h.tlsConfig,
|
||||
h.transport,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
if h.tlsConfig != nil && h.transport == nil {
|
||||
tlsConn, err := tls.ServerHandshake(ctx, conn, h.tlsConfig)
|
||||
|
||||
@@ -170,8 +170,17 @@ func (h *Outbound) CloseIdleConnections() {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
if h.transport != nil {
|
||||
scope.Add(h.transport.Close)
|
||||
}
|
||||
if h.multiplexDialer != nil {
|
||||
scope.Add(h.multiplexDialer.Close)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type vlessDialer Outbound
|
||||
|
||||
+11
-11
@@ -100,7 +100,7 @@ func NewInbound(ctx context.Context, router adapter.Router, logger log.ContextLo
|
||||
return inbound, nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
func (h *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
@@ -108,15 +108,24 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.service.Close)
|
||||
if h.tlsConfig != nil {
|
||||
err = h.tlsConfig.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.tlsConfig.Close)
|
||||
}
|
||||
if h.transport == nil {
|
||||
return h.listener.Start()
|
||||
err = h.listener.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(h.listener.Close)
|
||||
return nil
|
||||
}
|
||||
scope.Add(h.transport.Close)
|
||||
scope.Add(h.listener.Close)
|
||||
if common.Contains(h.transport.Network(), N.NetworkTCP) {
|
||||
tcpListener, err := h.listener.ListenTCP()
|
||||
if err != nil {
|
||||
@@ -144,15 +153,6 @@ func (h *Inbound) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Inbound) Close() error {
|
||||
return common.Close(
|
||||
h.service,
|
||||
h.listener,
|
||||
h.tlsConfig,
|
||||
h.transport,
|
||||
)
|
||||
}
|
||||
|
||||
func (h *Inbound) NewConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
if h.tlsConfig != nil && h.transport == nil {
|
||||
tlsConn, err := tls.ServerHandshake(ctx, conn, h.tlsConfig)
|
||||
|
||||
@@ -148,8 +148,17 @@ func (h *Outbound) CloseIdleConnections() {
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return common.Close(common.PtrOrNil(h.multiplexDialer), h.transport)
|
||||
func (h *Outbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
if h.transport != nil {
|
||||
scope.Add(h.transport.Close)
|
||||
}
|
||||
if h.multiplexDialer != nil {
|
||||
scope.Add(h.multiplexDialer.Close)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *Outbound) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
|
||||
|
||||
@@ -134,8 +134,10 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
return ep, nil
|
||||
}
|
||||
|
||||
func (w *Endpoint) Start(stage adapter.StartStage) error {
|
||||
func (w *Endpoint) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
scope.Add(w.endpoint.Close)
|
||||
case adapter.StartStateStart:
|
||||
return w.endpoint.Start(false)
|
||||
case adapter.StartStatePostStart:
|
||||
@@ -144,17 +146,16 @@ func (w *Endpoint) Start(stage adapter.StartStage) error {
|
||||
return err
|
||||
}
|
||||
w.started.Store(true)
|
||||
scope.Add(func() error {
|
||||
w.bindAccess.Lock()
|
||||
w.started.Store(false)
|
||||
w.bindAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *Endpoint) Close() error {
|
||||
w.bindAccess.Lock()
|
||||
w.started.Store(false)
|
||||
w.bindAccess.Unlock()
|
||||
return w.endpoint.Close()
|
||||
}
|
||||
|
||||
func (w *Endpoint) InterfaceUpdated(ctx context.Context) {
|
||||
if !w.started.Load() {
|
||||
return
|
||||
|
||||
+8
-6
@@ -42,7 +42,14 @@ func NewConnectionManager(logger logger.ContextLogger) *ConnectionManager {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ConnectionManager) Start(stage adapter.StartStage) error {
|
||||
func (m *ConnectionManager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
scope.Add(func() error {
|
||||
m.CloseAll()
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -65,11 +72,6 @@ func (m *ConnectionManager) CloseAll() {
|
||||
}
|
||||
}
|
||||
|
||||
func (m *ConnectionManager) Close() error {
|
||||
m.CloseAll()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ConnectionManager) TrackConn(conn net.Conn) net.Conn {
|
||||
m.access.Lock()
|
||||
element := m.connections.PushBack(conn)
|
||||
|
||||
+25
-63
@@ -25,7 +25,6 @@ import (
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
"github.com/sagernet/sing/common/winpowrprof"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
"github.com/sagernet/sing/service"
|
||||
"github.com/sagernet/sing/service/pause"
|
||||
|
||||
@@ -61,8 +60,6 @@ type NetworkManager struct {
|
||||
environmentUpdateAccess sync.Mutex
|
||||
environmentUpdateTimer *time.Timer
|
||||
startedCtx context.Context
|
||||
startedCancel context.CancelFunc
|
||||
interfaceUpdateElement *list.Element[tun.DefaultInterfaceUpdateCallback]
|
||||
interfaceUpdateAccess sync.Mutex
|
||||
interfaceUpdateCancel context.CancelFunc
|
||||
networkResetPending bool
|
||||
@@ -146,11 +143,19 @@ func NewNetworkManager(ctx context.Context, logger logger.ContextLogger, options
|
||||
return nm, nil
|
||||
}
|
||||
|
||||
func (r *NetworkManager) Start(stage adapter.StartStage) error {
|
||||
func (r *NetworkManager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
monitor := taskmonitor.New(r.logger, C.StartTimeout)
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
r.router = service.FromContext[adapter.Router](r.ctx)
|
||||
scope.Add(func() error {
|
||||
r.environmentUpdateAccess.Lock()
|
||||
if r.environmentUpdateTimer != nil {
|
||||
r.environmentUpdateTimer.Stop()
|
||||
}
|
||||
r.environmentUpdateAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
if r.networkMonitor != nil {
|
||||
monitor.Start("initialize network monitor")
|
||||
err := r.networkMonitor.Start()
|
||||
@@ -158,6 +163,7 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
scope.Add(r.networkMonitor.Close)
|
||||
}
|
||||
if r.interfaceMonitor != nil {
|
||||
monitor.Start("initialize interface monitor")
|
||||
@@ -166,7 +172,12 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
r.interfaceUpdateElement = r.interfaceMonitor.RegisterCallback(r.notifyInterfaceUpdate)
|
||||
scope.Add(r.interfaceMonitor.Close)
|
||||
interfaceUpdateElement := r.interfaceMonitor.RegisterCallback(r.notifyInterfaceUpdate)
|
||||
scope.Add(func() error {
|
||||
r.interfaceMonitor.UnregisterCallback(interfaceUpdateElement)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
case adapter.StartStateStart:
|
||||
if C.IsAndroid && r.platformInterface == nil {
|
||||
@@ -186,6 +197,7 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
|
||||
r.logger.Warn("initialize package manager: ", err)
|
||||
} else {
|
||||
r.packageManager = packageManager
|
||||
scope.Add(packageManager.Close)
|
||||
}
|
||||
}
|
||||
case adapter.StartStatePostStart:
|
||||
@@ -197,14 +209,20 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
} else {
|
||||
r.wifiMonitor = wifiMonitor
|
||||
scope.Add(wifiMonitor.Close)
|
||||
err = r.wifiMonitor.Start()
|
||||
if err != nil {
|
||||
r.logger.Warn(E.Cause(err, "start WIFI monitor"))
|
||||
}
|
||||
}
|
||||
}
|
||||
scope.Add(func() error {
|
||||
r.resetRunAccess.Lock()
|
||||
defer r.resetRunAccess.Unlock()
|
||||
return nil
|
||||
})
|
||||
r.interfaceUpdateAccess.Lock()
|
||||
r.startedCtx, r.startedCancel = context.WithCancel(r.ctx)
|
||||
r.startedCtx = scope.Context()
|
||||
if r.interfaceMonitor != nil {
|
||||
r.dispatchInterfaceUpdateLocked()
|
||||
}
|
||||
@@ -224,6 +242,7 @@ func (r *NetworkManager) Start(stage adapter.StartStage) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "start power listener")
|
||||
}
|
||||
scope.Add(r.powerListener.Close)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
@@ -239,63 +258,6 @@ func (r *NetworkManager) Initialize(ruleSets []adapter.RuleSet) {
|
||||
}
|
||||
}
|
||||
|
||||
func (r *NetworkManager) Close() error {
|
||||
monitor := taskmonitor.New(r.logger, C.StopTimeout)
|
||||
var err error
|
||||
if r.interfaceUpdateElement != nil {
|
||||
r.interfaceMonitor.UnregisterCallback(r.interfaceUpdateElement)
|
||||
r.interfaceUpdateElement = nil
|
||||
}
|
||||
if r.powerListener != nil {
|
||||
monitor.Start("close power listener")
|
||||
err = E.Append(err, r.powerListener.Close(), func(err error) error {
|
||||
return E.Cause(err, "close power listener")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
if r.startedCancel != nil {
|
||||
r.startedCancel()
|
||||
monitor.Start("wait network reset")
|
||||
r.resetRunAccess.Lock()
|
||||
monitor.Finish()
|
||||
defer r.resetRunAccess.Unlock()
|
||||
}
|
||||
if r.packageManager != nil {
|
||||
monitor.Start("close package manager")
|
||||
err = E.Append(err, r.packageManager.Close(), func(err error) error {
|
||||
return E.Cause(err, "close package manager")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
if r.interfaceMonitor != nil {
|
||||
monitor.Start("close interface monitor")
|
||||
err = E.Append(err, r.interfaceMonitor.Close(), func(err error) error {
|
||||
return E.Cause(err, "close interface monitor")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
if r.networkMonitor != nil {
|
||||
monitor.Start("close network monitor")
|
||||
err = E.Append(err, r.networkMonitor.Close(), func(err error) error {
|
||||
return E.Cause(err, "close network monitor")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
r.environmentUpdateAccess.Lock()
|
||||
if r.environmentUpdateTimer != nil {
|
||||
r.environmentUpdateTimer.Stop()
|
||||
}
|
||||
r.environmentUpdateAccess.Unlock()
|
||||
if r.wifiMonitor != nil {
|
||||
monitor.Start("close WIFI monitor")
|
||||
err = E.Append(err, r.wifiMonitor.Close(), func(err error) error {
|
||||
return E.Cause(err, "close WIFI monitor")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *NetworkManager) InterfaceFinder() control.InterfaceFinder {
|
||||
return r.interfaceFinder
|
||||
}
|
||||
|
||||
+2
-8
@@ -77,11 +77,12 @@ func (m *ReferenceManager) Name() string {
|
||||
return "reference manager"
|
||||
}
|
||||
|
||||
func (m *ReferenceManager) Start(stage adapter.StartStage) error {
|
||||
func (m *ReferenceManager) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if stage != adapter.StartStateStarted {
|
||||
return nil
|
||||
}
|
||||
m.subscriber = observable.NewSubscriber[struct{}](1)
|
||||
scope.Add(m.subscriber.Close)
|
||||
history := service.PtrFromContext[urltest.HistoryStorage](m.ctx)
|
||||
if history != nil {
|
||||
history.AddUpdateHook(m.subscriber)
|
||||
@@ -95,13 +96,6 @@ func (m *ReferenceManager) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ReferenceManager) Close() error {
|
||||
if m.subscriber != nil {
|
||||
m.subscriber.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *ReferenceManager) loop() {
|
||||
subscription, done := m.subscriber.Subscription()
|
||||
for {
|
||||
|
||||
+11
-44
@@ -47,7 +47,6 @@ type Router struct {
|
||||
pauseManager pause.Manager
|
||||
trackers []adapter.ConnectionTracker
|
||||
platformInterface adapter.PlatformInterface
|
||||
started bool
|
||||
}
|
||||
|
||||
func NewRouter(ctx context.Context, logFactory log.Factory, options option.RouteOptions, dnsOptions option.DNSOptions) *Router {
|
||||
@@ -99,10 +98,13 @@ func (r *Router) Initialize(rules []option.Rule, ruleSets []option.RuleSet) erro
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Start(stage adapter.StartStage) error {
|
||||
func (r *Router) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
monitor := taskmonitor.New(r.logger, C.StartTimeout)
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
for _, ruleSet := range r.ruleSets {
|
||||
scope.Add(ruleSet.Close)
|
||||
}
|
||||
if r.needFindNeighbor {
|
||||
if r.platformInterface != nil && r.platformInterface.UsePlatformNeighborResolver() {
|
||||
monitor.Start("initialize neighbor resolver")
|
||||
@@ -113,6 +115,7 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
r.logger.Error(E.Cause(err, "start neighbor resolver"))
|
||||
} else {
|
||||
r.neighborResolver = resolver
|
||||
scope.Add(resolver.Close)
|
||||
}
|
||||
} else {
|
||||
monitor.Start("initialize neighbor resolver")
|
||||
@@ -128,6 +131,7 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
r.logger.Error(E.Cause(err, "start neighbor resolver"))
|
||||
} else {
|
||||
r.neighborResolver = resolver
|
||||
scope.Add(resolver.Close)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -160,6 +164,9 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
startContext.Close()
|
||||
}
|
||||
r.ruleSetUpdater = R.NewRuleSetUpdater(r.ctx, r.ruleSets)
|
||||
if r.ruleSetUpdater != nil {
|
||||
scope.Add(r.ruleSetUpdater.Close)
|
||||
}
|
||||
r.network.Initialize(r.ruleSets)
|
||||
needFindProcess := r.needFindProcess
|
||||
for _, ruleSet := range r.ruleSets {
|
||||
@@ -192,12 +199,14 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
}
|
||||
}
|
||||
if r.processSearcher != nil {
|
||||
scope.Add(r.processSearcher.Close)
|
||||
processCache := common.Must1(freelru.New[processCacheKey, processCacheEntry](256, maphash.NewHasher[processCacheKey]().Hash32, true))
|
||||
processCache.SetLifetime(200 * time.Millisecond)
|
||||
r.processCache = processCache
|
||||
}
|
||||
case adapter.StartStatePostStart:
|
||||
for i, rule := range r.rules {
|
||||
scope.Add(rule.Close)
|
||||
monitor.Start("initialize rule[", i, "]")
|
||||
err := rule.Start()
|
||||
monitor.Finish()
|
||||
@@ -208,7 +217,6 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
if r.ruleSetUpdater != nil {
|
||||
r.ruleSetUpdater.Start()
|
||||
}
|
||||
r.started = true
|
||||
return nil
|
||||
case adapter.StartStateStarted:
|
||||
for _, ruleSet := range r.ruleSets {
|
||||
@@ -219,47 +227,6 @@ func (r *Router) Start(stage adapter.StartStage) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Close() error {
|
||||
monitor := taskmonitor.New(r.logger, C.StopTimeout)
|
||||
var err error
|
||||
if r.neighborResolver != nil {
|
||||
monitor.Start("close neighbor resolver")
|
||||
err = E.Append(err, r.neighborResolver.Close(), func(closeErr error) error {
|
||||
return E.Cause(closeErr, "close neighbor resolver")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
for i, rule := range r.rules {
|
||||
monitor.Start("close rule[", i, "]")
|
||||
err = E.Append(err, rule.Close(), func(err error) error {
|
||||
return E.Cause(err, "close rule[", i, "]")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
if r.ruleSetUpdater != nil {
|
||||
monitor.Start("close rule-set updater")
|
||||
err = E.Append(err, r.ruleSetUpdater.Close(), func(err error) error {
|
||||
return E.Cause(err, "close rule-set updater")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
for i, ruleSet := range r.ruleSets {
|
||||
monitor.Start("close rule-set[", i, "]")
|
||||
err = E.Append(err, ruleSet.Close(), func(err error) error {
|
||||
return E.Cause(err, "close rule-set[", i, "]")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
if r.processSearcher != nil {
|
||||
monitor.Start("close process searcher")
|
||||
err = E.Append(err, r.processSearcher.Close(), func(err error) error {
|
||||
return E.Cause(err, "close process searcher")
|
||||
})
|
||||
monitor.Finish()
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Router) RuleSet(tag string) (adapter.RuleSet, bool) {
|
||||
ruleSet, loaded := r.ruleSetMap[tag]
|
||||
return ruleSet, loaded
|
||||
|
||||
@@ -18,8 +18,7 @@ type ruleSetItemTestRouter struct {
|
||||
ruleSets map[string]adapter.RuleSet
|
||||
}
|
||||
|
||||
func (r *ruleSetItemTestRouter) Start(adapter.StartStage) error { return nil }
|
||||
func (r *ruleSetItemTestRouter) Close() error { return nil }
|
||||
func (r *ruleSetItemTestRouter) Start(adapter.StartStage, *adapter.Scope) error { return nil }
|
||||
func (r *ruleSetItemTestRouter) PreMatch(adapter.InboundContext, []byte) adapter.PreMatchResult {
|
||||
return adapter.PreMatchResult{}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user