Improve network reset

This commit is contained in:
世界
2026-08-30 17:41:43 +08:00
parent 3afd290278
commit e4c8b49eaf
26 changed files with 250 additions and 62 deletions
+1
View File
@@ -14,6 +14,7 @@ import (
type Searcher interface { type Searcher interface {
FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*adapter.ConnectionOwner, error) FindProcessInfo(ctx context.Context, network string, source netip.AddrPort, destination netip.AddrPort) (*adapter.ConnectionOwner, error)
ResetCache()
Close() error Close() error
} }
+3
View File
@@ -23,6 +23,9 @@ func NewSearcher(config Config) (Searcher, error) {
return &androidSearcher{config.PackageManager}, nil return &androidSearcher{config.PackageManager}, nil
} }
func (s *androidSearcher) ResetCache() {
}
func (s *androidSearcher) Close() error { func (s *androidSearcher) Close() error {
return nil return nil
} }
+4
View File
@@ -20,6 +20,10 @@ func NewSearcher(_ Config) (Searcher, error) {
return &darwinSearcher{}, nil return &darwinSearcher{}, nil
} }
func (d *darwinSearcher) ResetCache() {
sharedDarwinConnectionFinder.resetCache()
}
func (d *darwinSearcher) Close() error { func (d *darwinSearcher) Close() error {
return nil return nil
} }
+6
View File
@@ -119,6 +119,12 @@ func (f *darwinConnectionFinder) find(network string, source netip.AddrPort, des
return nil, ErrNotFound return nil, ErrNotFound
} }
func (f *darwinConnectionFinder) resetCache() {
f.access.Lock()
defer f.access.Unlock()
clear(f.snapshots)
}
func (f *darwinConnectionFinder) loadSnapshot(network string, forceRefresh bool) (darwinSnapshot, bool, error) { func (f *darwinConnectionFinder) loadSnapshot(network string, forceRefresh bool) (darwinSnapshot, bool, error) {
f.access.Lock() f.access.Lock()
defer f.access.Unlock() defer f.access.Unlock()
+4
View File
@@ -35,6 +35,10 @@ func NewSearcher(config Config) (Searcher, error) {
return searcher, nil return searcher, nil
} }
func (s *linuxSearcher) ResetCache() {
s.processPathCache.cache.Purge()
}
func (s *linuxSearcher) Close() error { func (s *linuxSearcher) Close() error {
var errs []error var errs []error
for _, conn := range s.diagConns { for _, conn := range s.diagConns {
+3
View File
@@ -28,6 +28,9 @@ func initWin32API() error {
return winiphlpapi.LoadExtendedTable() return winiphlpapi.LoadExtendedTable()
} }
func (s *windowsSearcher) ResetCache() {
}
func (s *windowsSearcher) Close() error { func (s *windowsSearcher) Close() error {
return nil return nil
} }
+20 -6
View File
@@ -10,6 +10,7 @@ import (
"net/url" "net/url"
"strconv" "strconv"
"sync" "sync"
"sync/atomic"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
@@ -45,6 +46,8 @@ type HTTPSTransport struct {
dialer N.Dialer dialer N.Dialer
destination *url.URL destination *url.URL
headers http.Header headers http.Header
serverAddr M.Socksaddr
fallback *atomic.Bool
transportAccess sync.Mutex transportAccess sync.Mutex
transport *HTTPSTransportWrapper transport *HTTPSTransportWrapper
transportResetAt time.Time transportResetAt time.Time
@@ -123,13 +126,20 @@ func NewHTTPSRaw(
if tlsConfig != nil { if tlsConfig != nil {
dialer = tls.NewDialer(dialer, tlsConfig) dialer = tls.NewDialer(dialer, tlsConfig)
} }
fallback := new(atomic.Bool)
if destination.Scheme == "http" {
// plain HTTP DoH used by Tailscale
fallback.Store(true)
}
return &HTTPSTransport{ return &HTTPSTransport{
TransportAdapter: adapter, TransportAdapter: adapter,
logger: logger, logger: logger,
dialer: dialer, dialer: dialer,
destination: destination, destination: destination,
headers: headers, headers: headers,
transport: NewHTTPSTransportWrapper(dialer, serverAddr, destination), serverAddr: serverAddr,
fallback: fallback,
transport: NewHTTPSTransportWrapper(dialer, serverAddr, fallback),
} }
} }
@@ -148,8 +158,14 @@ func (t *HTTPSTransport) Close() error {
func (t *HTTPSTransport) Reset() { func (t *HTTPSTransport) Reset() {
t.transportAccess.Lock() t.transportAccess.Lock()
defer t.transportAccess.Unlock() defer t.transportAccess.Unlock()
t.transport.CloseIdleConnections() t.resetTransportLocked()
t.transport = t.transport.Clone() }
func (t *HTTPSTransport) resetTransportLocked() {
oldTransport := t.transport
t.transport = NewHTTPSTransportWrapper(t.dialer, t.serverAddr, t.fallback)
t.transportResetAt = time.Now()
oldTransport.Close()
} }
func (t *HTTPSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { func (t *HTTPSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
@@ -162,9 +178,7 @@ func (t *HTTPSTransport) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS
if t.transportResetAt.After(startAt) { if t.transportResetAt.After(startAt) {
return nil, err return nil, err
} }
t.transport.CloseIdleConnections() t.resetTransportLocked()
t.transport = t.transport.Clone()
t.transportResetAt = time.Now()
} }
return nil, err return nil, err
} }
+78 -40
View File
@@ -5,7 +5,7 @@ import (
"errors" "errors"
"net" "net"
"net/http" "net/http"
"net/url" "sync"
"sync/atomic" "sync/atomic"
"github.com/sagernet/sing-box/common/tls" "github.com/sagernet/sing-box/common/tls"
@@ -22,42 +22,50 @@ type HTTPSTransportWrapper struct {
http2Transport *http2.Transport http2Transport *http2.Transport
httpTransport *http.Transport httpTransport *http.Transport
fallback *atomic.Bool fallback *atomic.Bool
connAccess sync.Mutex
connections map[*httpsTrackedConn]struct{}
closed bool
} }
func NewHTTPSTransportWrapper(dialer N.Dialer, serverAddr M.Socksaddr, destination *url.URL) *HTTPSTransportWrapper { func NewHTTPSTransportWrapper(dialer N.Dialer, serverAddr M.Socksaddr, fallback *atomic.Bool) *HTTPSTransportWrapper {
var fallback atomic.Bool wrapper := &HTTPSTransportWrapper{
if destination.Scheme == "http" { fallback: fallback,
// plain HTTP DoH used by Tailscale connections: make(map[*httpsTrackedConn]struct{}),
fallback.Store(true)
} }
return &HTTPSTransportWrapper{ wrapper.http2Transport = &http2.Transport{
http2Transport: &http2.Transport{ DialTLSContext: func(ctx context.Context, _, _ string, _ *tls.STDConfig) (net.Conn, error) {
DialTLSContext: func(ctx context.Context, _, _ string, _ *tls.STDConfig) (net.Conn, error) { resultConn, err := dialer.DialContext(ctx, N.NetworkTCP, serverAddr)
resultConn, err := dialer.DialContext(ctx, N.NetworkTCP, serverAddr) if err != nil {
if err != nil { return nil, err
return nil, err }
if tlsConn, isTLSConn := resultConn.(tls.Conn); isTLSConn {
state := tlsConn.ConnectionState()
if state.NegotiatedProtocol != http2.NextProtoTLS {
tlsConn.Close()
fallback.Store(true)
return nil, errFallback
} }
if tlsConn, isTLSConn := resultConn.(tls.Conn); isTLSConn { }
state := tlsConn.ConnectionState() return wrapper.trackConn(resultConn)
if state.NegotiatedProtocol != http2.NextProtoTLS {
tlsConn.Close()
fallback.Store(true)
return nil, errFallback
}
}
return resultConn, nil
},
}, },
httpTransport: &http.Transport{
DialContext: func(ctx context.Context, _, addr string) (net.Conn, error) {
return dialer.DialContext(ctx, N.NetworkTCP, serverAddr)
},
DialTLSContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
return dialer.DialContext(ctx, N.NetworkTCP, serverAddr)
},
},
fallback: &fallback,
} }
wrapper.httpTransport = &http.Transport{
DialContext: func(ctx context.Context, _, addr string) (net.Conn, error) {
resultConn, err := dialer.DialContext(ctx, N.NetworkTCP, serverAddr)
if err != nil {
return nil, err
}
return wrapper.trackConn(resultConn)
},
DialTLSContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
resultConn, err := dialer.DialContext(ctx, N.NetworkTCP, serverAddr)
if err != nil {
return nil, err
}
return wrapper.trackConn(resultConn)
},
}
return wrapper
} }
func (h *HTTPSTransportWrapper) RoundTrip(request *http.Request) (*http.Response, error) { func (h *HTTPSTransportWrapper) RoundTrip(request *http.Request) (*http.Response, error) {
@@ -74,17 +82,47 @@ func (h *HTTPSTransportWrapper) RoundTrip(request *http.Request) (*http.Response
return response, nil return response, nil
} }
func (h *HTTPSTransportWrapper) CloseIdleConnections() { func (h *HTTPSTransportWrapper) trackConn(conn net.Conn) (net.Conn, error) {
trackedConn := &httpsTrackedConn{Conn: conn, wrapper: h}
h.connAccess.Lock()
if h.closed {
h.connAccess.Unlock()
conn.Close()
return nil, net.ErrClosed
}
h.connections[trackedConn] = struct{}{}
h.connAccess.Unlock()
return trackedConn, nil
}
func (h *HTTPSTransportWrapper) Close() {
h.connAccess.Lock()
if h.closed {
h.connAccess.Unlock()
return
}
h.closed = true
connections := make([]*httpsTrackedConn, 0, len(h.connections))
for trackedConn := range h.connections {
connections = append(connections, trackedConn)
}
h.connections = nil
h.connAccess.Unlock()
for _, trackedConn := range connections {
trackedConn.Conn.Close()
}
h.http2Transport.CloseIdleConnections() h.http2Transport.CloseIdleConnections()
h.httpTransport.CloseIdleConnections() h.httpTransport.CloseIdleConnections()
} }
func (h *HTTPSTransportWrapper) Clone() *HTTPSTransportWrapper { type httpsTrackedConn struct {
return &HTTPSTransportWrapper{ net.Conn
httpTransport: h.httpTransport, wrapper *HTTPSTransportWrapper
http2Transport: &http2.Transport{ }
DialTLSContext: h.http2Transport.DialTLSContext,
}, func (c *httpsTrackedConn) Close() error {
fallback: h.fallback, c.wrapper.connAccess.Lock()
} delete(c.wrapper.connections, c)
c.wrapper.connAccess.Unlock()
return c.Conn.Close()
} }
+3
View File
@@ -148,6 +148,9 @@ func (t *Transport) Reset() {
} }
} }
t.system.reset() t.system.reset()
if t.resolved != nil {
t.resolved.Reset()
}
if t.dhcpTransport != nil { if t.dhcpTransport != nil {
t.dhcpTransport.Reset() t.dhcpTransport.Reset()
} }
+1
View File
@@ -9,6 +9,7 @@ import (
type ResolvedResolver interface { type ResolvedResolver interface {
Start() error Start() error
Close() error Close() error
Reset()
Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error)
ExchangeAsync(ctx context.Context, message *mDNS.Msg, callback func(response *mDNS.Msg, err error)) ExchangeAsync(ctx context.Context, message *mDNS.Msg, callback func(response *mDNS.Msg, err error))
} }
@@ -134,6 +134,19 @@ func (t *DBusResolvedResolver) Close() error {
return closeErr return closeErr
} }
func (t *DBusResolvedResolver) Reset() {
serverSet := t.savedServerSet.Load()
if serverSet == nil {
return
}
for _, server := range serverSet.servers {
server.primaryTransport.Reset()
if server.fallbackTransport != nil {
server.fallbackTransport.Reset()
}
}
}
func (t *DBusResolvedResolver) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) { func (t *DBusResolvedResolver) Exchange(ctx context.Context, message *mDNS.Msg) (*mDNS.Msg, error) {
serverSet := t.savedServerSet.Load() serverSet := t.savedServerSet.Load()
if serverSet == nil { if serverSet == nil {
+2 -2
View File
@@ -47,8 +47,8 @@ require (
github.com/sagernet/sing v0.9.0-beta.3 github.com/sagernet/sing v0.9.0-beta.3
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3
github.com/sagernet/sing-mux v0.3.5 github.com/sagernet/sing-mux v0.3.5
github.com/sagernet/sing-openconnect v0.0.0-20260718163953-a1c7815e4f04 github.com/sagernet/sing-openconnect v0.0.0-20260719094202-dc28b269c7ce
github.com/sagernet/sing-openvpn v0.0.0-20260718163953-26ecbeb6352c github.com/sagernet/sing-openvpn v0.0.0-20260719094204-c57d60b5c5a4
github.com/sagernet/sing-quic v0.6.4-0.20260803041931-6c84c468bea2 github.com/sagernet/sing-quic v0.6.4-0.20260803041931-6c84c468bea2
github.com/sagernet/sing-shadowsocks v0.2.8 github.com/sagernet/sing-shadowsocks v0.2.8
github.com/sagernet/sing-shadowsocks2 v0.2.1 github.com/sagernet/sing-shadowsocks2 v0.2.1
+4 -4
View File
@@ -285,10 +285,10 @@ github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3 h1:3y6
github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg= github.com/sagernet/sing-cloudflared v0.1.3-0.20260706062323-d9787e794aa3/go.mod h1:XEqEDYRCAYLaoPjZ1ifVWJg5iWAJHL2gOAXe/PM28Cg=
github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONfhI= github.com/sagernet/sing-mux v0.3.5 h1:RHnhVEc+SFqkrK4xMygYjDwwLhzp2Bj3lztSukONfhI=
github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk= github.com/sagernet/sing-mux v0.3.5/go.mod h1:QvlKMyNBNrQoyX4x+gq028uPbLM2XeRpWtDsWBJbFSk=
github.com/sagernet/sing-openconnect v0.0.0-20260718163953-a1c7815e4f04 h1:HIb3Tu19qqH5fD5xnyyHb6zJaETIsnXamb/hWTtxil8= github.com/sagernet/sing-openconnect v0.0.0-20260719094202-dc28b269c7ce h1:uPyEKbqEyGaJoKxQtiS+T9ZTrioL0Vl5Ko3i6iTpV2Y=
github.com/sagernet/sing-openconnect v0.0.0-20260718163953-a1c7815e4f04/go.mod h1:EIzh5HtImfQJxPKXFwS9lyMnmMy4aCQCx7ntQ4u41Gs= github.com/sagernet/sing-openconnect v0.0.0-20260719094202-dc28b269c7ce/go.mod h1:EIzh5HtImfQJxPKXFwS9lyMnmMy4aCQCx7ntQ4u41Gs=
github.com/sagernet/sing-openvpn v0.0.0-20260718163953-26ecbeb6352c h1:EhwLZF3IUyDj4uZ7vkUZAI7GymXCeOCwiseuOTsFjp8= github.com/sagernet/sing-openvpn v0.0.0-20260719094204-c57d60b5c5a4 h1:3H1pOsE5IRzr2U+oUTabPrvryj7xg1CEmOnMMwsQSQA=
github.com/sagernet/sing-openvpn v0.0.0-20260718163953-26ecbeb6352c/go.mod h1:CmTGnS5ijVSqFQV1dTq4WvFLUoz7bk9xasBPsX8NcYo= github.com/sagernet/sing-openvpn v0.0.0-20260719094204-c57d60b5c5a4/go.mod h1:CmTGnS5ijVSqFQV1dTq4WvFLUoz7bk9xasBPsX8NcYo=
github.com/sagernet/sing-quic v0.6.4-0.20260803041931-6c84c468bea2 h1:XhJro6+Ou+WOPjfs22m14lY7Sh6sWPm/f0QiyFUgM60= github.com/sagernet/sing-quic v0.6.4-0.20260803041931-6c84c468bea2 h1:XhJro6+Ou+WOPjfs22m14lY7Sh6sWPm/f0QiyFUgM60=
github.com/sagernet/sing-quic v0.6.4-0.20260803041931-6c84c468bea2/go.mod h1:9k+dzGsWMttUGldBzq3dU792YHXzW6NgfbOGltnXq+0= github.com/sagernet/sing-quic v0.6.4-0.20260803041931-6c84c468bea2/go.mod h1:9k+dzGsWMttUGldBzq3dU792YHXzW6NgfbOGltnXq+0=
github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE= github.com/sagernet/sing-shadowsocks v0.2.8 h1:PURj5PRoAkqeHh2ZW205RWzN9E9RtKCVCzByXruQWfE=
+4
View File
@@ -77,6 +77,10 @@ func (i *Inbound) Start(stage adapter.StartStage) error {
return i.listener.Start() return i.listener.Start()
} }
func (i *Inbound) InterfaceUpdated() {
i.udpNat.Purge()
}
func (i *Inbound) Close() error { func (i *Inbound) Close() error {
return i.listener.Close() return i.listener.Close()
} }
+23 -9
View File
@@ -29,10 +29,11 @@ func RegisterOutbound(registry *outbound.Registry) {
} }
var ( var (
_ N.ParallelDialer = (*Outbound)(nil) _ N.ParallelDialer = (*Outbound)(nil)
_ dialer.ParallelNetworkDialer = (*Outbound)(nil) _ dialer.ParallelNetworkDialer = (*Outbound)(nil)
_ dialer.DirectDialer = (*Outbound)(nil) _ dialer.DirectDialer = (*Outbound)(nil)
_ adapter.FlowOutbound = (*Outbound)(nil) _ adapter.FlowOutbound = (*Outbound)(nil)
_ adapter.InterfaceUpdateListener = (*Outbound)(nil)
) )
type Outbound struct { type Outbound struct {
@@ -88,30 +89,43 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
func (h *Outbound) Start(stage adapter.StartStage) error { func (h *Outbound) Start(stage adapter.StartStage) error {
switch stage { switch stage {
case adapter.StartStatePostStart, adapter.StartStateStarted: case adapter.StartStatePostStart, adapter.StartStateStarted:
h.fetchMyAddresses() if len(h.myAddresses.Load()) == 0 {
h.fetchMyAddresses()
}
} }
return nil return nil
} }
func (h *Outbound) fetchMyAddresses() { func (h *Outbound) fetchMyAddresses() {
if len(h.myAddresses.Load()) > 0 {
return
}
myInterfaceNames := h.network.InterfaceMonitor().MyInterfaces() myInterfaceNames := h.network.InterfaceMonitor().MyInterfaces()
if len(myInterfaceNames) == 0 { if len(myInterfaceNames) == 0 {
return return
} }
var myAddresses []netip.Prefix var (
myAddresses []netip.Prefix
found bool
)
for _, myInterfaceName := range myInterfaceNames { for _, myInterfaceName := range myInterfaceNames {
myInterface, err := h.network.InterfaceFinder().ByName(myInterfaceName) myInterface, err := h.network.InterfaceFinder().ByName(myInterfaceName)
if err != nil { if err != nil {
continue continue
} }
found = true
myAddresses = append(myAddresses, myInterface.Addresses...) myAddresses = append(myAddresses, myInterface.Addresses...)
} }
if !found {
return
}
h.myAddresses.Store(myAddresses) h.myAddresses.Store(myAddresses)
} }
func (h *Outbound) InterfaceUpdated() {
h.fetchMyAddresses()
if h.icmpPort != nil {
h.icmpPort.Close()
}
}
func (h *Outbound) isMyLoopbackAddress(addresses ...netip.Addr) bool { func (h *Outbound) isMyLoopbackAddress(addresses ...netip.Addr) bool {
for _, prefix := range h.myAddresses.Load() { for _, prefix := range h.myAddresses.Load() {
for _, address := range addresses { for _, address := range addresses {
+15 -1
View File
@@ -28,7 +28,10 @@ func RegisterURLTest(registry *outbound.Registry) {
outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest) outbound.Register[option.URLTestOutboundOptions](registry, C.TypeURLTest, NewURLTest)
} }
var _ adapter.OutboundGroup = (*URLTest)(nil) var (
_ adapter.OutboundGroup = (*URLTest)(nil)
_ adapter.InterfaceUpdateListener = (*URLTest)(nil)
)
type URLTest struct { type URLTest struct {
outbound.Adapter outbound.Adapter
@@ -118,6 +121,17 @@ func (s *URLTest) PerformUpdateCheck() {
s.group.performUpdateCheck() s.group.performUpdateCheck()
} }
func (s *URLTest) InterfaceUpdated() {
group := s.group
if group == nil {
return
}
if group.pause.IsDevicePaused() || group.pause.IsNetworkPaused() {
return
}
go group.CheckOutbounds(true)
}
func (s *URLTest) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { func (s *URLTest) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
s.group.Touch() s.group.Touch()
var outbound adapter.Outbound var outbound adapter.Outbound
+5
View File
@@ -34,6 +34,7 @@ import (
var ( var (
_ adapter.OutboundWithPreferredRoutes = (*Endpoint)(nil) _ adapter.OutboundWithPreferredRoutes = (*Endpoint)(nil)
_ adapter.FlowOutbound = (*Endpoint)(nil) _ adapter.FlowOutbound = (*Endpoint)(nil)
_ adapter.InterfaceUpdateListener = (*Endpoint)(nil)
_ dialer.PacketDialerWithDestination = (*Endpoint)(nil) _ dialer.PacketDialerWithDestination = (*Endpoint)(nil)
_ tun.Port = (*Endpoint)(nil) _ tun.Port = (*Endpoint)(nil)
) )
@@ -396,6 +397,10 @@ func (e *Endpoint) Close() error {
return err return err
} }
func (e *Endpoint) InterfaceUpdated() {
e.client.RestartSession()
}
func (e *Endpoint) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction { func (e *Endpoint) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction {
return adapter.PreMatchFlow return adapter.PreMatchFlow
} }
+5
View File
@@ -32,6 +32,7 @@ import (
var ( var (
_ adapter.OutboundWithPreferredRoutes = (*ClientEndpoint)(nil) _ adapter.OutboundWithPreferredRoutes = (*ClientEndpoint)(nil)
_ adapter.FlowOutbound = (*ClientEndpoint)(nil) _ adapter.FlowOutbound = (*ClientEndpoint)(nil)
_ adapter.InterfaceUpdateListener = (*ClientEndpoint)(nil)
_ dialer.PacketDialerWithDestination = (*ClientEndpoint)(nil) _ dialer.PacketDialerWithDestination = (*ClientEndpoint)(nil)
_ tun.Port = (*ClientEndpoint)(nil) _ tun.Port = (*ClientEndpoint)(nil)
) )
@@ -453,6 +454,10 @@ func (c *ClientEndpoint) Close() error {
return err return err
} }
func (c *ClientEndpoint) InterfaceUpdated() {
c.client.RestartSession()
}
func (c *ClientEndpoint) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction { func (c *ClientEndpoint) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction {
return adapter.PreMatchFlow return adapter.PreMatchFlow
} }
+4
View File
@@ -85,6 +85,10 @@ func (t *TProxy) Start(stage adapter.StartStage) error {
return err return err
} }
func (t *TProxy) InterfaceUpdated() {
t.udpNat.Purge()
}
func (t *TProxy) Close() error { func (t *TProxy) Close() error {
_ = t.udpNat.Close() _ = t.udpNat.Close()
return t.listener.Close() return t.listener.Close()
+7
View File
@@ -32,9 +32,12 @@ type Outbound struct {
serverAddr M.Socksaddr serverAddr M.Socksaddr
} }
var _ adapter.InterfaceUpdateListener = (*Outbound)(nil)
type snellClient interface { type snellClient interface {
snellprotocol.Method snellprotocol.Method
DialContext(ctx context.Context, destination M.Socksaddr) (net.Conn, error) DialContext(ctx context.Context, destination M.Socksaddr) (net.Conn, error)
Reset()
Close() error Close() error
} }
@@ -136,6 +139,10 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
return packetConn, nil return packetConn, nil
} }
func (h *Outbound) InterfaceUpdated() {
h.client.Reset()
}
func (h *Outbound) Close() error { func (h *Outbound) Close() error {
return h.client.Close() return h.client.Close()
} }
+11
View File
@@ -67,6 +67,7 @@ import (
var ( var (
_ adapter.OutboundWithPreferredRoutes = (*Endpoint)(nil) _ adapter.OutboundWithPreferredRoutes = (*Endpoint)(nil)
_ adapter.InterfaceUpdateListener = (*Endpoint)(nil)
_ dialer.PacketDialerWithDestination = (*Endpoint)(nil) _ dialer.PacketDialerWithDestination = (*Endpoint)(nil)
_ tun.Port = (*Endpoint)(nil) _ tun.Port = (*Endpoint)(nil)
) )
@@ -687,6 +688,16 @@ func (t *Endpoint) Close() error {
return err return err
} }
func (t *Endpoint) InterfaceUpdated() {
if !t.started.Load() {
return
}
netMon, loaded := t.server.Sys().NetMon.GetOK()
if loaded && netMon != nil {
netMon.InjectEvent()
}
}
func (t *Endpoint) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) { func (t *Endpoint) DialContext(ctx context.Context, network string, destination M.Socksaddr) (net.Conn, error) {
switch network { switch network {
case N.NetworkTCP: case N.NetworkTCP:
+7
View File
@@ -505,6 +505,13 @@ func (t *Inbound) updateRouteAddressSet(it adapter.RuleSet) {
t.routeExcludeAddressSet = nil t.routeExcludeAddressSet = nil
} }
func (t *Inbound) InterfaceUpdated() {
tunStack := t.tunStack
if tunStack != nil {
tunStack.ResetNetwork()
}
}
func (t *Inbound) Close() error { func (t *Inbound) Close() error {
return common.Close( return common.Close(
t.tunStack, t.tunStack,
+11
View File
@@ -26,6 +26,7 @@ import (
var ( var (
_ adapter.OutboundWithPreferredRoutes = (*Endpoint)(nil) _ adapter.OutboundWithPreferredRoutes = (*Endpoint)(nil)
_ adapter.InterfaceUpdateListener = (*Endpoint)(nil)
_ dialer.PacketDialerWithDestination = (*Endpoint)(nil) _ dialer.PacketDialerWithDestination = (*Endpoint)(nil)
) )
@@ -159,6 +160,16 @@ func (w *Endpoint) Close() error {
return w.endpoint.Close() return w.endpoint.Close()
} }
func (w *Endpoint) InterfaceUpdated() {
if !w.started.Load() {
return
}
err := w.endpoint.BindUpdate()
if err != nil {
w.logger.Error(E.Cause(err, "update bind"))
}
}
func (w *Endpoint) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction { func (w *Endpoint) PreMatchFlow(network string, destination netip.Addr) adapter.PreMatchAction {
return adapter.PreMatchFlow return adapter.PreMatchFlow
} }
+3
View File
@@ -44,6 +44,9 @@ func (s *platformSearcher) FindProcessInfo(ctx context.Context, network string,
return s.platform.FindConnectionOwner(request) return s.platform.FindConnectionOwner(request)
} }
func (s *platformSearcher) ResetCache() {
}
func (s *platformSearcher) Close() error { func (s *platformSearcher) Close() error {
return nil return nil
} }
+6
View File
@@ -288,4 +288,10 @@ func (r *Router) NeighborResolver() adapter.NeighborResolver {
func (r *Router) ResetNetwork() { func (r *Router) ResetNetwork() {
r.httpClientManager.ResetNetwork() r.httpClientManager.ResetNetwork()
r.dns.ResetNetwork() r.dns.ResetNetwork()
if r.processCache != nil {
r.processCache.Purge()
}
if r.processSearcher != nil {
r.processSearcher.ResetCache()
}
} }
+7
View File
@@ -254,6 +254,13 @@ func (e *Endpoint) Lookup(address netip.Addr) *device.Peer {
return e.allowedIPs.Lookup(address.AsSlice()) return e.allowedIPs.Lookup(address.AsSlice())
} }
func (e *Endpoint) BindUpdate() error {
if e.device == nil {
return nil
}
return e.device.BindUpdate()
}
func (e *Endpoint) onPauseUpdated(event int) { func (e *Endpoint) onPauseUpdated(event int) {
switch event { switch event {
case pause.EventDevicePaused, pause.EventNetworkPause: case pause.EventDevicePaused, pause.EventNetworkPause: