mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-05-14 00:51:12 +03:00
Add MTProxy, MASQUE, VPN, Link parser. Update AmneziaWG. Remove Tunneling
This commit is contained in:
@@ -3,6 +3,7 @@ package group
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"regexp"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
@@ -42,11 +43,20 @@ type Selector struct {
|
||||
selected common.TypedValue[adapter.Outbound]
|
||||
interruptGroup *interrupt.Group
|
||||
interruptExternalConnections bool
|
||||
|
||||
provider adapter.ProviderManager
|
||||
providers map[string]adapter.Provider
|
||||
outboundsCache map[string][]adapter.Outbound
|
||||
|
||||
providerTags []string
|
||||
exclude *regexp.Regexp
|
||||
include *regexp.Regexp
|
||||
useAllProviders bool
|
||||
}
|
||||
|
||||
func NewSelector(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.SelectorOutboundOptions) (adapter.Outbound, error) {
|
||||
outbound := &Selector{
|
||||
Adapter: outbound.NewAdapter(C.TypeSelector, tag, nil, options.Outbounds),
|
||||
Adapter: outbound.NewAdapter(C.TypeSelector, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.Outbounds),
|
||||
ctx: ctx,
|
||||
outbound: service.FromContext[adapter.OutboundManager](ctx),
|
||||
connection: service.FromContext[adapter.ConnectionManager](ctx),
|
||||
@@ -56,9 +66,15 @@ func NewSelector(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
outbounds: make(map[string]adapter.Outbound),
|
||||
interruptGroup: interrupt.NewGroup(),
|
||||
interruptExternalConnections: options.InterruptExistConnections,
|
||||
}
|
||||
if len(outbound.tags) == 0 {
|
||||
return nil, E.New("missing tags")
|
||||
|
||||
provider: service.FromContext[adapter.ProviderManager](ctx),
|
||||
providers: make(map[string]adapter.Provider),
|
||||
outboundsCache: make(map[string][]adapter.Outbound),
|
||||
|
||||
providerTags: options.Providers,
|
||||
exclude: (*regexp.Regexp)(options.Exclude),
|
||||
include: (*regexp.Regexp)(options.Include),
|
||||
useAllProviders: options.UseAllProviders,
|
||||
}
|
||||
return outbound, nil
|
||||
}
|
||||
@@ -72,6 +88,28 @@ func (s *Selector) Network() []string {
|
||||
}
|
||||
|
||||
func (s *Selector) Start() error {
|
||||
if s.useAllProviders {
|
||||
var providerTags []string
|
||||
for _, provider := range s.provider.Providers() {
|
||||
providerTags = append(providerTags, provider.Tag())
|
||||
s.providers[provider.Tag()] = provider
|
||||
provider.RegisterCallback(s.onProviderUpdated)
|
||||
}
|
||||
s.providerTags = providerTags
|
||||
} else {
|
||||
for i, tag := range s.providerTags {
|
||||
provider, loaded := s.provider.Get(tag)
|
||||
if !loaded {
|
||||
return E.New("outbound provider ", i, " not found: ", tag)
|
||||
}
|
||||
s.providers[tag] = provider
|
||||
provider.RegisterCallback(s.onProviderUpdated)
|
||||
}
|
||||
}
|
||||
if len(s.tags)+len(s.providerTags) == 0 {
|
||||
return E.New("missing outbound and provider tags")
|
||||
}
|
||||
|
||||
for i, tag := range s.tags {
|
||||
detour, loaded := s.outbound.Outbound(tag)
|
||||
if !loaded {
|
||||
@@ -79,31 +117,16 @@ func (s *Selector) Start() error {
|
||||
}
|
||||
s.outbounds[tag] = detour
|
||||
}
|
||||
|
||||
if s.Tag() != "" {
|
||||
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
|
||||
if cacheFile != nil {
|
||||
selected := cacheFile.LoadSelected(s.Tag())
|
||||
if selected != "" {
|
||||
detour, loaded := s.outbounds[selected]
|
||||
if loaded {
|
||||
s.selected.Store(detour)
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(s.tags) == 0 {
|
||||
detour, _ := s.outbound.Outbound("Compatible")
|
||||
s.tags = append(s.tags, detour.Tag())
|
||||
s.outbounds[detour.Tag()] = detour
|
||||
}
|
||||
|
||||
if s.defaultTag != "" {
|
||||
detour, loaded := s.outbounds[s.defaultTag]
|
||||
if !loaded {
|
||||
return E.New("default outbound not found: ", s.defaultTag)
|
||||
}
|
||||
s.selected.Store(detour)
|
||||
return nil
|
||||
outbound, err := s.outboundSelect()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
s.selected.Store(s.outbounds[s.tags[0]])
|
||||
s.selected.Store(outbound)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -145,7 +168,7 @@ func (s *Selector) DialContext(ctx context.Context, network string, destination
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.interruptGroup.NewConn(conn, interrupt.IsExternalConnectionFromContext(ctx)), nil
|
||||
return s.interruptGroup.NewConn(conn, interrupt.IsExternalConnectionFromContext(ctx), interrupt.IsProviderConnectionFromContext(ctx)), nil
|
||||
}
|
||||
|
||||
func (s *Selector) ListenPacket(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
|
||||
@@ -153,13 +176,13 @@ func (s *Selector) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.interruptGroup.NewPacketConn(conn, interrupt.IsExternalConnectionFromContext(ctx)), nil
|
||||
return s.interruptGroup.NewPacketConn(conn, interrupt.IsExternalConnectionFromContext(ctx), interrupt.IsProviderConnectionFromContext(ctx)), nil
|
||||
}
|
||||
|
||||
func (s *Selector) NewConnectionEx(ctx context.Context, conn net.Conn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
ctx = interrupt.ContextWithIsExternalConnection(ctx)
|
||||
selected := s.selected.Load()
|
||||
conn = s.interruptGroup.NewConn(conn, interrupt.IsExternalConnectionFromContext(ctx))
|
||||
conn = s.interruptGroup.NewConn(conn, interrupt.IsExternalConnectionFromContext(ctx), interrupt.IsProviderConnectionFromContext(ctx))
|
||||
if outboundHandler, isHandler := selected.(adapter.ConnectionHandlerEx); isHandler {
|
||||
outboundHandler.NewConnectionEx(ctx, conn, metadata, onClose)
|
||||
} else {
|
||||
@@ -170,7 +193,7 @@ func (s *Selector) NewConnectionEx(ctx context.Context, conn net.Conn, metadata
|
||||
func (s *Selector) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext, onClose N.CloseHandlerFunc) {
|
||||
ctx = interrupt.ContextWithIsExternalConnection(ctx)
|
||||
selected := s.selected.Load()
|
||||
conn = s.interruptGroup.NewSingPacketConn(conn, interrupt.IsExternalConnectionFromContext(ctx))
|
||||
conn = s.interruptGroup.NewSingPacketConn(conn, interrupt.IsExternalConnectionFromContext(ctx), interrupt.IsProviderConnectionFromContext(ctx))
|
||||
if outboundHandler, isHandler := selected.(adapter.PacketConnectionHandlerEx); isHandler {
|
||||
outboundHandler.NewPacketConnectionEx(ctx, conn, metadata, onClose)
|
||||
} else {
|
||||
@@ -192,3 +215,77 @@ func RealTag(detour adapter.Outbound) string {
|
||||
}
|
||||
return detour.Tag()
|
||||
}
|
||||
|
||||
func (s *Selector) onProviderUpdated(tag string) error {
|
||||
_, loaded := s.providers[tag]
|
||||
if !loaded {
|
||||
return E.New(s.Tag(), ": ", "outbound provider not found: ", tag)
|
||||
}
|
||||
var (
|
||||
tags = s.Dependencies()
|
||||
outboundByTag = make(map[string]adapter.Outbound)
|
||||
)
|
||||
for _, tag := range tags {
|
||||
outboundByTag[tag] = s.outbounds[tag]
|
||||
}
|
||||
for _, providerTag := range s.providerTags {
|
||||
if providerTag != tag && s.outboundsCache[providerTag] != nil {
|
||||
for _, detour := range s.outboundsCache[providerTag] {
|
||||
tags = append(tags, detour.Tag())
|
||||
outboundByTag[detour.Tag()] = detour
|
||||
}
|
||||
continue
|
||||
}
|
||||
provider := s.providers[providerTag]
|
||||
var cache []adapter.Outbound
|
||||
for _, detour := range provider.Outbounds() {
|
||||
tag := detour.Tag()
|
||||
if s.exclude != nil && s.exclude.MatchString(tag) {
|
||||
continue
|
||||
}
|
||||
if s.include != nil && !s.include.MatchString(tag) {
|
||||
continue
|
||||
}
|
||||
tags = append(tags, tag)
|
||||
cache = append(cache, detour)
|
||||
outboundByTag[tag] = detour
|
||||
}
|
||||
s.outboundsCache[providerTag] = cache
|
||||
}
|
||||
if len(tags) == 0 {
|
||||
detour, _ := s.outbound.Outbound("Compatible")
|
||||
tags = append(tags, detour.Tag())
|
||||
outboundByTag[detour.Tag()] = detour
|
||||
}
|
||||
s.tags, s.outbounds = tags, outboundByTag
|
||||
detour, _ := s.outboundSelect()
|
||||
if s.selected.Swap(detour) != detour {
|
||||
s.interruptGroup.Interrupt(s.interruptExternalConnections)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Selector) outboundSelect() (adapter.Outbound, error) {
|
||||
if s.Tag() != "" {
|
||||
cacheFile := service.FromContext[adapter.CacheFile](s.ctx)
|
||||
if cacheFile != nil {
|
||||
selected := cacheFile.LoadSelected(s.Tag())
|
||||
if selected != "" {
|
||||
detour, loaded := s.outbounds[selected]
|
||||
if loaded {
|
||||
return detour, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if s.defaultTag != "" {
|
||||
detour, loaded := s.outbounds[s.defaultTag]
|
||||
if !loaded {
|
||||
return nil, E.New("default outbound not found: ", s.defaultTag)
|
||||
}
|
||||
return detour, nil
|
||||
}
|
||||
|
||||
return s.outbounds[s.tags[0]], nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user