From 66f502b15395d48e2b2b898b39ddf555dbbcd146 Mon Sep 17 00:00:00 2001 From: ginuerzh Date: Sat, 20 Jun 2026 15:15:31 +0800 Subject: [PATCH] fix(router): skip system route setup for TUN @internal router When a TUN listener with `route=::/0` (or any route) creates its fallback @internal router during parseMetadata/Init, the router immediately calls setSysRoutes before the TUN device exists. This causes an ENETUNREACH "no route to host" error logged by the kernel because the gateway is unreachable at that point. The system routes are correctly added later by the listener's own addRoutes() after device creation. The @internal router only needs in-memory routes for GetRoute lookups. Add NoSysRouteOption which disables netlink route management while keeping route data for in-memory queries. Use it in the TUN listener's @internal router. Fixes go-gost/x#48 --- listener/tun/metadata.go | 1 + router/router.go | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/listener/tun/metadata.go b/listener/tun/metadata.go index 42057f00..c0c543db 100644 --- a/listener/tun/metadata.go +++ b/listener/tun/metadata.go @@ -109,6 +109,7 @@ func (l *tunListener) parseMetadata(md mdata.Metadata) (err error) { if config.Router == nil && len(l.routes) > 0 { config.Router = xrouter.NewRouter( xrouter.RoutesOption(l.routes), + xrouter.NoSysRouteOption(), xrouter.LoggerOption(logger.Default().WithFields(map[string]any{ "kind": "router", "router": "@internal", diff --git a/router/router.go b/router/router.go index d0843e8e..94629916 100644 --- a/router/router.go +++ b/router/router.go @@ -22,6 +22,7 @@ type options struct { redisLoader loader.Loader httpLoader loader.Loader period time.Duration + noSysRoute bool logger logger.Logger } @@ -63,6 +64,17 @@ func HTTPLoaderOption(httpLoader loader.Loader) Option { } } +// NoSysRouteOption disables automatic system route management via netlink. +// When set, the router only maintains in-memory routes for GetRoute lookups +// and does not attempt to add or replace routes in the OS routing table. +// This is useful when another component (e.g. a TUN listener) manages system +// routes independently. +func NoSysRouteOption() Option { + return func(opts *options) { + opts.noSysRoute = true + } +} + // LoggerOption sets the logger for the router. func LoggerOption(logger logger.Logger) Option { return func(opts *options) { @@ -141,8 +153,10 @@ func (p *localRouter) reload(ctx context.Context) error { p.options.logger.Debugf("load items %d", len(routes)) - if err := p.setSysRoutes(routes...); err != nil { - p.options.logger.Error(err) + if !p.options.noSysRoute { + if err := p.setSysRoutes(routes...); err != nil { + p.options.logger.Error(err) + } } p.mu.Lock()