Files
sing-box-extended-mirror/adapter/router.go
T

155 lines
4.9 KiB
Go
Raw Normal View History

2022-06-30 21:27:56 +08:00
package adapter
import (
"context"
2024-10-25 22:24:19 +08:00
"net"
2026-07-06 14:26:32 +08:00
"net/netip"
2026-07-08 00:10:00 +08:00
"time"
2022-06-30 21:27:56 +08:00
2025-02-17 22:00:57 +08:00
"github.com/sagernet/sing-tun"
2026-07-06 14:26:32 +08:00
"github.com/sagernet/sing-tun/gtcpip/header"
M "github.com/sagernet/sing/common/metadata"
2023-12-01 13:24:12 +08:00
N "github.com/sagernet/sing/common/network"
2024-06-07 15:55:21 +08:00
"github.com/sagernet/sing/common/x/list"
2022-07-07 21:47:21 +08:00
2024-06-07 15:55:21 +08:00
"go4.org/netipx"
2022-06-30 21:27:56 +08:00
)
type Router interface {
2024-11-10 16:46:59 +08:00
Lifecycle
ConnectionRouter
2026-07-06 23:40:48 +08:00
PreMatch(metadata InboundContext, firstPacket []byte) PreMatchResult
2026-07-19 13:04:55 +08:00
HijackDNSPacket(ctx context.Context, payload []byte, writer N.PacketWriter, metadata InboundContext)
2024-10-21 23:38:34 +08:00
ConnectionRouterEx
2023-12-01 13:24:12 +08:00
RuleSet(tag string) (RuleSet, bool)
2022-07-19 22:16:49 +08:00
Rules() []Rule
2026-01-04 02:53:33 +08:00
NeedFindProcess() bool
2026-03-03 20:59:13 +08:00
NeedFindNeighbor() bool
NeighborResolver() NeighborResolver
2025-04-03 20:01:08 +08:00
AppendTracker(tracker ConnectionTracker)
2024-11-10 12:11:21 +08:00
ResetNetwork()
2022-07-02 14:07:50 +08:00
}
2026-07-06 14:26:32 +08:00
type PreMatchAction uint8
const (
PreMatchContinue PreMatchAction = iota
PreMatchFlow
PreMatchReject
PreMatchDrop
PreMatchBypass
2026-07-19 13:04:55 +08:00
PreMatchHijackDNS
2026-07-06 14:26:32 +08:00
)
type PreMatchResult struct {
Action PreMatchAction
Outbound Outbound
Destination netip.AddrPort
2026-07-08 00:10:00 +08:00
UDPTimeout time.Duration
2026-07-06 23:40:48 +08:00
NewTracker func() tun.FlowTracker
2026-07-06 14:26:32 +08:00
}
2026-07-06 23:40:48 +08:00
func JudgeFlow(router Router, inbound string, inboundType string, network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
2026-07-06 14:26:32 +08:00
var networkName string
switch network {
case uint8(header.TCPProtocolNumber):
networkName = N.NetworkTCP
case uint8(header.UDPProtocolNumber):
networkName = N.NetworkUDP
case uint8(header.ICMPv4ProtocolNumber), uint8(header.ICMPv6ProtocolNumber):
networkName = N.NetworkICMP
default:
return tun.FlowVerdict{Action: tun.ActionAccept}
}
metadata := InboundContext{
Inbound: inbound,
InboundType: inboundType,
Network: networkName,
Source: M.SocksaddrFromNetIP(source),
Destination: M.SocksaddrFromNetIP(destination),
}
if networkName == N.NetworkICMP {
metadata.Source.Port = 0
metadata.Destination.Port = 0
}
2026-07-06 23:40:48 +08:00
result := router.PreMatch(metadata, firstPacket)
2026-07-06 14:26:32 +08:00
switch result.Action {
case PreMatchFlow:
port, isPort := result.Outbound.(tun.Port)
if !isPort {
return tun.FlowVerdict{Action: tun.ActionAccept}
}
2026-07-08 00:10:00 +08:00
verdict := tun.FlowVerdict{Action: tun.ActionFlow, Port: port, UDPTimeout: result.UDPTimeout, NewTracker: result.NewTracker}
2026-07-06 14:26:32 +08:00
if result.Destination.IsValid() {
destinationPort := result.Destination.Port()
if networkName == N.NetworkICMP {
destinationPort = destination.Port()
}
verdict.Destination = netip.AddrPortFrom(result.Destination.Addr(), destinationPort)
}
return verdict
case PreMatchReject:
return tun.FlowVerdict{Action: tun.ActionReject}
case PreMatchDrop:
return tun.FlowVerdict{Action: tun.ActionDrop}
case PreMatchBypass:
return tun.FlowVerdict{Action: tun.ActionBypass}
2026-07-19 13:04:55 +08:00
case PreMatchHijackDNS:
return tun.FlowVerdict{Action: tun.ActionHijackDNS}
2026-07-06 14:26:32 +08:00
default:
return tun.FlowVerdict{Action: tun.ActionAccept}
}
}
2024-11-10 16:46:59 +08:00
type ConnectionTracker interface {
RoutedConnection(ctx context.Context, conn net.Conn, metadata InboundContext, matchedRule Rule, matchOutbound Outbound) net.Conn
RoutedPacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext, matchedRule Rule, matchOutbound Outbound) N.PacketConn
2026-07-06 23:40:48 +08:00
RoutedFlow(ctx context.Context, metadata InboundContext, matchedRule Rule, matchOutbound Outbound) tun.FlowTracker
2024-11-10 16:46:59 +08:00
}
2024-10-21 23:38:34 +08:00
// Deprecated: Use ConnectionRouterEx instead.
type ConnectionRouter interface {
RouteConnection(ctx context.Context, conn net.Conn, metadata InboundContext) error
RoutePacketConnection(ctx context.Context, conn N.PacketConn, metadata InboundContext) error
2023-02-08 16:28:52 +08:00
}
2024-10-21 23:38:34 +08:00
type ConnectionRouterEx interface {
ConnectionRouter
RouteConnectionEx(ctx context.Context, conn net.Conn, metadata InboundContext, onClose N.CloseHandlerFunc)
RoutePacketConnectionEx(ctx context.Context, conn N.PacketConn, metadata InboundContext, onClose N.CloseHandlerFunc)
2023-12-01 13:24:12 +08:00
}
type RuleSet interface {
2024-06-07 15:55:21 +08:00
Name() string
2024-10-25 22:24:19 +08:00
StartContext(ctx context.Context, startContext *HTTPStartContext) error
2023-12-01 13:24:12 +08:00
Metadata() RuleSetMetadata
2024-06-07 15:55:21 +08:00
ExtractIPSet() []*netipx.IPSet
IncRef()
DecRef()
Cleanup()
RegisterCallback(callback RuleSetUpdateCallback) *list.Element[RuleSetUpdateCallback]
UnregisterCallback(element *list.Element[RuleSetUpdateCallback])
2023-12-01 13:24:12 +08:00
Close() error
HeadlessRule
}
2024-06-07 15:55:21 +08:00
type RuleSetUpdateCallback func(it RuleSet)
type DNSRuleSetUpdateValidator interface {
ValidateRuleSetMetadataUpdate(tag string, metadata RuleSetMetadata) error
}
// ip_version is not a headless-rule item, so ContainsIPVersionRule is intentionally absent.
2023-12-01 13:24:12 +08:00
type RuleSetMetadata struct {
ContainsProcessRule bool
ContainsWIFIRule bool
ContainsIPCIDRRule bool
ContainsDNSQueryTypeRule bool
// ContainsNonIPCIDRRule signals that the rule-set carries at least one sub-rule
// with a predicate other than destination ip_cidr / ip_set, so it can contribute
// to DNS pre-response matching. A rule-set where this is false and
// ContainsIPCIDRRule is true is "pure-IP" and matches nothing before a DNS
// response is available.
ContainsNonIPCIDRRule bool
2023-12-01 13:24:12 +08:00
}