From 611d6bbfc541501f65b86e72bd28a2f0ea727a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=96=E7=95=8C?= Date: Tue, 21 Feb 2023 14:53:00 +0800 Subject: [PATCH] Add NTP service --- adapter/router.go | 2 + adapter/time.go | 8 +++ box.go | 1 + common/tls/client.go | 2 +- common/tls/ech_client.go | 1 + common/tls/mkcert.go | 9 ++-- common/tls/server.go | 5 +- common/tls/std_client.go | 4 +- common/tls/std_server.go | 5 +- common/tls/utls_client.go | 1 + go.mod | 6 +-- go.sum | 8 +-- inbound/http.go | 2 +- inbound/hysteria.go | 2 +- inbound/naive.go | 2 +- inbound/shadowsocks.go | 2 +- inbound/shadowsocks_multi.go | 1 + inbound/trojan.go | 2 +- inbound/vmess.go | 5 +- log/override.go | 2 +- ntp/service.go | 99 ++++++++++++++++++++++++++++++++++++ option/config.go | 1 + option/ntp.go | 8 +++ outbound/shadowsocks.go | 2 +- outbound/vmess.go | 3 ++ route/router.go | 29 ++++++++++- 26 files changed, 186 insertions(+), 26 deletions(-) create mode 100644 adapter/time.go create mode 100644 ntp/service.go create mode 100644 option/ntp.go diff --git a/adapter/router.go b/adapter/router.go index 39178f02..e1807747 100644 --- a/adapter/router.go +++ b/adapter/router.go @@ -41,6 +41,8 @@ type Router interface { PackageManager() tun.PackageManager Rules() []Rule + TimeService + ClashServer() ClashServer SetClashServer(server ClashServer) diff --git a/adapter/time.go b/adapter/time.go new file mode 100644 index 00000000..3cb13fc1 --- /dev/null +++ b/adapter/time.go @@ -0,0 +1,8 @@ +package adapter + +import "time" + +type TimeService interface { + Service + TimeFunc() func() time.Time +} diff --git a/box.go b/box.go index af683375..2924cc7b 100644 --- a/box.go +++ b/box.go @@ -107,6 +107,7 @@ func New(ctx context.Context, options option.Options) (*Box, error) { logFactory, common.PtrValueOrDefault(options.Route), common.PtrValueOrDefault(options.DNS), + common.PtrValueOrDefault(options.NTP), options.Inbounds, options.PlatformInterface, ) diff --git a/common/tls/client.go b/common/tls/client.go index 71dcde46..1507e6d1 100644 --- a/common/tls/client.go +++ b/common/tls/client.go @@ -34,7 +34,7 @@ func NewClient(router adapter.Router, serverAddress string, options option.Outbo } else if options.UTLS != nil && options.UTLS.Enabled { return NewUTLSClient(router, serverAddress, options) } else { - return NewSTDClient(serverAddress, options) + return NewSTDClient(router, serverAddress, options) } } diff --git a/common/tls/ech_client.go b/common/tls/ech_client.go index 97903caa..f94824a2 100644 --- a/common/tls/ech_client.go +++ b/common/tls/ech_client.go @@ -90,6 +90,7 @@ func NewECHClient(router adapter.Router, serverAddress string, options option.Ou } var tlsConfig cftls.Config + tlsConfig.Time = router.TimeFunc() if options.DisableSNI { tlsConfig.ServerName = "127.0.0.1" } else { diff --git a/common/tls/mkcert.go b/common/tls/mkcert.go index d11ca934..9598cffa 100644 --- a/common/tls/mkcert.go +++ b/common/tls/mkcert.go @@ -11,7 +11,10 @@ import ( "time" ) -func GenerateKeyPair(serverName string) (*tls.Certificate, error) { +func GenerateKeyPair(timeFunc func() time.Time, serverName string) (*tls.Certificate, error) { + if timeFunc == nil { + timeFunc = time.Now + } key, err := rsa.GenerateKey(rand.Reader, 2048) if err != nil { return nil, err @@ -22,8 +25,8 @@ func GenerateKeyPair(serverName string) (*tls.Certificate, error) { } template := &x509.Certificate{ SerialNumber: serialNumber, - NotBefore: time.Now().Add(time.Hour * -1), - NotAfter: time.Now().Add(time.Hour), + NotBefore: timeFunc().Add(time.Hour * -1), + NotAfter: timeFunc().Add(time.Hour), KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, BasicConstraintsValid: true, diff --git a/common/tls/server.go b/common/tls/server.go index 9d69333e..dbace148 100644 --- a/common/tls/server.go +++ b/common/tls/server.go @@ -5,17 +5,18 @@ import ( "crypto/tls" "net" + "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/common/badtls" C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/option" ) -func NewServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { +func NewServer(ctx context.Context, router adapter.Router, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { if !options.Enabled { return nil, nil } - return NewSTDServer(ctx, logger, options) + return NewSTDServer(ctx, router, logger, options) } func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) { diff --git a/common/tls/std_client.go b/common/tls/std_client.go index 571602f3..cf630c66 100644 --- a/common/tls/std_client.go +++ b/common/tls/std_client.go @@ -7,6 +7,7 @@ import ( "net/netip" "os" + "github.com/sagernet/sing-box/adapter" "github.com/sagernet/sing-box/option" E "github.com/sagernet/sing/common/exceptions" ) @@ -43,7 +44,7 @@ func (s *STDClientConfig) Clone() Config { return &STDClientConfig{s.config.Clone()} } -func NewSTDClient(serverAddress string, options option.OutboundTLSOptions) (Config, error) { +func NewSTDClient(router adapter.Router, serverAddress string, options option.OutboundTLSOptions) (Config, error) { var serverName string if options.ServerName != "" { serverName = options.ServerName @@ -57,6 +58,7 @@ func NewSTDClient(serverAddress string, options option.OutboundTLSOptions) (Conf } var tlsConfig tls.Config + tlsConfig.Time = router.TimeFunc() if options.DisableSNI { tlsConfig.ServerName = "127.0.0.1" } else { diff --git a/common/tls/std_server.go b/common/tls/std_server.go index 03730952..8414ab36 100644 --- a/common/tls/std_server.go +++ b/common/tls/std_server.go @@ -156,7 +156,7 @@ func (c *STDServerConfig) Close() error { return nil } -func NewSTDServer(ctx context.Context, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { +func NewSTDServer(ctx context.Context, router adapter.Router, logger log.Logger, options option.InboundTLSOptions) (ServerConfig, error) { if !options.Enabled { return nil, nil } @@ -175,6 +175,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound } else { tlsConfig = &tls.Config{} } + tlsConfig.Time = router.TimeFunc() if options.ServerName != "" { tlsConfig.ServerName = options.ServerName } @@ -230,7 +231,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound } if certificate == nil && key == nil && options.Insecure { tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { - return GenerateKeyPair(info.ServerName) + return GenerateKeyPair(router.TimeFunc(), info.ServerName) } } else { if certificate == nil { diff --git a/common/tls/utls_client.go b/common/tls/utls_client.go index 33db86e7..a01c4840 100644 --- a/common/tls/utls_client.go +++ b/common/tls/utls_client.go @@ -91,6 +91,7 @@ func NewUTLSClient(router adapter.Router, serverAddress string, options option.O } var tlsConfig utls.Config + tlsConfig.Time = router.TimeFunc() if options.DisableSNI { tlsConfig.ServerName = "127.0.0.1" } else { diff --git a/go.mod b/go.mod index 742afaa0..53617b54 100644 --- a/go.mod +++ b/go.mod @@ -23,9 +23,9 @@ require ( github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 - github.com/sagernet/sing v0.1.7 + github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b github.com/sagernet/sing-dns v0.1.4 - github.com/sagernet/sing-shadowsocks v0.1.1 + github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9 github.com/sagernet/sing-shadowtls v0.0.0-20230220055143-e986e9cd9eb9 github.com/sagernet/sing-tun v0.1.1 github.com/sagernet/sing-vmess v0.1.2 @@ -49,8 +49,6 @@ require ( gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c ) -//replace github.com/sagernet/sing => ../sing - require ( github.com/ajg/form v1.5.1 // indirect github.com/andybalholm/brotli v1.0.5 // indirect diff --git a/go.sum b/go.sum index 4e611d26..ad7216f0 100644 --- a/go.sum +++ b/go.sum @@ -127,12 +127,12 @@ github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 h1:tztuJB+giOWNRK github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32/go.mod h1:QMCkxXAC3CvBgDZVIJp43NWTuwGBScCzMLVLynjERL8= github.com/sagernet/sing v0.0.0-20220812082120-05f9836bff8f/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= github.com/sagernet/sing v0.0.0-20220817130738-ce854cda8522/go.mod h1:QVsS5L/ZA2Q5UhQwLrn0Trw+msNd/NPGEhBKR/ioWiY= -github.com/sagernet/sing v0.1.7 h1:g4vjr3q8SUlBZSx97Emz5OBfSMBxxW5Q8C2PfdoSo08= -github.com/sagernet/sing v0.1.7/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= +github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b h1:Ji2AfGlc4j9AitobOx4k3BCj7eS5nSxL1cgaL81zvlo= +github.com/sagernet/sing v0.1.8-0.20230221060643-3401d210384b/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= github.com/sagernet/sing-dns v0.1.4 h1:7VxgeoSCiiazDSaXXQVcvrTBxFpOePPq/4XdgnUDN+0= github.com/sagernet/sing-dns v0.1.4/go.mod h1:1+6pCa48B1AI78lD+/i/dLgpw4MwfnsSpZo0Ds8wzzk= -github.com/sagernet/sing-shadowsocks v0.1.1 h1:uFK2rlVeD/b1xhDwSMbUI2goWc6fOKxp+ZeKHZq6C9Q= -github.com/sagernet/sing-shadowsocks v0.1.1/go.mod h1:f3mHTy5shnVM9l8UocMlJgC/1G/zdj5FuEuVXhDinGU= +github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9 h1:qS39eA4C7x+zhEkySbASrtmb6ebdy5v0y2M6mgkmSO0= +github.com/sagernet/sing-shadowsocks v0.1.2-0.20230221080503-769c01d6bba9/go.mod h1:f3mHTy5shnVM9l8UocMlJgC/1G/zdj5FuEuVXhDinGU= github.com/sagernet/sing-shadowtls v0.0.0-20230220055143-e986e9cd9eb9 h1:k1nXJL/00TSzlhFzTPpeo6VkbUyreIFVdGcd8pD7lrY= github.com/sagernet/sing-shadowtls v0.0.0-20230220055143-e986e9cd9eb9/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= github.com/sagernet/sing-tun v0.1.1 h1:2Hg3GAyJWzQ7Ua1j74dE+mI06vaqSBO9yD4tkTjggn4= diff --git a/inbound/http.go b/inbound/http.go index 14a614b1..9fe8ac80 100644 --- a/inbound/http.go +++ b/inbound/http.go @@ -44,7 +44,7 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge authenticator: auth.NewAuthenticator(options.Users), } if options.TLS != nil { - tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServer(ctx, router, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/inbound/hysteria.go b/inbound/hysteria.go index 363f92d7..14d00846 100644 --- a/inbound/hysteria.go +++ b/inbound/hysteria.go @@ -126,7 +126,7 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL if len(options.TLS.ALPN) == 0 { options.TLS.ALPN = []string{hysteria.DefaultALPN} } - tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServer(ctx, router, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/inbound/naive.go b/inbound/naive.go index 5b2fe14f..d823ae02 100644 --- a/inbound/naive.go +++ b/inbound/naive.go @@ -60,7 +60,7 @@ func NewNaive(ctx context.Context, router adapter.Router, logger log.ContextLogg return nil, E.New("missing users") } if options.TLS != nil { - tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServer(ctx, router, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/inbound/shadowsocks.go b/inbound/shadowsocks.go index 2bbb304b..c3318789 100644 --- a/inbound/shadowsocks.go +++ b/inbound/shadowsocks.go @@ -68,7 +68,7 @@ func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte case common.Contains(shadowaead.List, options.Method): inbound.service, err = shadowaead.NewService(options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler()) case common.Contains(shadowaead_2022.List, options.Method): - inbound.service, err = shadowaead_2022.NewServiceWithPassword(options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler()) + inbound.service, err = shadowaead_2022.NewServiceWithPassword(options.Method, options.Password, udpTimeout, inbound.upstreamContextHandler(), router.TimeFunc()) default: err = E.New("unsupported method: ", options.Method) } diff --git a/inbound/shadowsocks_multi.go b/inbound/shadowsocks_multi.go index fc9debd5..cfcd4225 100644 --- a/inbound/shadowsocks_multi.go +++ b/inbound/shadowsocks_multi.go @@ -57,6 +57,7 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log. options.Password, udpTimeout, adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound), + router.TimeFunc(), ) if err != nil { return nil, err diff --git a/inbound/trojan.go b/inbound/trojan.go index 84ef9bcf..0ec65498 100644 --- a/inbound/trojan.go +++ b/inbound/trojan.go @@ -49,7 +49,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog users: options.Users, } if options.TLS != nil { - tlsConfig, err := tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + tlsConfig, err := tls.NewServer(ctx, router, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/inbound/vmess.go b/inbound/vmess.go index 3ce73062..69552162 100644 --- a/inbound/vmess.go +++ b/inbound/vmess.go @@ -50,6 +50,9 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg users: options.Users, } var serviceOptions []vmess.ServiceOption + if timeFunc := router.TimeFunc(); timeFunc != nil { + serviceOptions = append(serviceOptions, vmess.ServiceWithTimeFunc(timeFunc)) + } if options.Transport != nil && options.Transport.Type != "" { serviceOptions = append(serviceOptions, vmess.ServiceWithDisableHeaderProtection()) } @@ -66,7 +69,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg return nil, err } if options.TLS != nil { - inbound.tlsConfig, err = tls.NewServer(ctx, logger, common.PtrValueOrDefault(options.TLS)) + inbound.tlsConfig, err = tls.NewServer(ctx, router, logger, common.PtrValueOrDefault(options.TLS)) if err != nil { return nil, err } diff --git a/log/override.go b/log/override.go index a0e5d3ca..42e26e60 100644 --- a/log/override.go +++ b/log/override.go @@ -12,7 +12,7 @@ func ContextWithOverrideLevel(ctx context.Context, level Level) context.Context func OverrideLevelFromContext(origin Level, ctx context.Context) Level { level, loaded := ctx.Value((*overrideLevelKey)(nil)).(Level) - if !loaded || origin < level { + if !loaded || origin > level { return origin } return level diff --git a/ntp/service.go b/ntp/service.go new file mode 100644 index 00000000..fef33818 --- /dev/null +++ b/ntp/service.go @@ -0,0 +1,99 @@ +package ntp + +import ( + "context" + "time" + + "github.com/sagernet/sing-box/adapter" + "github.com/sagernet/sing-box/common/dialer" + "github.com/sagernet/sing-box/option" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/logger" + M "github.com/sagernet/sing/common/metadata" + N "github.com/sagernet/sing/common/network" + "github.com/sagernet/sing/common/ntp" +) + +const timeLayout = "2006-01-02 15:04:05 -0700" + +var _ adapter.TimeService = (*Service)(nil) + +type Service struct { + ctx context.Context + cancel context.CancelFunc + server M.Socksaddr + dialer N.Dialer + logger logger.Logger + + ticker *time.Ticker + clockOffset time.Duration +} + +func NewService(ctx context.Context, router adapter.Router, logger logger.Logger, options option.NTPOptions) *Service { + ctx, cancel := context.WithCancel(ctx) + server := options.ServerOptions.Build() + if server.Port == 0 { + server.Port = 123 + } + var interval time.Duration + if options.Interval > 0 { + interval = time.Duration(options.Interval) * time.Second + } else { + interval = 30 * time.Minute + } + return &Service{ + ctx: ctx, + cancel: cancel, + server: server, + dialer: dialer.New(router, options.DialerOptions), + logger: logger, + ticker: time.NewTicker(interval), + } +} + +func (s *Service) Start() error { + err := s.update() + if err != nil { + return E.Cause(err, "initialize time") + } + s.logger.Info("updated time: ", s.TimeFunc()().Local().Format(timeLayout)) + go s.loopUpdate() + return nil +} + +func (s *Service) Close() error { + s.ticker.Stop() + s.cancel() + return nil +} + +func (s *Service) TimeFunc() func() time.Time { + return func() time.Time { + return time.Now().Add(s.clockOffset) + } +} + +func (s *Service) loopUpdate() { + for { + select { + case <-s.ctx.Done(): + return + case <-s.ticker.C: + } + err := s.update() + if err == nil { + s.logger.Debug("updated time: ", s.TimeFunc()().Local().Format(timeLayout)) + } else { + s.logger.Warn("update time: ", err) + } + } +} + +func (s *Service) update() error { + response, err := ntp.Exchange(s.ctx, s.dialer, s.server) + if err != nil { + return err + } + s.clockOffset = response.ClockOffset + return nil +} diff --git a/option/config.go b/option/config.go index b148aad4..3accfa1d 100644 --- a/option/config.go +++ b/option/config.go @@ -12,6 +12,7 @@ import ( type _Options struct { Log *LogOptions `json:"log,omitempty"` DNS *DNSOptions `json:"dns,omitempty"` + NTP *NTPOptions `json:"ntp,omitempty"` Inbounds []Inbound `json:"inbounds,omitempty"` Outbounds []Outbound `json:"outbounds,omitempty"` Route *RouteOptions `json:"route,omitempty"` diff --git a/option/ntp.go b/option/ntp.go new file mode 100644 index 00000000..a1c6d65a --- /dev/null +++ b/option/ntp.go @@ -0,0 +1,8 @@ +package option + +type NTPOptions struct { + Enabled bool `json:"enabled"` + Interval Duration `json:"interval,omitempty"` + ServerOptions + DialerOptions +} diff --git a/outbound/shadowsocks.go b/outbound/shadowsocks.go index b73e5143..63781fdb 100644 --- a/outbound/shadowsocks.go +++ b/outbound/shadowsocks.go @@ -34,7 +34,7 @@ type Shadowsocks struct { } func NewShadowsocks(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.ShadowsocksOutboundOptions) (*Shadowsocks, error) { - method, err := shadowimpl.FetchMethod(options.Method, options.Password) + method, err := shadowimpl.FetchMethod(options.Method, options.Password, router.TimeFunc()) if err != nil { return nil, err } diff --git a/outbound/vmess.go b/outbound/vmess.go index 428f9b77..8c5fa0b9 100644 --- a/outbound/vmess.go +++ b/outbound/vmess.go @@ -74,6 +74,9 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg return nil, E.New("unknown packet encoding: ", options.PacketEncoding) } var clientOptions []vmess.ClientOption + if timeFunc := router.TimeFunc(); timeFunc != nil { + clientOptions = append(clientOptions, vmess.ClientWithTimeFunc(timeFunc)) + } if options.GlobalPadding { clientOptions = append(clientOptions, vmess.ClientWithGlobalPadding()) } diff --git a/route/router.go b/route/router.go index 1dfbd9ed..909782b4 100644 --- a/route/router.go +++ b/route/router.go @@ -24,6 +24,7 @@ import ( C "github.com/sagernet/sing-box/constant" "github.com/sagernet/sing-box/experimental/libbox/platform" "github.com/sagernet/sing-box/log" + "github.com/sagernet/sing-box/ntp" "github.com/sagernet/sing-box/option" "github.com/sagernet/sing-dns" "github.com/sagernet/sing-tun" @@ -96,12 +97,21 @@ type Router struct { interfaceMonitor tun.DefaultInterfaceMonitor packageManager tun.PackageManager processSearcher process.Searcher + timeService adapter.TimeService clashServer adapter.ClashServer v2rayServer adapter.V2RayServer platformInterface platform.Interface } -func NewRouter(ctx context.Context, logFactory log.Factory, options option.RouteOptions, dnsOptions option.DNSOptions, inbounds []option.Inbound, platformInterface platform.Interface) (*Router, error) { +func NewRouter( + ctx context.Context, + logFactory log.Factory, + options option.RouteOptions, + dnsOptions option.DNSOptions, + ntpOptions option.NTPOptions, + inbounds []option.Inbound, + platformInterface platform.Interface, +) (*Router, error) { if options.DefaultInterface != "" { warnDefaultInterfaceOnUnsupportedPlatform.Check() } @@ -302,6 +312,9 @@ func NewRouter(ctx context.Context, logFactory log.Factory, options option.Route } } } + if ntpOptions.Enabled { + router.timeService = ntp.NewService(ctx, router, logFactory.NewLogger("ntp"), ntpOptions) + } return router, nil } @@ -460,6 +473,12 @@ func (r *Router) Start() error { return E.Cause(err, "initialize DNS server[", i, "]") } } + if r.timeService != nil { + err := r.timeService.Start() + if err != nil { + return E.Cause(err, "initialize time service") + } + } return nil } @@ -487,6 +506,7 @@ func (r *Router) Close() error { r.interfaceMonitor, r.networkMonitor, r.packageManager, + r.timeService, ) } @@ -783,6 +803,13 @@ func (r *Router) PackageManager() tun.PackageManager { return r.packageManager } +func (r *Router) TimeFunc() func() time.Time { + if r.timeService == nil { + return nil + } + return r.timeService.TimeFunc() +} + func (r *Router) ClashServer() adapter.ClashServer { return r.clashServer }