mirror of
https://github.com/SagerNet/sing-box.git
synced 2026-11-10 21:21:02 +08:00
Forward endpoint local flows to tun
This commit is contained in:
19 files changed
+160
-82
No files matched your search
@@ -0,0 +1,92 @@
|
||||
package adapter
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing-tun/gtcpip/header"
|
||||
"github.com/sagernet/sing/common/byteformats"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func JudgeHostFlow(ctx context.Context, networkManager NetworkManager, logger log.ContextLogger, network uint8, source netip.AddrPort, destination netip.AddrPort) tun.FlowVerdict {
|
||||
port := networkManager.HostPort()
|
||||
if port == nil {
|
||||
return tun.FlowVerdict{Action: tun.ActionAccept}
|
||||
}
|
||||
inet4Address, inet6Address := port.PortAddresses()
|
||||
hostAddress := inet4Address
|
||||
if destination.Addr().Is6() {
|
||||
hostAddress = inet6Address
|
||||
}
|
||||
networkName := flowNetworkName(network)
|
||||
if !hostAddress.IsValid() || networkName == "" {
|
||||
return tun.FlowVerdict{Action: tun.ActionAccept}
|
||||
}
|
||||
hostDestination := netip.AddrPortFrom(hostAddress, destination.Port())
|
||||
return tun.FlowVerdict{
|
||||
Action: tun.ActionFlow,
|
||||
Port: port,
|
||||
Destination: hostDestination,
|
||||
NewTracker: func() tun.FlowTracker {
|
||||
flowContext := log.ContextWithNewID(ctx)
|
||||
sourceAddress := M.SocksaddrFromNetIP(source)
|
||||
destinationAddress := M.SocksaddrFromNetIP(hostDestination)
|
||||
if networkName == N.NetworkICMP {
|
||||
sourceAddress.Port = 0
|
||||
destinationAddress.Port = 0
|
||||
}
|
||||
logger.InfoContext(flowContext, "forward ", networkName, " connection from ", sourceAddress, " to ", destinationAddress, " via tun")
|
||||
return NewFlowLogger(flowContext, logger)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func flowNetworkName(network uint8) string {
|
||||
switch network {
|
||||
case uint8(header.TCPProtocolNumber):
|
||||
return N.NetworkTCP
|
||||
case uint8(header.UDPProtocolNumber):
|
||||
return N.NetworkUDP
|
||||
case uint8(header.ICMPv4ProtocolNumber), uint8(header.ICMPv6ProtocolNumber):
|
||||
return N.NetworkICMP
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
var _ tun.FlowTracker = (*FlowLogger)(nil)
|
||||
|
||||
type FlowLogger struct {
|
||||
ctx context.Context
|
||||
logger log.ContextLogger
|
||||
upload atomic.Int64
|
||||
download atomic.Int64
|
||||
}
|
||||
|
||||
func NewFlowLogger(ctx context.Context, logger log.ContextLogger) *FlowLogger {
|
||||
return &FlowLogger{ctx: ctx, logger: logger}
|
||||
}
|
||||
|
||||
func (l *FlowLogger) AttachFlow(handle tun.FlowHandle) {
|
||||
}
|
||||
|
||||
func (l *FlowLogger) CountForward(n int) {
|
||||
l.upload.Add(int64(n))
|
||||
}
|
||||
|
||||
func (l *FlowLogger) CountReverse(n int) {
|
||||
l.download.Add(int64(n))
|
||||
}
|
||||
|
||||
func (l *FlowLogger) FlowEstablished() {
|
||||
}
|
||||
|
||||
func (l *FlowLogger) CloseFlow(reason tun.FlowCloseReason) {
|
||||
l.logger.DebugContext(l.ctx, "flow closed: ", reason,
|
||||
", upload ", byteformats.FormatBytes(uint64(l.upload.Load())), ", download ", byteformats.FormatBytes(uint64(l.download.Load())))
|
||||
}
|
||||
@@ -30,6 +30,8 @@ type NetworkManager interface {
|
||||
AutoRedirectOutputMarkFunc() control.Func
|
||||
RegisterBridgeInterface(interfaceName string)
|
||||
BridgeInterfaces() []string
|
||||
RegisterHostPort(port tun.RoutedPort)
|
||||
HostPort() tun.RoutedPort
|
||||
NetworkMonitor() tun.NetworkUpdateMonitor
|
||||
InterfaceMonitor() tun.DefaultInterfaceMonitor
|
||||
PackageManager() tun.PackageManager
|
||||
|
||||
+2
-10
@@ -7,7 +7,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing-tun/gtcpip/header"
|
||||
M "github.com/sagernet/sing/common/metadata"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
"github.com/sagernet/sing/common/x/list"
|
||||
@@ -50,15 +49,8 @@ type PreMatchResult struct {
|
||||
}
|
||||
|
||||
func JudgeFlow(router Router, metadata InboundContext, network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
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:
|
||||
networkName := flowNetworkName(network)
|
||||
if networkName == "" {
|
||||
return tun.FlowVerdict{Action: tun.ActionAccept}
|
||||
}
|
||||
metadata.Network = networkName
|
||||
|
||||
@@ -58,7 +58,7 @@ require (
|
||||
github.com/sagernet/sing-usbip v0.0.0-20260817040617-28bd42667eca
|
||||
github.com/sagernet/sing-vmess v0.2.9-0.20261108133243-b01463cef941
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261022222424-1688b52f8204
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261028024127-670967df7dbf
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215849-fdf0ad046586
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854
|
||||
github.com/spf13/cobra v1.10.2
|
||||
|
||||
@@ -346,8 +346,8 @@ github.com/sagernet/sing-vmess v0.2.9-0.20261108133243-b01463cef941 h1:QiLfQ/yZw
|
||||
github.com/sagernet/sing-vmess v0.2.9-0.20261108133243-b01463cef941/go.mod h1:P11scgTxMxVVQ8dlM27yNm3Cro40mD0+gHbnqrNGDuY=
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1 h1:XkJcivBC9V4wBjiGXIXZ229aZCU1hzcbp6kSkkyQ478=
|
||||
github.com/sagernet/smux v1.5.50-sing-box-mod.1/go.mod h1:NjhsCEWedJm7eFLyhuBgIEzwfhRmytrUoiLluxs5Sk8=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261022222424-1688b52f8204 h1:k25hl6yegTD3I3UEp95ZF09KDBiFsutUawV7vjRjQsg=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261022222424-1688b52f8204/go.mod h1:Z8Eql5l0q6mQ+etunojfaZxNJVhEkpbKGS/nnx9ZQpE=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261028024127-670967df7dbf h1:59b83P3sRDWJcTifDZpeVn4gZFropKsNdYWuPfhqI1w=
|
||||
github.com/sagernet/tailscale v1.102.1-sing-box-1.14-mod.5.0.20261028024127-670967df7dbf/go.mod h1:Z8Eql5l0q6mQ+etunojfaZxNJVhEkpbKGS/nnx9ZQpE=
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215849-fdf0ad046586 h1:lssrGZJRiO6s2ShbBjchpFsNml9cj/7G+aeEL57ZvVc=
|
||||
github.com/sagernet/wireguard-go v0.0.8-0.20261022215849-fdf0ad046586/go.mod h1:er10sELpmzLXq7S7Pbc1Zsbyapcr+/gxNAHKTo6fzVA=
|
||||
github.com/sagernet/ws v0.0.0-20231204124109-acfe8907c854 h1:6uUiZcDRnZSAegryaUGwPC/Fj13JSHwiTftrXhMmYOc=
|
||||
|
||||
@@ -125,6 +125,8 @@ func NewClientEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
Adapter: endpoint.NewAdapterWithDialerOptions(C.TypeMASQUEClient, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
|
||||
router: router,
|
||||
logger: logger,
|
||||
system: options.System,
|
||||
network: service.FromContext[adapter.NetworkManager](ctx),
|
||||
},
|
||||
ctx: ctx,
|
||||
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
|
||||
@@ -273,7 +275,7 @@ func (c *ClientEndpoint) DetachReturn(returnPath tun.Return) error {
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
return c.judgeFlow(c, c.state.Load().localAddresses, network, source, destination, firstPacket)
|
||||
return c.judgeFlow(c.ctx, c, c.state.Load().localAddresses, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) NewDNSPacket(payload []byte, source M.Socksaddr, destination M.Socksaddr, writer N.PacketWriter) {
|
||||
|
||||
@@ -30,6 +30,8 @@ type endpointBase struct {
|
||||
endpoint.Adapter
|
||||
router adapter.Router
|
||||
logger log.ContextLogger
|
||||
system bool
|
||||
network adapter.NetworkManager
|
||||
}
|
||||
|
||||
func newDeviceOptions(ctx context.Context, logger log.ContextLogger, handler tun.Handler, options option.MASQUEEndpointOptions, udpTimeout time.Duration, address []netip.Prefix) *device.Options {
|
||||
@@ -101,10 +103,13 @@ func (e *endpointBase) newDNSPacket(ctx context.Context, endpoint adapter.Endpoi
|
||||
e.router.HijackDNSPacket(ctx, payload, writer, metadata)
|
||||
}
|
||||
|
||||
func (e *endpointBase) judgeFlow(endpoint adapter.Endpoint, localAddresses []netip.Prefix, network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
func (e *endpointBase) judgeFlow(ctx context.Context, endpoint adapter.Endpoint, localAddresses []netip.Prefix, network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
if isLocalAddress(localAddresses, destination.Addr()) {
|
||||
if e.system {
|
||||
return tun.FlowVerdict{Action: tun.ActionAccept}
|
||||
}
|
||||
return adapter.JudgeHostFlow(ctx, e.network, e.logger, network, source, destination)
|
||||
}
|
||||
return adapter.JudgeFlow(e.router, adapter.InboundContext{Inbound: endpoint.Tag(), InboundType: endpoint.Type()}, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
|
||||
@@ -80,6 +80,8 @@ func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
Adapter: endpoint.NewAdapter(C.TypeMASQUEServer, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, nil),
|
||||
router: router,
|
||||
logger: logger,
|
||||
system: options.System,
|
||||
network: service.FromContext[adapter.NetworkManager](ctx),
|
||||
},
|
||||
ctx: ctx,
|
||||
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
|
||||
@@ -249,7 +251,7 @@ func (s *ServerEndpoint) DetachReturn(returnPath tun.Return) error {
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
return s.judgeFlow(s, s.localAddresses, network, source, destination, firstPacket)
|
||||
return s.judgeFlow(s.ctx, s, s.localAddresses, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) NewDNSPacket(payload []byte, source M.Socksaddr, destination M.Socksaddr, writer N.PacketWriter) {
|
||||
|
||||
@@ -111,6 +111,8 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
Adapter: endpoint.NewAdapterWithDialerOptions(C.TypeOpenConnect, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
|
||||
router: router,
|
||||
logger: logger,
|
||||
system: options.System,
|
||||
network: service.FromContext[adapter.NetworkManager](ctx),
|
||||
},
|
||||
loopContext: loopContext,
|
||||
cancelLoop: cancelLoop,
|
||||
@@ -569,7 +571,7 @@ func (e *Endpoint) DetachReturn(returnPath tun.Return) error {
|
||||
}
|
||||
|
||||
func (e *Endpoint) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
return judgeOpenConnectFlow(e.router, e.Tag(), e.Type(), e.state.Load().localAddresses, network, source, destination, firstPacket)
|
||||
return e.judgeFlow(e.loopContext, e, e.state.Load().localAddresses, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
func (e *Endpoint) NewDNSPacket(payload []byte, source M.Socksaddr, destination M.Socksaddr, writer N.PacketWriter) {
|
||||
|
||||
@@ -30,6 +30,8 @@ type endpointBase struct {
|
||||
endpoint.Adapter
|
||||
router adapter.Router
|
||||
logger log.ContextLogger
|
||||
system bool
|
||||
network adapter.NetworkManager
|
||||
}
|
||||
|
||||
func (e *endpointBase) newConnection(ctx context.Context, endpoint adapter.Endpoint, localAddresses []netip.Prefix, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||
@@ -91,13 +93,16 @@ func loopbackAddressFor(address netip.Addr) netip.Addr {
|
||||
return netip.IPv6Loopback()
|
||||
}
|
||||
|
||||
func judgeOpenConnectFlow(router adapter.Router, tag string, endpointType string, localAddresses []netip.Prefix, network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
func (e *endpointBase) judgeFlow(ctx context.Context, endpoint adapter.Endpoint, localAddresses []netip.Prefix, network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
for _, localPrefix := range localAddresses {
|
||||
if destination.Addr() == localPrefix.Addr() {
|
||||
if e.system {
|
||||
return tun.FlowVerdict{Action: tun.ActionAccept}
|
||||
}
|
||||
return adapter.JudgeHostFlow(ctx, e.network, e.logger, network, source, destination)
|
||||
}
|
||||
return adapter.JudgeFlow(router, adapter.InboundContext{Inbound: tag, InboundType: endpointType}, network, source, destination, firstPacket)
|
||||
}
|
||||
return adapter.JudgeFlow(e.router, adapter.InboundContext{Inbound: endpoint.Tag(), InboundType: endpoint.Type()}, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
func materialSource(name string, inlineValues []string, path string) (openconnect.Material, error) {
|
||||
|
||||
@@ -82,6 +82,8 @@ func NewClientEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
Adapter: endpoint.NewAdapterWithDialerOptions(C.TypeOpenVPNClient, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, options.DialerOptions),
|
||||
router: router,
|
||||
logger: logger,
|
||||
system: options.System,
|
||||
network: service.FromContext[adapter.NetworkManager](ctx),
|
||||
},
|
||||
ctx: ctx,
|
||||
loopContext: loopContext,
|
||||
@@ -752,7 +754,7 @@ func (c *ClientEndpoint) DetachReturn(returnPath tun.Return) error {
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
return judgeOpenVPNFlow(c.router, c.Tag(), c.Type(), c.state.Load().localAddresses, network, source, destination, firstPacket)
|
||||
return c.judgeFlow(c.ctx, c, c.state.Load().localAddresses, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
func (c *ClientEndpoint) NewDNSPacket(payload []byte, source M.Socksaddr, destination M.Socksaddr, writer N.PacketWriter) {
|
||||
|
||||
@@ -36,6 +36,8 @@ type endpointBase struct {
|
||||
endpoint.Adapter
|
||||
router adapter.Router
|
||||
logger log.ContextLogger
|
||||
system bool
|
||||
network adapter.NetworkManager
|
||||
}
|
||||
|
||||
func (e *endpointBase) newConnection(ctx context.Context, endpoint adapter.Endpoint, localAddresses []netip.Prefix, conn net.Conn, source M.Socksaddr, destination M.Socksaddr, onClose N.CloseHandlerFunc) {
|
||||
@@ -97,13 +99,16 @@ func loopbackAddressFor(address netip.Addr) netip.Addr {
|
||||
return netip.IPv6Loopback()
|
||||
}
|
||||
|
||||
func judgeOpenVPNFlow(router adapter.Router, tag string, endpointType string, localAddresses []netip.Prefix, network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
func (e *endpointBase) judgeFlow(ctx context.Context, endpoint adapter.Endpoint, localAddresses []netip.Prefix, network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
for _, localPrefix := range localAddresses {
|
||||
if destination.Addr() == localPrefix.Addr() {
|
||||
if e.system {
|
||||
return tun.FlowVerdict{Action: tun.ActionAccept}
|
||||
}
|
||||
return adapter.JudgeHostFlow(ctx, e.network, e.logger, network, source, destination)
|
||||
}
|
||||
return adapter.JudgeFlow(router, adapter.InboundContext{Inbound: tag, InboundType: endpointType}, network, source, destination, firstPacket)
|
||||
}
|
||||
return adapter.JudgeFlow(e.router, adapter.InboundContext{Inbound: endpoint.Tag(), InboundType: endpoint.Type()}, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
func keyDirectionValue(direction string) (int, error) {
|
||||
|
||||
@@ -80,6 +80,8 @@ func NewServerEndpoint(ctx context.Context, router adapter.Router, logger log.Co
|
||||
Adapter: endpoint.NewAdapter(C.TypeOpenVPNServer, tag, []string{N.NetworkTCP, N.NetworkUDP, N.NetworkICMP}, nil),
|
||||
router: router,
|
||||
logger: logger,
|
||||
system: options.System,
|
||||
network: service.FromContext[adapter.NetworkManager](ctx),
|
||||
},
|
||||
ctx: ctx,
|
||||
cancelLoop: cancelLoop,
|
||||
@@ -668,7 +670,7 @@ func (s *ServerEndpoint) DetachReturn(returnPath tun.Return) error {
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
return judgeOpenVPNFlow(s.router, s.Tag(), s.Type(), s.localAddresses, network, source, destination, firstPacket)
|
||||
return s.judgeFlow(s.ctx, s, s.localAddresses, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
func (s *ServerEndpoint) NewDNSPacket(payload []byte, source M.Socksaddr, destination M.Socksaddr, writer N.PacketWriter) {
|
||||
|
||||
@@ -46,8 +46,11 @@ func (t *Endpoint) UpstreamPort() any {
|
||||
func (t *Endpoint) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
inet4Address, inet6Address := t.PortAddresses()
|
||||
if destination.Addr() == inet4Address || destination.Addr() == inet6Address {
|
||||
if t.systemInterface {
|
||||
return tun.FlowVerdict{Action: tun.ActionAccept}
|
||||
}
|
||||
return adapter.JudgeHostFlow(t.ctx, t.network, t.logger, network, source, destination)
|
||||
}
|
||||
if t.started.Load() {
|
||||
tsFilter := t.wgEngine.GetFilter()
|
||||
if tsFilter != nil {
|
||||
|
||||
@@ -527,6 +527,9 @@ func (t *Inbound) Start(stage adapter.StartStage, scope *adapter.Scope) error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "starting TUN interface")
|
||||
}
|
||||
if routedPort, isRoutedPort := t.tunStack.(tun.RoutedPort); isRoutedPort {
|
||||
t.networkManager.RegisterHostPort(routedPort)
|
||||
}
|
||||
if t.autoRedirect != nil {
|
||||
scope.Add(t.autoRedirect.Close)
|
||||
monitor.Start("initialize auto-redirect")
|
||||
|
||||
@@ -46,6 +46,8 @@ type Endpoint struct {
|
||||
dnsRouter adapter.DNSRouter
|
||||
logger logger.ContextLogger
|
||||
localAddresses []netip.Prefix
|
||||
system bool
|
||||
network adapter.NetworkManager
|
||||
endpoint *wireguard.Endpoint
|
||||
onDemand bool
|
||||
bindAccess sync.Mutex
|
||||
@@ -60,6 +62,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
dnsRouter: service.FromContext[adapter.DNSRouter](ctx),
|
||||
logger: logger,
|
||||
localAddresses: options.Address,
|
||||
system: options.System,
|
||||
onDemand: options.OnDemand,
|
||||
}
|
||||
if options.Detour != "" && options.ListenPort != 0 {
|
||||
@@ -83,6 +86,7 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
udpTimeout = C.UDPTimeout
|
||||
}
|
||||
networkManager := service.FromContext[adapter.NetworkManager](ctx)
|
||||
ep.network = networkManager
|
||||
wgEndpoint, err := wireguard.NewEndpoint(wireguard.EndpointOptions{
|
||||
Context: ctx,
|
||||
Logger: logger,
|
||||
@@ -222,8 +226,11 @@ func (w *Endpoint) DetachReturn(returnPath tun.Return) error {
|
||||
func (w *Endpoint) JudgeFlow(network uint8, source netip.AddrPort, destination netip.AddrPort, firstPacket []byte) tun.FlowVerdict {
|
||||
for _, localPrefix := range w.localAddresses {
|
||||
if localPrefix.Contains(destination.Addr()) {
|
||||
if w.system {
|
||||
return tun.FlowVerdict{Action: tun.ActionAccept}
|
||||
}
|
||||
return adapter.JudgeHostFlow(w.ctx, w.network, w.logger, network, source, destination)
|
||||
}
|
||||
}
|
||||
return adapter.JudgeFlow(w.router, adapter.InboundContext{Inbound: w.Tag(), InboundType: w.Type()}, network, source, destination, firstPacket)
|
||||
}
|
||||
|
||||
@@ -1,76 +1,18 @@
|
||||
package route
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/sagernet/sing-box/adapter"
|
||||
"github.com/sagernet/sing-box/log"
|
||||
"github.com/sagernet/sing-tun"
|
||||
"github.com/sagernet/sing/common"
|
||||
"github.com/sagernet/sing/common/byteformats"
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
var (
|
||||
_ tun.FlowTracker = (*flowLogger)(nil)
|
||||
_ tun.FlowTracker = (*flowInterrupter)(nil)
|
||||
_ tun.FlowTracker = (*multiFlowTracker)(nil)
|
||||
)
|
||||
|
||||
type flowLogger struct {
|
||||
ctx context.Context
|
||||
logger log.ContextLogger
|
||||
network string
|
||||
source string
|
||||
destination string
|
||||
outbound adapter.Outbound
|
||||
createdAt time.Time
|
||||
upload atomic.Int64
|
||||
download atomic.Int64
|
||||
}
|
||||
|
||||
func newFlowLogger(ctx context.Context, logger log.ContextLogger, metadata adapter.InboundContext, outbound adapter.Outbound) *flowLogger {
|
||||
var source, destination string
|
||||
if metadata.Network == N.NetworkICMP {
|
||||
source = metadata.Source.AddrString()
|
||||
destination = metadata.Destination.AddrString()
|
||||
} else {
|
||||
source = metadata.Source.String()
|
||||
destination = metadata.Destination.String()
|
||||
}
|
||||
return &flowLogger{
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
network: metadata.Network,
|
||||
source: source,
|
||||
destination: destination,
|
||||
outbound: outbound,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *flowLogger) AttachFlow(handle tun.FlowHandle) {
|
||||
l.createdAt = time.Now()
|
||||
}
|
||||
|
||||
func (l *flowLogger) CountForward(n int) {
|
||||
l.upload.Add(int64(n))
|
||||
}
|
||||
|
||||
func (l *flowLogger) CountReverse(n int) {
|
||||
l.download.Add(int64(n))
|
||||
}
|
||||
|
||||
func (l *flowLogger) FlowEstablished() {
|
||||
}
|
||||
|
||||
func (l *flowLogger) CloseFlow(reason tun.FlowCloseReason) {
|
||||
l.logger.DebugContext(l.ctx, "flow closed: ", reason,
|
||||
", upload ", byteformats.FormatBytes(uint64(l.upload.Load())), ", download ", byteformats.FormatBytes(uint64(l.download.Load())))
|
||||
}
|
||||
|
||||
type multiFlowTracker struct {
|
||||
access sync.Mutex
|
||||
trackers []tun.FlowTracker
|
||||
|
||||
@@ -42,6 +42,7 @@ type NetworkManager struct {
|
||||
autoDetectInterface bool
|
||||
defaultOptions adapter.NetworkOptions
|
||||
autoRedirectOutputMark uint32
|
||||
hostPort common.TypedValue[tun.RoutedPort]
|
||||
bridgeInterfaceAccess sync.Mutex
|
||||
bridgeInterfaces []string
|
||||
networkMonitor tun.NetworkUpdateMonitor
|
||||
@@ -394,6 +395,17 @@ func (r *NetworkManager) AutoRedirectOutputMark() uint32 {
|
||||
return r.autoRedirectOutputMark
|
||||
}
|
||||
|
||||
func (r *NetworkManager) RegisterHostPort(port tun.RoutedPort) {
|
||||
if r.hostPort.Load() != nil {
|
||||
return
|
||||
}
|
||||
r.hostPort.Store(port)
|
||||
}
|
||||
|
||||
func (r *NetworkManager) HostPort() tun.RoutedPort {
|
||||
return r.hostPort.Load()
|
||||
}
|
||||
|
||||
func (r *NetworkManager) RegisterBridgeInterface(interfaceName string) {
|
||||
r.bridgeInterfaceAccess.Lock()
|
||||
defer r.bridgeInterfaceAccess.Unlock()
|
||||
|
||||
+1
-1
@@ -540,7 +540,7 @@ func (r *Router) preMatchFlow(ctx context.Context, metadata *adapter.InboundCont
|
||||
result.NewTracker = func() tun.FlowTracker {
|
||||
r.logger.InfoContext(ctx, "pre-match: forward ", metadataCopy.Network, " connection from ", metadataCopy.Source, " to ", metadataCopy.Destination, " via outbound/", outbound.Type(), "[", outbound.Tag(), "]")
|
||||
flowTrackers := make([]tun.FlowTracker, 0, len(r.trackers)+2)
|
||||
flowTrackers = append(flowTrackers, newFlowLogger(ctx, r.logger, metadataCopy, outbound))
|
||||
flowTrackers = append(flowTrackers, adapter.NewFlowLogger(ctx, r.logger))
|
||||
flowInterrupter := newFlowInterrupter(chain)
|
||||
if flowInterrupter != nil {
|
||||
flowTrackers = append(flowTrackers, flowInterrupter)
|
||||
|
||||
Reference in new issue
Block a user