Fix tailscale crash at start

This commit is contained in:
世界
2026-05-12 20:09:53 +08:00
parent 2f139af2d1
commit b4c625543a
2 changed files with 38 additions and 1 deletions

View File

@@ -111,6 +111,7 @@ type Endpoint struct {
systemInterfaceName string systemInterfaceName string
systemInterfaceMTU uint32 systemInterfaceMTU uint32
serverStarted bool serverStarted bool
started atomic.Bool
systemTun tun.Tun systemTun tun.Tun
systemDialer *dialer.DefaultDialer systemDialer *dialer.DefaultDialer
fallbackTCPCloser func() fallbackTCPCloser func()
@@ -422,6 +423,7 @@ func (t *Endpoint) postStart() error {
} }
t.filter = localBackend.ExportFilter() t.filter = localBackend.ExportFilter()
go t.watchState() go t.watchState()
t.started.Store(true)
return nil return nil
} }
@@ -485,6 +487,7 @@ func (t *Endpoint) watchState() {
func (t *Endpoint) Close() error { func (t *Endpoint) Close() error {
var err error var err error
t.started.Store(false)
if t.serverStarted { if t.serverStarted {
err = common.Close(common.PtrOrNil(t.server)) err = common.Close(common.PtrOrNil(t.server))
t.serverStarted = false t.serverStarted = false
@@ -509,6 +512,9 @@ func (t *Endpoint) DialContext(ctx context.Context, network string, destination
case N.NetworkUDP: case N.NetworkUDP:
t.logger.InfoContext(ctx, "outbound packet connection to ", destination) t.logger.InfoContext(ctx, "outbound packet connection to ", destination)
} }
if !t.started.Load() {
return nil, E.New("Tailscale is not ready yet")
}
if destination.IsDomain() { if destination.IsDomain() {
destinationAddresses, err := t.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) destinationAddresses, err := t.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{})
if err != nil { if err != nil {
@@ -565,6 +571,9 @@ func (t *Endpoint) DialContext(ctx context.Context, network string, destination
} }
func (t *Endpoint) listenPacketWithAddress(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) { func (t *Endpoint) listenPacketWithAddress(ctx context.Context, destination M.Socksaddr) (net.PacketConn, error) {
if !t.started.Load() {
return nil, E.New("Tailscale is not ready yet")
}
if t.systemDialer != nil { if t.systemDialer != nil {
return t.systemDialer.ListenPacket(ctx, destination) return t.systemDialer.ListenPacket(ctx, destination)
} }
@@ -632,6 +641,9 @@ func (t *Endpoint) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
} }
func (t *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) { func (t *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
if !t.started.Load() {
return nil, E.New("Tailscale is not ready yet")
}
tsFilter := t.filter.Load() tsFilter := t.filter.Load()
if tsFilter != nil { if tsFilter != nil {
var ipProto ipproto.Proto var ipProto ipproto.Proto
@@ -725,6 +737,9 @@ func (t *Endpoint) NewPacketConnectionEx(ctx context.Context, conn N.PacketConn,
} }
func (t *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) { func (t *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
if !t.started.Load() {
return nil, E.New("Tailscale is not ready yet")
}
ctx := log.ContextWithNewID(t.ctx) ctx := log.ContextWithNewID(t.ctx)
var destination tun.DirectRouteDestination var destination tun.DirectRouteDestination
var err error var err error

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"net" "net"
"net/netip" "net/netip"
"sync/atomic"
"time" "time"
"github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/adapter"
@@ -41,6 +42,7 @@ type Endpoint struct {
logger logger.ContextLogger logger logger.ContextLogger
localAddresses []netip.Prefix localAddresses []netip.Prefix
endpoint *wireguard.Endpoint endpoint *wireguard.Endpoint
started atomic.Bool
} }
func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardEndpointOptions) (adapter.Endpoint, error) { func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.WireGuardEndpointOptions) (adapter.Endpoint, error) {
@@ -120,16 +122,24 @@ func (w *Endpoint) Start(stage adapter.StartStage) error {
case adapter.StartStateStart: case adapter.StartStateStart:
return w.endpoint.Start(false) return w.endpoint.Start(false)
case adapter.StartStatePostStart: case adapter.StartStatePostStart:
return w.endpoint.Start(true) err := w.endpoint.Start(true)
if err != nil {
return err
}
w.started.Store(true)
} }
return nil return nil
} }
func (w *Endpoint) Close() error { func (w *Endpoint) Close() error {
w.started.Store(false)
return w.endpoint.Close() return w.endpoint.Close()
} }
func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) { func (w *Endpoint) PrepareConnection(network string, source M.Socksaddr, destination M.Socksaddr, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
if !w.started.Load() {
return nil, E.New("WireGuard is not ready yet")
}
var ipVersion uint8 var ipVersion uint8
if !destination.IsIPv6() { if !destination.IsIPv6() {
ipVersion = 4 ipVersion = 4
@@ -210,6 +220,9 @@ func (w *Endpoint) DialContext(ctx context.Context, network string, destination
case N.NetworkUDP: case N.NetworkUDP:
w.logger.InfoContext(ctx, "outbound packet connection to ", destination) w.logger.InfoContext(ctx, "outbound packet connection to ", destination)
} }
if !w.started.Load() {
return nil, E.New("WireGuard is not ready yet")
}
if destination.IsDomain() { if destination.IsDomain() {
destinationAddresses, err := w.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) destinationAddresses, err := w.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{})
if err != nil { if err != nil {
@@ -224,6 +237,9 @@ func (w *Endpoint) DialContext(ctx context.Context, network string, destination
func (w *Endpoint) ListenPacketWithDestination(ctx context.Context, destination M.Socksaddr) (net.PacketConn, netip.Addr, error) { func (w *Endpoint) ListenPacketWithDestination(ctx context.Context, destination M.Socksaddr) (net.PacketConn, netip.Addr, error) {
w.logger.InfoContext(ctx, "outbound packet connection to ", destination) w.logger.InfoContext(ctx, "outbound packet connection to ", destination)
if !w.started.Load() {
return nil, netip.Addr{}, E.New("WireGuard is not ready yet")
}
if destination.IsDomain() { if destination.IsDomain() {
destinationAddresses, err := w.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{}) destinationAddresses, err := w.dnsRouter.Lookup(ctx, destination.Fqdn, adapter.DNSQueryOptions{})
if err != nil { if err != nil {
@@ -257,9 +273,15 @@ func (w *Endpoint) PreferredDomain(domain string) bool {
} }
func (w *Endpoint) PreferredAddress(address netip.Addr) bool { func (w *Endpoint) PreferredAddress(address netip.Addr) bool {
if !w.started.Load() {
return false
}
return w.endpoint.Lookup(address) != nil return w.endpoint.Lookup(address) != nil
} }
func (w *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) { func (w *Endpoint) NewDirectRouteConnection(metadata adapter.InboundContext, routeContext tun.DirectRouteContext, timeout time.Duration) (tun.DirectRouteDestination, error) {
if !w.started.Load() {
return nil, E.New("WireGuard is not ready yet")
}
return w.endpoint.NewDirectRouteConnection(metadata, routeContext, timeout) return w.endpoint.NewDirectRouteConnection(metadata, routeContext, timeout)
} }