mirror of
https://github.com/shtorm-7/sing-box-extended.git
synced 2026-09-15 21:00:27 +00:00
Inverted rules whose address filter conditions come from rule sets or logical rules were rejected during pre-lookup matching, so the lookup was never sent and the rules never matched; for plain ip rule sets this was a regression from the rule-set invert fix in 1.12.22. Pre-lookup matching now tracks whether the result depends on deferred address filter conditions and defers such rules to the response phase, while results already determined by evaluated conditions are still decided during pre-lookup.
203 lines
5.1 KiB
Go
203 lines
5.1 KiB
Go
package adapter
|
|
|
|
import (
|
|
"context"
|
|
"net"
|
|
"net/netip"
|
|
"time"
|
|
|
|
"github.com/sagernet/sing-box/common/tlsspoof"
|
|
C "github.com/sagernet/sing-box/constant"
|
|
"github.com/sagernet/sing-box/log"
|
|
"github.com/sagernet/sing-box/option"
|
|
M "github.com/sagernet/sing/common/metadata"
|
|
|
|
"github.com/miekg/dns"
|
|
)
|
|
|
|
type Inbound interface {
|
|
Lifecycle
|
|
Type() string
|
|
Tag() string
|
|
}
|
|
|
|
type TCPInjectableInbound interface {
|
|
Inbound
|
|
ConnectionHandler
|
|
}
|
|
|
|
type UDPInjectableInbound interface {
|
|
Inbound
|
|
PacketConnectionHandler
|
|
}
|
|
|
|
type InboundRegistry interface {
|
|
option.InboundOptionsRegistry
|
|
Create(ctx context.Context, router Router, logger log.ContextLogger, tag string, inboundType string, options any) (Inbound, error)
|
|
}
|
|
|
|
type InboundManager interface {
|
|
Lifecycle
|
|
Inbounds() []Inbound
|
|
Get(tag string) (Inbound, bool)
|
|
Remove(tag string) error
|
|
Create(ctx context.Context, router Router, logger log.ContextLogger, tag string, inboundType string, options any) error
|
|
}
|
|
|
|
type InboundContext struct {
|
|
Inbound string
|
|
InboundType string
|
|
IPVersion uint8
|
|
Network string
|
|
Source M.Socksaddr
|
|
Destination M.Socksaddr
|
|
User string
|
|
Outbound string
|
|
|
|
// sniffer
|
|
|
|
Protocol string
|
|
Domain string
|
|
Client string
|
|
SniffContext any
|
|
SnifferNames []string
|
|
SniffError error
|
|
|
|
// cache
|
|
|
|
// Deprecated: implement in rule action
|
|
InboundDetour string
|
|
LastInbound string
|
|
OriginDestination M.Socksaddr
|
|
RouteOriginalDestination M.Socksaddr
|
|
UDPDisableDomainUnmapping bool
|
|
UDPConnect bool
|
|
UDPTimeout time.Duration
|
|
TLSFragment bool
|
|
TLSFragmentFallbackDelay time.Duration
|
|
TLSRecordFragment bool
|
|
TLSSpoof string
|
|
TLSSpoofMethod tlsspoof.Method
|
|
|
|
NetworkStrategy *C.NetworkStrategy
|
|
NetworkType []C.InterfaceType
|
|
FallbackNetworkType []C.InterfaceType
|
|
FallbackDelay time.Duration
|
|
|
|
DestinationAddresses []netip.Addr
|
|
DNSResponse *dns.Msg
|
|
NamedDNSResponses map[string]*dns.Msg
|
|
DestinationAddressMatchFromResponse bool
|
|
SourceGeoIPCode string
|
|
GeoIPCode string
|
|
ProcessInfo *ConnectionOwner
|
|
SourceMACAddress net.HardwareAddr
|
|
SourceHostname string
|
|
QueryType uint16
|
|
QueryClientSubnet netip.Prefix
|
|
QueryDNSSEC bool
|
|
FakeIP bool
|
|
PreMatch bool
|
|
|
|
// rule cache
|
|
|
|
IPCIDRMatchSource bool
|
|
IPCIDRAcceptEmpty bool
|
|
|
|
SourceAddressMatch bool
|
|
SourcePortMatch bool
|
|
DestinationAddressMatch bool
|
|
DestinationPortMatch bool
|
|
DeferredIPCIDRMatchGroups uint8
|
|
IgnoreDestinationIPCIDRMatch bool
|
|
}
|
|
|
|
func (c *InboundContext) ResetRuleCache() {
|
|
c.IPCIDRMatchSource = false
|
|
c.IPCIDRAcceptEmpty = false
|
|
c.ResetRuleMatchCache()
|
|
}
|
|
|
|
func (c *InboundContext) ResetRuleMatchCache() {
|
|
c.SourceAddressMatch = false
|
|
c.SourcePortMatch = false
|
|
c.DestinationAddressMatch = false
|
|
c.DestinationPortMatch = false
|
|
c.DeferredIPCIDRMatchGroups = 0
|
|
}
|
|
|
|
func (c *InboundContext) DNSResponseAddressesForMatch() []netip.Addr {
|
|
return DNSResponseAddresses(c.DNSResponse)
|
|
}
|
|
|
|
func DNSResponseAddresses(response *dns.Msg) []netip.Addr {
|
|
if response == nil || response.Rcode != dns.RcodeSuccess {
|
|
return nil
|
|
}
|
|
addresses := make([]netip.Addr, 0, len(response.Answer))
|
|
for _, rawRecord := range response.Answer {
|
|
switch record := rawRecord.(type) {
|
|
case *dns.A:
|
|
addr := M.AddrFromIP(record.A)
|
|
if addr.IsValid() {
|
|
addresses = append(addresses, addr)
|
|
}
|
|
case *dns.AAAA:
|
|
addr := M.AddrFromIP(record.AAAA)
|
|
if addr.IsValid() {
|
|
addresses = append(addresses, addr)
|
|
}
|
|
case *dns.HTTPS:
|
|
for _, value := range record.SVCB.Value {
|
|
switch hint := value.(type) {
|
|
case *dns.SVCBIPv4Hint:
|
|
for _, ip := range hint.Hint {
|
|
addr := M.AddrFromIP(ip).Unmap()
|
|
if addr.IsValid() {
|
|
addresses = append(addresses, addr)
|
|
}
|
|
}
|
|
case *dns.SVCBIPv6Hint:
|
|
for _, ip := range hint.Hint {
|
|
addr := M.AddrFromIP(ip)
|
|
if addr.IsValid() {
|
|
addresses = append(addresses, addr)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return addresses
|
|
}
|
|
|
|
type inboundContextKey struct{}
|
|
|
|
func WithContext(ctx context.Context, inboundContext *InboundContext) context.Context {
|
|
return context.WithValue(ctx, (*inboundContextKey)(nil), inboundContext)
|
|
}
|
|
|
|
func ContextFrom(ctx context.Context) *InboundContext {
|
|
metadata := ctx.Value((*inboundContextKey)(nil))
|
|
if metadata == nil {
|
|
return nil
|
|
}
|
|
return metadata.(*InboundContext)
|
|
}
|
|
|
|
func ExtendContext(ctx context.Context) (context.Context, *InboundContext) {
|
|
var newMetadata InboundContext
|
|
if metadata := ContextFrom(ctx); metadata != nil {
|
|
newMetadata = *metadata
|
|
}
|
|
return WithContext(ctx, &newMetadata), &newMetadata
|
|
}
|
|
|
|
func OverrideContext(ctx context.Context) context.Context {
|
|
if metadata := ContextFrom(ctx); metadata != nil {
|
|
newMetadata := *metadata
|
|
return WithContext(ctx, &newMetadata)
|
|
}
|
|
return ctx
|
|
}
|