mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-06-23 19:03:11 +03:00
Add http/block outbound & Improve route
This commit is contained in:
120
route/router.go
120
route/router.go
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/sagernet/sing-box/option"
|
||||
"github.com/sagernet/sing/common"
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
F "github.com/sagernet/sing/common/format"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
@@ -23,11 +24,15 @@ import (
|
||||
var _ adapter.Router = (*Router)(nil)
|
||||
|
||||
type Router struct {
|
||||
ctx context.Context
|
||||
logger log.Logger
|
||||
defaultOutbound adapter.Outbound
|
||||
outboundByTag map[string]adapter.Outbound
|
||||
rules []adapter.Rule
|
||||
ctx context.Context
|
||||
logger log.Logger
|
||||
|
||||
outboundByTag map[string]adapter.Outbound
|
||||
rules []adapter.Rule
|
||||
|
||||
defaultDetour string
|
||||
defaultOutboundForConnection adapter.Outbound
|
||||
defaultOutboundForPacketConnection adapter.Outbound
|
||||
|
||||
needGeoDatabase bool
|
||||
geoOptions option.GeoIPOptions
|
||||
@@ -42,6 +47,7 @@ func NewRouter(ctx context.Context, logger log.Logger, options option.RouteOptio
|
||||
rules: make([]adapter.Rule, 0, len(options.Rules)),
|
||||
needGeoDatabase: hasGeoRule(options.Rules),
|
||||
geoOptions: common.PtrValueOrDefault(options.GeoIP),
|
||||
defaultDetour: options.DefaultDetour,
|
||||
}
|
||||
for i, ruleOptions := range options.Rules {
|
||||
rule, err := NewRule(router, logger, ruleOptions)
|
||||
@@ -55,11 +61,12 @@ func NewRouter(ctx context.Context, logger log.Logger, options option.RouteOptio
|
||||
|
||||
func hasGeoRule(rules []option.Rule) bool {
|
||||
for _, rule := range rules {
|
||||
if rule.DefaultOptions != nil {
|
||||
if isGeoRule(common.PtrValueOrDefault(rule.DefaultOptions)) {
|
||||
switch rule.Type {
|
||||
case C.RuleTypeDefault:
|
||||
if isGeoRule(rule.DefaultOptions) {
|
||||
return true
|
||||
}
|
||||
} else if rule.LogicalOptions != nil {
|
||||
case C.RuleTypeLogical:
|
||||
for _, subRule := range rule.LogicalOptions.Rules {
|
||||
if isGeoRule(subRule) {
|
||||
return true
|
||||
@@ -78,17 +85,73 @@ func notPrivateNode(code string) bool {
|
||||
return code == "private"
|
||||
}
|
||||
|
||||
func (r *Router) UpdateOutbounds(outbounds []adapter.Outbound) {
|
||||
var defaultOutbound adapter.Outbound
|
||||
func (r *Router) Initialize(outbounds []adapter.Outbound, defaultOutbound func() adapter.Outbound) error {
|
||||
outboundByTag := make(map[string]adapter.Outbound)
|
||||
if len(outbounds) > 0 {
|
||||
defaultOutbound = outbounds[0]
|
||||
for _, detour := range outbounds {
|
||||
outboundByTag[detour.Tag()] = detour
|
||||
}
|
||||
for _, outbound := range outbounds {
|
||||
outboundByTag[outbound.Tag()] = outbound
|
||||
var defaultOutboundForConnection adapter.Outbound
|
||||
var defaultOutboundForPacketConnection adapter.Outbound
|
||||
if r.defaultDetour != "" {
|
||||
detour, loaded := outboundByTag[r.defaultDetour]
|
||||
if !loaded {
|
||||
return E.New("default detour not found: ", r.defaultDetour)
|
||||
}
|
||||
if common.Contains(detour.Network(), C.NetworkTCP) {
|
||||
defaultOutboundForConnection = detour
|
||||
}
|
||||
if common.Contains(detour.Network(), C.NetworkUDP) {
|
||||
defaultOutboundForPacketConnection = detour
|
||||
}
|
||||
}
|
||||
r.defaultOutbound = defaultOutbound
|
||||
var index, packetIndex int
|
||||
if defaultOutboundForConnection == nil {
|
||||
for i, detour := range outbounds {
|
||||
if common.Contains(detour.Network(), C.NetworkTCP) {
|
||||
index = i
|
||||
defaultOutboundForConnection = detour
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if defaultOutboundForPacketConnection == nil {
|
||||
for i, detour := range outbounds {
|
||||
if common.Contains(detour.Network(), C.NetworkUDP) {
|
||||
packetIndex = i
|
||||
defaultOutboundForPacketConnection = detour
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if defaultOutboundForConnection == nil || defaultOutboundForPacketConnection == nil {
|
||||
detour := defaultOutbound()
|
||||
if defaultOutboundForConnection == nil {
|
||||
defaultOutboundForConnection = detour
|
||||
}
|
||||
if defaultOutboundForPacketConnection == nil {
|
||||
defaultOutboundForPacketConnection = detour
|
||||
}
|
||||
}
|
||||
if defaultOutboundForConnection != defaultOutboundForPacketConnection {
|
||||
var description string
|
||||
if defaultOutboundForConnection.Tag() != "" {
|
||||
description = defaultOutboundForConnection.Tag()
|
||||
} else {
|
||||
description = F.ToString(index)
|
||||
}
|
||||
var packetDescription string
|
||||
if defaultOutboundForPacketConnection.Tag() != "" {
|
||||
packetDescription = defaultOutboundForPacketConnection.Tag()
|
||||
} else {
|
||||
packetDescription = F.ToString(packetIndex)
|
||||
}
|
||||
r.logger.Info("using ", defaultOutboundForConnection.Type(), "[", description, "] as default outbound for connection")
|
||||
r.logger.Info("using ", defaultOutboundForPacketConnection.Type(), "[", packetDescription, "] as default outbound for packet connection")
|
||||
}
|
||||
r.defaultOutboundForConnection = defaultOutboundForConnection
|
||||
r.defaultOutboundForPacketConnection = defaultOutboundForPacketConnection
|
||||
r.outboundByTag = outboundByTag
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Router) Start() error {
|
||||
@@ -158,7 +221,7 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error {
|
||||
}
|
||||
detour = outbound
|
||||
} else {
|
||||
detour = r.defaultOutbound
|
||||
detour = r.defaultOutboundForConnection
|
||||
}
|
||||
|
||||
if parentDir := filepath.Dir(savePath); parentDir != "" {
|
||||
@@ -190,27 +253,30 @@ func (r *Router) downloadGeoIPDatabase(savePath string) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (r *Router) DefaultOutbound() adapter.Outbound {
|
||||
if r.defaultOutbound == nil {
|
||||
panic("missing default outbound")
|
||||
}
|
||||
return r.defaultOutbound
|
||||
}
|
||||
|
||||
func (r *Router) Outbound(tag string) (adapter.Outbound, bool) {
|
||||
outbound, loaded := r.outboundByTag[tag]
|
||||
return outbound, loaded
|
||||
}
|
||||
|
||||
func (r *Router) RouteConnection(ctx context.Context, conn net.Conn, metadata adapter.InboundContext) error {
|
||||
return r.match(ctx, metadata).NewConnection(ctx, conn, metadata.Destination)
|
||||
detour := r.match(ctx, metadata, r.defaultOutboundForConnection)
|
||||
if !common.Contains(detour.Network(), C.NetworkTCP) {
|
||||
conn.Close()
|
||||
return E.New("missing supported outbound, closing connection")
|
||||
}
|
||||
return detour.NewConnection(ctx, conn, metadata.Destination)
|
||||
}
|
||||
|
||||
func (r *Router) RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata adapter.InboundContext) error {
|
||||
return r.match(ctx, metadata).NewPacketConnection(ctx, conn, metadata.Destination)
|
||||
detour := r.match(ctx, metadata, r.defaultOutboundForPacketConnection)
|
||||
if !common.Contains(detour.Network(), C.NetworkUDP) {
|
||||
conn.Close()
|
||||
return E.New("missing supported outbound, closing packet connection")
|
||||
}
|
||||
return detour.NewPacketConnection(ctx, conn, metadata.Destination)
|
||||
}
|
||||
|
||||
func (r *Router) match(ctx context.Context, metadata adapter.InboundContext) adapter.Outbound {
|
||||
func (r *Router) match(ctx context.Context, metadata adapter.InboundContext, defaultOutbound adapter.Outbound) adapter.Outbound {
|
||||
for i, rule := range r.rules {
|
||||
if rule.Match(&metadata) {
|
||||
detour := rule.Outbound()
|
||||
@@ -222,5 +288,5 @@ func (r *Router) match(ctx context.Context, metadata adapter.InboundContext) ada
|
||||
}
|
||||
}
|
||||
r.logger.WithContext(ctx).Info("no match")
|
||||
return r.defaultOutbound
|
||||
return defaultOutbound
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ func NewRule(router adapter.Router, logger log.Logger, options option.Rule) (ada
|
||||
if options.DefaultOptions.Outbound == "" {
|
||||
return nil, E.New("missing outbound field")
|
||||
}
|
||||
return NewDefaultRule(router, logger, common.PtrValueOrDefault(options.DefaultOptions))
|
||||
return NewDefaultRule(router, logger, options.DefaultOptions)
|
||||
case C.RuleTypeLogical:
|
||||
if !options.LogicalOptions.IsValid() {
|
||||
return nil, E.New("missing conditions")
|
||||
@@ -32,7 +32,7 @@ func NewRule(router adapter.Router, logger log.Logger, options option.Rule) (ada
|
||||
if options.LogicalOptions.Outbound == "" {
|
||||
return nil, E.New("missing outbound field")
|
||||
}
|
||||
return NewLogicalRule(router, logger, common.PtrValueOrDefault(options.LogicalOptions))
|
||||
return NewLogicalRule(router, logger, options.LogicalOptions)
|
||||
default:
|
||||
return nil, E.New("unknown rule type: ", options.Type)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user