mirror of
https://github.com/SagerNet/sing-box.git
synced 2025-06-13 21:54:13 +08:00
test
This commit is contained in:
parent
c646fd6b2c
commit
307968bc2a
@ -10,15 +10,18 @@ import (
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common/control"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
"github.com/sagernet/sing/service"
|
||||
|
||||
mdns "github.com/miekg/dns"
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
type Router interface {
|
||||
Service
|
||||
PreStarter
|
||||
PostStarter
|
||||
Cleanup() error
|
||||
|
||||
Outbounds() []Outbound
|
||||
Outbound(tag string) (Outbound, bool)
|
||||
@ -92,12 +95,21 @@ type DNSRule interface {
|
||||
}
|
||||
|
||||
type RuleSet interface {
|
||||
Name() string
|
||||
StartContext(ctx context.Context, startContext RuleSetStartContext) error
|
||||
Metadata() RuleSetMetadata
|
||||
ExtractIPSet() []*netipx.IPSet
|
||||
IncRef()
|
||||
DecRef()
|
||||
Cleanup()
|
||||
RegisterCallback(callback RuleSetUpdateCallback) *list.Element[RuleSetUpdateCallback]
|
||||
UnregisterCallback(element *list.Element[RuleSetUpdateCallback])
|
||||
Close() error
|
||||
HeadlessRule
|
||||
}
|
||||
|
||||
type RuleSetUpdateCallback func(it RuleSet)
|
||||
|
||||
type RuleSetMetadata struct {
|
||||
ContainsProcessRule bool
|
||||
ContainsWIFIRule bool
|
||||
|
28
box.go
28
box.go
@ -303,7 +303,11 @@ func (s *Box) start() error {
|
||||
return E.Cause(err, "initialize inbound/", in.Type(), "[", tag, "]")
|
||||
}
|
||||
}
|
||||
return s.postStart()
|
||||
err = s.postStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return s.router.Cleanup()
|
||||
}
|
||||
|
||||
func (s *Box) postStart() error {
|
||||
@ -313,16 +317,28 @@ func (s *Box) postStart() error {
|
||||
return E.Cause(err, "start ", serviceName)
|
||||
}
|
||||
}
|
||||
for _, outbound := range s.outbounds {
|
||||
if lateOutbound, isLateOutbound := outbound.(adapter.PostStarter); isLateOutbound {
|
||||
// TODO: reorganize ALL start order
|
||||
for _, out := range s.outbounds {
|
||||
if lateOutbound, isLateOutbound := out.(adapter.PostStarter); isLateOutbound {
|
||||
err := lateOutbound.PostStart()
|
||||
if err != nil {
|
||||
return E.Cause(err, "post-start outbound/", outbound.Tag())
|
||||
return E.Cause(err, "post-start outbound/", out.Tag())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return s.router.PostStart()
|
||||
err := s.router.PostStart()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, in := range s.inbounds {
|
||||
if lateInbound, isLateInbound := in.(adapter.PostStarter); isLateInbound {
|
||||
err = lateInbound.PostStart()
|
||||
if err != nil {
|
||||
return E.Cause(err, "post-start inbound/", in.Tag())
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Box) Close() error {
|
||||
|
4
go.mod
4
go.mod
@ -33,7 +33,7 @@ require (
|
||||
github.com/sagernet/sing-shadowsocks v0.2.6
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0
|
||||
github.com/sagernet/sing-shadowtls v0.1.4
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.9
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.9.0.20240612071945-28df5b4b41f5
|
||||
github.com/sagernet/sing-vmess v0.1.8
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7
|
||||
github.com/sagernet/tfo-go v0.0.0-20231209031829-7b5343ac1dc6
|
||||
@ -81,7 +81,7 @@ require (
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/quic-go/qpack v0.4.0 // indirect
|
||||
github.com/quic-go/qtls-go1-20 v0.4.1 // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba // indirect
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a // indirect
|
||||
github.com/sagernet/nftables v0.3.0-beta.2 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/u-root/uio v0.0.0-20230220225925-ffce2a382923 // indirect
|
||||
|
8
go.sum
8
go.sum
@ -104,8 +104,8 @@ github.com/sagernet/gomobile v0.1.3 h1:ohjIb1Ou2+1558PnZour3od69suSuvkdSVOlO1tC4
|
||||
github.com/sagernet/gomobile v0.1.3/go.mod h1:Pqq2+ZVvs10U7xK+UwJgwYWUykewi8H6vlslAO73n9E=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f h1:NkhuupzH5ch7b/Y/6ZHJWrnNLoiNnSJaow6DPb8VW2I=
|
||||
github.com/sagernet/gvisor v0.0.0-20240428053021-e691de28565f/go.mod h1:KXmw+ouSJNOsuRpg4wgwwCQuunrGz4yoAqQjsLjc6N0=
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba h1:EY5AS7CCtfmARNv2zXUOrsEMPFDGYxaw65JzA2p51Vk=
|
||||
github.com/sagernet/netlink v0.0.0-20240523065131-45e60152f9ba/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a h1:ObwtHN2VpqE0ZNjr6sGeT00J8uU7JF4cNUdb44/Duis=
|
||||
github.com/sagernet/netlink v0.0.0-20240612041022-b9a21c07ac6a/go.mod h1:xLnfdiJbSp8rNqYEdIW/6eDO4mVoogml14Bh2hSiFpM=
|
||||
github.com/sagernet/nftables v0.3.0-beta.2 h1:yKqMl4Dpb6nKxAmlE6fXjJRlLO2c1f2wyNFBg4hBr8w=
|
||||
github.com/sagernet/nftables v0.3.0-beta.2/go.mod h1:OQXAjvjNGGFxaTgVCSTRIhYB5/llyVDeapVoENYBDS8=
|
||||
github.com/sagernet/quic-go v0.45.0-beta.2 h1:nWq9KJTR+cGU8UU4E20XNjdM6QgbLkBgpq+NCExg5RY=
|
||||
@ -127,8 +127,8 @@ github.com/sagernet/sing-shadowsocks2 v0.2.0 h1:wpZNs6wKnR7mh1wV9OHwOyUr21VkS3wK
|
||||
github.com/sagernet/sing-shadowsocks2 v0.2.0/go.mod h1:RnXS0lExcDAovvDeniJ4IKa2IuChrdipolPYWBv9hWQ=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4 h1:aTgBSJEgnumzFenPvc+kbD9/W0PywzWevnVpEx6Tw3k=
|
||||
github.com/sagernet/sing-shadowtls v0.1.4/go.mod h1:F8NBgsY5YN2beQavdgdm1DPlhaKQlaL6lpDdcBglGK4=
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.9 h1:/5hXQ0u7tHtngfXozRc+o/gt6zfHBHMOwSIHXF0+S3I=
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.9/go.mod h1:uoRiCzWHzHLw/angVqXDzUNiQcMRl/ZrElJryQLJFhY=
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.9.0.20240612071945-28df5b4b41f5 h1:OpRvbxi+9zZ4LmWo1GqlWXGLOdCquFg5J3qh6uUwTBU=
|
||||
github.com/sagernet/sing-tun v0.4.0-beta.9.0.20240612071945-28df5b4b41f5/go.mod h1:yaLwsfgGeRTsgupm3MOz/6r7EJ74qIgZCyKLNW/6aHE=
|
||||
github.com/sagernet/sing-vmess v0.1.8 h1:XVWad1RpTy9b5tPxdm5MCU8cGfrTGdR8qCq6HV2aCNc=
|
||||
github.com/sagernet/sing-vmess v0.1.8/go.mod h1:vhx32UNzTDUkNwOyIjcZQohre1CaytquC5mPplId8uA=
|
||||
github.com/sagernet/smux v0.0.0-20231208180855-7041f6ea79e7 h1:DImB4lELfQhplLTxeq2z31Fpv8CQqqrUwTbrIRumZqQ=
|
||||
|
113
inbound/tun.go
113
inbound/tun.go
@ -20,25 +20,34 @@ 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"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
var _ adapter.Inbound = (*Tun)(nil)
|
||||
|
||||
type Tun struct {
|
||||
tag string
|
||||
ctx context.Context
|
||||
router adapter.Router
|
||||
logger log.ContextLogger
|
||||
inboundOptions option.InboundOptions
|
||||
tunOptions tun.Options
|
||||
endpointIndependentNat bool
|
||||
udpTimeout int64
|
||||
stack string
|
||||
tunIf tun.Tun
|
||||
tunStack tun.Stack
|
||||
platformInterface platform.Interface
|
||||
platformOptions option.TunPlatformOptions
|
||||
autoRedirect tun.AutoRedirect
|
||||
tag string
|
||||
ctx context.Context
|
||||
router adapter.Router
|
||||
logger log.ContextLogger
|
||||
inboundOptions option.InboundOptions
|
||||
tunOptions tun.Options
|
||||
endpointIndependentNat bool
|
||||
udpTimeout int64
|
||||
stack string
|
||||
tunIf tun.Tun
|
||||
tunStack tun.Stack
|
||||
platformInterface platform.Interface
|
||||
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
|
||||
}
|
||||
|
||||
func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.TunInboundOptions, platformInterface platform.Interface) (*Tun, error) {
|
||||
@ -81,6 +90,7 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
Inet4Address: options.Inet4Address,
|
||||
Inet6Address: options.Inet6Address,
|
||||
AutoRoute: options.AutoRoute,
|
||||
AutoRedirect: options.AutoRedirect,
|
||||
StrictRoute: options.StrictRoute,
|
||||
IncludeInterface: options.IncludeInterface,
|
||||
ExcludeInterface: options.ExcludeInterface,
|
||||
@ -108,15 +118,33 @@ func NewTun(ctx context.Context, router adapter.Router, logger log.ContextLogger
|
||||
}
|
||||
disableNFTables, dErr := strconv.ParseBool(os.Getenv("DISABLE_NFTABLES"))
|
||||
inbound.autoRedirect, err = tun.NewAutoRedirect(tun.AutoRedirectOptions{
|
||||
TunOptions: &inbound.tunOptions,
|
||||
Context: ctx,
|
||||
Handler: inbound,
|
||||
Logger: logger,
|
||||
TableName: "sing-box",
|
||||
DisableNFTables: dErr == nil && disableNFTables,
|
||||
TunOptions: &inbound.tunOptions,
|
||||
Context: ctx,
|
||||
Handler: inbound,
|
||||
Logger: logger,
|
||||
TableName: "sing-box",
|
||||
DisableNFTables: dErr == nil && disableNFTables,
|
||||
RouteAddressSet: &inbound.routeAddressSet,
|
||||
RouteExcludeAddressSet: &inbound.routeExcludeAddressSet,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "initialize auto redirect")
|
||||
return nil, E.Cause(err, "initialize auto-redirect")
|
||||
}
|
||||
for _, routeAddressSet := range options.RouteAddressSet {
|
||||
ruleSet, loaded := router.RuleSet(routeAddressSet)
|
||||
if !loaded {
|
||||
return nil, E.New("parse route_address_set: rule-set not found: ", routeAddressSet)
|
||||
}
|
||||
ruleSet.IncRef()
|
||||
inbound.routeRuleSet = append(inbound.routeRuleSet, ruleSet)
|
||||
}
|
||||
for _, routeExcludeAddressSet := range options.RouteExcludeAddressSet {
|
||||
ruleSet, loaded := router.RuleSet(routeExcludeAddressSet)
|
||||
if !loaded {
|
||||
return nil, E.New("parse route_exclude_address_set: rule-set not found: ", routeExcludeAddressSet)
|
||||
}
|
||||
ruleSet.IncRef()
|
||||
inbound.routeExcludeRuleSet = append(inbound.routeExcludeRuleSet, ruleSet)
|
||||
}
|
||||
}
|
||||
return inbound, nil
|
||||
@ -215,18 +243,45 @@ func (t *Tun) Start() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if t.autoRedirect != nil {
|
||||
monitor.Start("initiating auto redirect")
|
||||
err = t.autoRedirect.Start()
|
||||
monitor.Finish()
|
||||
if err != nil {
|
||||
return E.Cause(err, "auto redirect")
|
||||
}
|
||||
}
|
||||
t.logger.Info("started at ", t.tunOptions.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tun) PostStart() error {
|
||||
monitor := taskmonitor.New(t.logger, C.StartTimeout)
|
||||
// TODO: add ref counter to rule-set and release them if not needed
|
||||
for _, ruleSet := range t.routeRuleSet {
|
||||
t.routeAddressSet = append(t.routeAddressSet, ruleSet.ExtractIPSet()...)
|
||||
}
|
||||
for _, ruleSet := range t.routeExcludeRuleSet {
|
||||
t.routeExcludeAddressSet = append(t.routeExcludeAddressSet, ruleSet.ExtractIPSet()...)
|
||||
}
|
||||
if t.autoRedirect != nil {
|
||||
monitor.Start("initiating auto-redirect")
|
||||
err := t.autoRedirect.Start()
|
||||
monitor.Finish()
|
||||
if err != nil {
|
||||
return E.Cause(err, "auto-redirect")
|
||||
}
|
||||
}
|
||||
for _, routeRuleSet := range t.routeRuleSet {
|
||||
t.routeRuleSetCallback = append(t.routeRuleSetCallback, routeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
||||
routeRuleSet.DecRef()
|
||||
}
|
||||
for _, routeExcludeRuleSet := range t.routeExcludeRuleSet {
|
||||
t.routeExcludeRuleSetCallback = append(t.routeExcludeRuleSetCallback, routeExcludeRuleSet.RegisterCallback(t.updateRouteAddressSet))
|
||||
routeExcludeRuleSet.DecRef()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tun) updateRouteAddressSet(it adapter.RuleSet) {
|
||||
err := t.autoRedirect.UpdateRouteAddressSet()
|
||||
if err != nil {
|
||||
t.logger.Error("update route address set ", it.Name(), ": ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (t *Tun) Close() error {
|
||||
return common.Close(
|
||||
t.tunStack,
|
||||
|
@ -3,30 +3,42 @@ package option
|
||||
import "net/netip"
|
||||
|
||||
type TunInboundOptions struct {
|
||||
InterfaceName string `json:"interface_name,omitempty"`
|
||||
MTU uint32 `json:"mtu,omitempty"`
|
||||
GSO bool `json:"gso,omitempty"`
|
||||
Inet4Address Listable[netip.Prefix] `json:"inet4_address,omitempty"`
|
||||
Inet6Address Listable[netip.Prefix] `json:"inet6_address,omitempty"`
|
||||
AutoRoute bool `json:"auto_route,omitempty"`
|
||||
AutoRedirect bool `json:"auto_redirect,omitempty"`
|
||||
StrictRoute bool `json:"strict_route,omitempty"`
|
||||
Inet4RouteAddress Listable[netip.Prefix] `json:"inet4_route_address,omitempty"`
|
||||
Inet6RouteAddress Listable[netip.Prefix] `json:"inet6_route_address,omitempty"`
|
||||
Inet4RouteExcludeAddress Listable[netip.Prefix] `json:"inet4_route_exclude_address,omitempty"`
|
||||
Inet6RouteExcludeAddress Listable[netip.Prefix] `json:"inet6_route_exclude_address,omitempty"`
|
||||
IncludeInterface Listable[string] `json:"include_interface,omitempty"`
|
||||
ExcludeInterface Listable[string] `json:"exclude_interface,omitempty"`
|
||||
IncludeUID Listable[uint32] `json:"include_uid,omitempty"`
|
||||
IncludeUIDRange Listable[string] `json:"include_uid_range,omitempty"`
|
||||
ExcludeUID Listable[uint32] `json:"exclude_uid,omitempty"`
|
||||
ExcludeUIDRange Listable[string] `json:"exclude_uid_range,omitempty"`
|
||||
IncludeAndroidUser Listable[int] `json:"include_android_user,omitempty"`
|
||||
IncludePackage Listable[string] `json:"include_package,omitempty"`
|
||||
ExcludePackage Listable[string] `json:"exclude_package,omitempty"`
|
||||
EndpointIndependentNat bool `json:"endpoint_independent_nat,omitempty"`
|
||||
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
||||
Stack string `json:"stack,omitempty"`
|
||||
Platform *TunPlatformOptions `json:"platform,omitempty"`
|
||||
InterfaceName string `json:"interface_name,omitempty"`
|
||||
MTU uint32 `json:"mtu,omitempty"`
|
||||
GSO bool `json:"gso,omitempty"`
|
||||
Address Listable[netip.Prefix] `json:"address,omitempty"`
|
||||
AutoRoute bool `json:"auto_route,omitempty"`
|
||||
AutoRedirect bool `json:"auto_redirect,omitempty"`
|
||||
StrictRoute bool `json:"strict_route,omitempty"`
|
||||
RouteAddress Listable[netip.Prefix] `json:"route_address,omitempty"`
|
||||
RouteAddressSet Listable[string] `json:"route_address_set,omitempty"`
|
||||
RouteExcludeAddress Listable[netip.Prefix] `json:"route_exclude_address,omitempty"`
|
||||
RouteExcludeAddressSet Listable[string] `json:"route_exclude_address_set,omitempty"`
|
||||
IncludeInterface Listable[string] `json:"include_interface,omitempty"`
|
||||
ExcludeInterface Listable[string] `json:"exclude_interface,omitempty"`
|
||||
IncludeUID Listable[uint32] `json:"include_uid,omitempty"`
|
||||
IncludeUIDRange Listable[string] `json:"include_uid_range,omitempty"`
|
||||
ExcludeUID Listable[uint32] `json:"exclude_uid,omitempty"`
|
||||
ExcludeUIDRange Listable[string] `json:"exclude_uid_range,omitempty"`
|
||||
IncludeAndroidUser Listable[int] `json:"include_android_user,omitempty"`
|
||||
IncludePackage Listable[string] `json:"include_package,omitempty"`
|
||||
ExcludePackage Listable[string] `json:"exclude_package,omitempty"`
|
||||
EndpointIndependentNat bool `json:"endpoint_independent_nat,omitempty"`
|
||||
UDPTimeout UDPTimeoutCompat `json:"udp_timeout,omitempty"`
|
||||
Stack string `json:"stack,omitempty"`
|
||||
Platform *TunPlatformOptions `json:"platform,omitempty"`
|
||||
InboundOptions
|
||||
|
||||
// Deprecated: merged to `address`
|
||||
Inet4Address Listable[netip.Prefix] `json:"inet4_address,omitempty"`
|
||||
// Deprecated: merged to `address`
|
||||
Inet6Address Listable[netip.Prefix] `json:"inet6_address,omitempty"`
|
||||
// Deprecated: merged to `route_address`
|
||||
Inet4RouteAddress Listable[netip.Prefix] `json:"inet4_route_address,omitempty"`
|
||||
// Deprecated: merged to `route_address`
|
||||
Inet6RouteAddress Listable[netip.Prefix] `json:"inet6_route_address,omitempty"`
|
||||
// Deprecated: merged to `route_exclude_address`
|
||||
Inet4RouteExcludeAddress Listable[netip.Prefix] `json:"inet4_route_exclude_address,omitempty"`
|
||||
// Deprecated: merged to `route_exclude_address`
|
||||
Inet6RouteExcludeAddress Listable[netip.Prefix] `json:"inet6_route_exclude_address,omitempty"`
|
||||
}
|
||||
|
@ -728,6 +728,14 @@ func (r *Router) PostStart() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Cleanup() error {
|
||||
for _, ruleSet := range r.ruleSetMap {
|
||||
ruleSet.Cleanup()
|
||||
}
|
||||
runtime.GC()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Outbound(tag string) (adapter.Outbound, bool) {
|
||||
outbound, loaded := r.outboundByTag[tag]
|
||||
return outbound, loaded
|
||||
|
@ -32,6 +32,7 @@ func (r *RuleSetItem) Start() error {
|
||||
if !loaded {
|
||||
return E.New("rule-set not found: ", tag)
|
||||
}
|
||||
ruleSet.IncRef()
|
||||
r.setList = append(r.setList, ruleSet)
|
||||
}
|
||||
return nil
|
||||
|
@ -9,10 +9,13 @@ import (
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
func NewRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) (adapter.RuleSet, error) {
|
||||
@ -26,6 +29,24 @@ func NewRuleSet(ctx context.Context, router adapter.Router, logger logger.Contex
|
||||
}
|
||||
}
|
||||
|
||||
func extractIPSetFromRule(rawRule adapter.HeadlessRule) []*netipx.IPSet {
|
||||
switch rule := rawRule.(type) {
|
||||
case *DefaultHeadlessRule:
|
||||
return common.FlatMap(rule.destinationIPCIDRItems, func(rawItem RuleItem) []*netipx.IPSet {
|
||||
switch item := rawItem.(type) {
|
||||
case *IPCIDRItem:
|
||||
return []*netipx.IPSet{item.ipSet}
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
})
|
||||
case *LogicalHeadlessRule:
|
||||
return common.FlatMap(rule.rules, extractIPSetFromRule)
|
||||
default:
|
||||
panic("unexpected rule type")
|
||||
}
|
||||
}
|
||||
|
||||
var _ adapter.RuleSetStartContext = (*RuleSetStartContext)(nil)
|
||||
|
||||
type RuleSetStartContext struct {
|
||||
|
@ -9,16 +9,23 @@ import (
|
||||
"github.com/sagernet/sing-box/common/srs"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/atomic"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
var _ adapter.RuleSet = (*LocalRuleSet)(nil)
|
||||
|
||||
type LocalRuleSet struct {
|
||||
tag string
|
||||
rules []adapter.HeadlessRule
|
||||
metadata adapter.RuleSetMetadata
|
||||
refs atomic.Int32
|
||||
}
|
||||
|
||||
func NewLocalRuleSet(router adapter.Router, options option.RuleSet) (*LocalRuleSet, error) {
|
||||
@ -58,16 +65,11 @@ func NewLocalRuleSet(router adapter.Router, options option.RuleSet) (*LocalRuleS
|
||||
metadata.ContainsProcessRule = hasHeadlessRule(plainRuleSet.Rules, isProcessHeadlessRule)
|
||||
metadata.ContainsWIFIRule = hasHeadlessRule(plainRuleSet.Rules, isWIFIHeadlessRule)
|
||||
metadata.ContainsIPCIDRRule = hasHeadlessRule(plainRuleSet.Rules, isIPCIDRHeadlessRule)
|
||||
return &LocalRuleSet{rules, metadata}, nil
|
||||
return &LocalRuleSet{tag: options.Tag, rules: rules, metadata: metadata}, nil
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) Match(metadata *adapter.InboundContext) bool {
|
||||
for _, rule := range s.rules {
|
||||
if rule.Match(metadata) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (s *LocalRuleSet) Name() string {
|
||||
return s.tag
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) String() string {
|
||||
@ -82,6 +84,43 @@ func (s *LocalRuleSet) Metadata() adapter.RuleSetMetadata {
|
||||
return s.metadata
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) Close() error {
|
||||
func (s *LocalRuleSet) ExtractIPSet() []*netipx.IPSet {
|
||||
return common.FlatMap(s.rules, extractIPSetFromRule)
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) IncRef() {
|
||||
s.refs.Add(1)
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) DecRef() {
|
||||
if s.refs.Add(-1) < 0 {
|
||||
panic("rule-set: negative refs")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) Cleanup() {
|
||||
if s.refs.Load() == 0 {
|
||||
s.rules = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) RegisterCallback(callback adapter.RuleSetUpdateCallback) *list.Element[adapter.RuleSetUpdateCallback] {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) UnregisterCallback(element *list.Element[adapter.RuleSetUpdateCallback]) {
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) Close() error {
|
||||
s.rules = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *LocalRuleSet) Match(metadata *adapter.InboundContext) bool {
|
||||
for _, rule := range s.rules {
|
||||
if rule.Match(metadata) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -8,20 +8,26 @@ import (
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/common/srs"
|
||||
C "github.com/sagernet/sing-box/constant"
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/atomic"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
"github.com/sagernet/sing/common/json"
|
||||
"github.com/sagernet/sing/common/logger"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
"github.com/sagernet/sing/service"
|
||||
"github.com/sagernet/sing/service/pause"
|
||||
|
||||
"go4.org/netipx"
|
||||
)
|
||||
|
||||
var _ adapter.RuleSet = (*RemoteRuleSet)(nil)
|
||||
@ -40,6 +46,9 @@ type RemoteRuleSet struct {
|
||||
lastEtag string
|
||||
updateTicker *time.Ticker
|
||||
pauseManager pause.Manager
|
||||
callbackAccess sync.Mutex
|
||||
callbacks list.List[adapter.RuleSetUpdateCallback]
|
||||
refs atomic.Int32
|
||||
}
|
||||
|
||||
func NewRemoteRuleSet(ctx context.Context, router adapter.Router, logger logger.ContextLogger, options option.RuleSet) *RemoteRuleSet {
|
||||
@ -61,13 +70,8 @@ func NewRemoteRuleSet(ctx context.Context, router adapter.Router, logger logger.
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) Match(metadata *adapter.InboundContext) bool {
|
||||
for _, rule := range s.rules {
|
||||
if rule.Match(metadata) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
func (s *RemoteRuleSet) Name() string {
|
||||
return s.options.Tag
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) String() string {
|
||||
@ -116,6 +120,38 @@ func (s *RemoteRuleSet) Metadata() adapter.RuleSetMetadata {
|
||||
return s.metadata
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) ExtractIPSet() []*netipx.IPSet {
|
||||
return common.FlatMap(s.rules, extractIPSetFromRule)
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) IncRef() {
|
||||
s.refs.Add(1)
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) DecRef() {
|
||||
if s.refs.Add(-1) < 0 {
|
||||
panic("rule-set: negative refs")
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) Cleanup() {
|
||||
if s.refs.Load() == 0 {
|
||||
s.rules = nil
|
||||
}
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) RegisterCallback(callback adapter.RuleSetUpdateCallback) *list.Element[adapter.RuleSetUpdateCallback] {
|
||||
s.callbackAccess.Lock()
|
||||
defer s.callbackAccess.Unlock()
|
||||
return s.callbacks.PushBack(callback)
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) UnregisterCallback(element *list.Element[adapter.RuleSetUpdateCallback]) {
|
||||
s.callbackAccess.Lock()
|
||||
defer s.callbackAccess.Unlock()
|
||||
s.callbacks.Remove(element)
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) loadBytes(content []byte) error {
|
||||
var (
|
||||
plainRuleSet option.PlainRuleSet
|
||||
@ -148,6 +184,16 @@ func (s *RemoteRuleSet) loadBytes(content []byte) error {
|
||||
s.metadata.ContainsWIFIRule = hasHeadlessRule(plainRuleSet.Rules, isWIFIHeadlessRule)
|
||||
s.metadata.ContainsIPCIDRRule = hasHeadlessRule(plainRuleSet.Rules, isIPCIDRHeadlessRule)
|
||||
s.rules = rules
|
||||
s.callbackAccess.Lock()
|
||||
callbacks := s.callbacks.Array()
|
||||
s.callbackAccess.Unlock()
|
||||
for _, callback := range callbacks {
|
||||
callback(s)
|
||||
}
|
||||
if s.refs.Load() == 0 {
|
||||
s.rules = nil
|
||||
runtime.GC()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -253,7 +299,17 @@ func (s *RemoteRuleSet) fetchOnce(ctx context.Context, startContext adapter.Rule
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) Close() error {
|
||||
s.rules = nil
|
||||
s.updateTicker.Stop()
|
||||
s.cancel()
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *RemoteRuleSet) Match(metadata *adapter.InboundContext) bool {
|
||||
for _, rule := range s.rules {
|
||||
if rule.Match(metadata) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user