Add NTP service

This commit is contained in:
世界 2023-02-21 14:53:00 +08:00
parent f26785c0ba
commit 611d6bbfc5
No known key found for this signature in database
GPG key ID: CD109927C34A63C4
26 changed files with 186 additions and 26 deletions

View file

@ -41,6 +41,8 @@ type Router interface {
PackageManager() tun.PackageManager PackageManager() tun.PackageManager
Rules() []Rule Rules() []Rule
TimeService
ClashServer() ClashServer ClashServer() ClashServer
SetClashServer(server ClashServer) SetClashServer(server ClashServer)

8
adapter/time.go Normal file
View file

@ -0,0 +1,8 @@
package adapter
import "time"
type TimeService interface {
Service
TimeFunc() func() time.Time
}

1
box.go
View file

@ -107,6 +107,7 @@ func New(ctx context.Context, options option.Options) (*Box, error) {
logFactory, logFactory,
common.PtrValueOrDefault(options.Route), common.PtrValueOrDefault(options.Route),
common.PtrValueOrDefault(options.DNS), common.PtrValueOrDefault(options.DNS),
common.PtrValueOrDefault(options.NTP),
options.Inbounds, options.Inbounds,
options.PlatformInterface, options.PlatformInterface,
) )

View file

@ -34,7 +34,7 @@ func NewClient(router adapter.Router, serverAddress string, options option.Outbo
} else if options.UTLS != nil && options.UTLS.Enabled { } else if options.UTLS != nil && options.UTLS.Enabled {
return NewUTLSClient(router, serverAddress, options) return NewUTLSClient(router, serverAddress, options)
} else { } else {
return NewSTDClient(serverAddress, options) return NewSTDClient(router, serverAddress, options)
} }
} }

View file

@ -90,6 +90,7 @@ func NewECHClient(router adapter.Router, serverAddress string, options option.Ou
} }
var tlsConfig cftls.Config var tlsConfig cftls.Config
tlsConfig.Time = router.TimeFunc()
if options.DisableSNI { if options.DisableSNI {
tlsConfig.ServerName = "127.0.0.1" tlsConfig.ServerName = "127.0.0.1"
} else { } else {

View file

@ -11,7 +11,10 @@ import (
"time" "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) key, err := rsa.GenerateKey(rand.Reader, 2048)
if err != nil { if err != nil {
return nil, err return nil, err
@ -22,8 +25,8 @@ func GenerateKeyPair(serverName string) (*tls.Certificate, error) {
} }
template := &x509.Certificate{ template := &x509.Certificate{
SerialNumber: serialNumber, SerialNumber: serialNumber,
NotBefore: time.Now().Add(time.Hour * -1), NotBefore: timeFunc().Add(time.Hour * -1),
NotAfter: time.Now().Add(time.Hour), NotAfter: timeFunc().Add(time.Hour),
KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature, KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true, BasicConstraintsValid: true,

View file

@ -5,17 +5,18 @@ import (
"crypto/tls" "crypto/tls"
"net" "net"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/common/badtls" "github.com/sagernet/sing-box/common/badtls"
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/option" "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 { if !options.Enabled {
return nil, nil 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) { func ServerHandshake(ctx context.Context, conn net.Conn, config ServerConfig) (Conn, error) {

View file

@ -7,6 +7,7 @@ import (
"net/netip" "net/netip"
"os" "os"
"github.com/sagernet/sing-box/adapter"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
E "github.com/sagernet/sing/common/exceptions" E "github.com/sagernet/sing/common/exceptions"
) )
@ -43,7 +44,7 @@ func (s *STDClientConfig) Clone() Config {
return &STDClientConfig{s.config.Clone()} 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 var serverName string
if options.ServerName != "" { if options.ServerName != "" {
serverName = options.ServerName serverName = options.ServerName
@ -57,6 +58,7 @@ func NewSTDClient(serverAddress string, options option.OutboundTLSOptions) (Conf
} }
var tlsConfig tls.Config var tlsConfig tls.Config
tlsConfig.Time = router.TimeFunc()
if options.DisableSNI { if options.DisableSNI {
tlsConfig.ServerName = "127.0.0.1" tlsConfig.ServerName = "127.0.0.1"
} else { } else {

View file

@ -156,7 +156,7 @@ func (c *STDServerConfig) Close() error {
return nil 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 { if !options.Enabled {
return nil, nil return nil, nil
} }
@ -175,6 +175,7 @@ func NewSTDServer(ctx context.Context, logger log.Logger, options option.Inbound
} else { } else {
tlsConfig = &tls.Config{} tlsConfig = &tls.Config{}
} }
tlsConfig.Time = router.TimeFunc()
if options.ServerName != "" { if options.ServerName != "" {
tlsConfig.ServerName = 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 { if certificate == nil && key == nil && options.Insecure {
tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) { tlsConfig.GetCertificate = func(info *tls.ClientHelloInfo) (*tls.Certificate, error) {
return GenerateKeyPair(info.ServerName) return GenerateKeyPair(router.TimeFunc(), info.ServerName)
} }
} else { } else {
if certificate == nil { if certificate == nil {

View file

@ -91,6 +91,7 @@ func NewUTLSClient(router adapter.Router, serverAddress string, options option.O
} }
var tlsConfig utls.Config var tlsConfig utls.Config
tlsConfig.Time = router.TimeFunc()
if options.DisableSNI { if options.DisableSNI {
tlsConfig.ServerName = "127.0.0.1" tlsConfig.ServerName = "127.0.0.1"
} else { } else {

6
go.mod
View file

@ -23,9 +23,9 @@ require (
github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0 github.com/sagernet/cloudflare-tls v0.0.0-20221031050923-d70792f4c3a0
github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca github.com/sagernet/gomobile v0.0.0-20221130124640-349ebaa752ca
github.com/sagernet/quic-go v0.0.0-20230202071646-a8c8afb18b32 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-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-shadowtls v0.0.0-20230220055143-e986e9cd9eb9
github.com/sagernet/sing-tun v0.1.1 github.com/sagernet/sing-tun v0.1.1
github.com/sagernet/sing-vmess v0.1.2 github.com/sagernet/sing-vmess v0.1.2
@ -49,8 +49,6 @@ require (
gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c gvisor.dev/gvisor v0.0.0-20220901235040-6ca97ef2ce1c
) )
//replace github.com/sagernet/sing => ../sing
require ( require (
github.com/ajg/form v1.5.1 // indirect github.com/ajg/form v1.5.1 // indirect
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect

8
go.sum
View file

@ -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/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-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.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.8-0.20230221060643-3401d210384b h1:Ji2AfGlc4j9AitobOx4k3BCj7eS5nSxL1cgaL81zvlo=
github.com/sagernet/sing v0.1.7/go.mod h1:jt1w2u7lJQFFSGLiRrRIs5YWmx4kAPfWuOejuDW9qMk= 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 h1:7VxgeoSCiiazDSaXXQVcvrTBxFpOePPq/4XdgnUDN+0=
github.com/sagernet/sing-dns v0.1.4/go.mod h1:1+6pCa48B1AI78lD+/i/dLgpw4MwfnsSpZo0Ds8wzzk= 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.2-0.20230221080503-769c01d6bba9 h1:qS39eA4C7x+zhEkySbASrtmb6ebdy5v0y2M6mgkmSO0=
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/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 h1:k1nXJL/00TSzlhFzTPpeo6VkbUyreIFVdGcd8pD7lrY=
github.com/sagernet/sing-shadowtls v0.0.0-20230220055143-e986e9cd9eb9/go.mod h1:Kn1VUIprdkwCgkS6SXYaLmIpKzQbqBIKJBMY+RvBhYc= 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= github.com/sagernet/sing-tun v0.1.1 h1:2Hg3GAyJWzQ7Ua1j74dE+mI06vaqSBO9yD4tkTjggn4=

View file

@ -44,7 +44,7 @@ func NewHTTP(ctx context.Context, router adapter.Router, logger log.ContextLogge
authenticator: auth.NewAuthenticator(options.Users), authenticator: auth.NewAuthenticator(options.Users),
} }
if options.TLS != nil { 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -126,7 +126,7 @@ func NewHysteria(ctx context.Context, router adapter.Router, logger log.ContextL
if len(options.TLS.ALPN) == 0 { if len(options.TLS.ALPN) == 0 {
options.TLS.ALPN = []string{hysteria.DefaultALPN} 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -60,7 +60,7 @@ func NewNaive(ctx context.Context, router adapter.Router, logger log.ContextLogg
return nil, E.New("missing users") return nil, E.New("missing users")
} }
if options.TLS != nil { 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -68,7 +68,7 @@ func newShadowsocks(ctx context.Context, router adapter.Router, logger log.Conte
case common.Contains(shadowaead.List, options.Method): case common.Contains(shadowaead.List, options.Method):
inbound.service, err = shadowaead.NewService(options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler()) inbound.service, err = shadowaead.NewService(options.Method, nil, options.Password, udpTimeout, inbound.upstreamContextHandler())
case common.Contains(shadowaead_2022.List, options.Method): 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: default:
err = E.New("unsupported method: ", options.Method) err = E.New("unsupported method: ", options.Method)
} }

View file

@ -57,6 +57,7 @@ func newShadowsocksMulti(ctx context.Context, router adapter.Router, logger log.
options.Password, options.Password,
udpTimeout, udpTimeout,
adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound), adapter.NewUpstreamContextHandler(inbound.newConnection, inbound.newPacketConnection, inbound),
router.TimeFunc(),
) )
if err != nil { if err != nil {
return nil, err return nil, err

View file

@ -49,7 +49,7 @@ func NewTrojan(ctx context.Context, router adapter.Router, logger log.ContextLog
users: options.Users, users: options.Users,
} }
if options.TLS != nil { 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -50,6 +50,9 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
users: options.Users, users: options.Users,
} }
var serviceOptions []vmess.ServiceOption var serviceOptions []vmess.ServiceOption
if timeFunc := router.TimeFunc(); timeFunc != nil {
serviceOptions = append(serviceOptions, vmess.ServiceWithTimeFunc(timeFunc))
}
if options.Transport != nil && options.Transport.Type != "" { if options.Transport != nil && options.Transport.Type != "" {
serviceOptions = append(serviceOptions, vmess.ServiceWithDisableHeaderProtection()) serviceOptions = append(serviceOptions, vmess.ServiceWithDisableHeaderProtection())
} }
@ -66,7 +69,7 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
return nil, err return nil, err
} }
if options.TLS != nil { 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -12,7 +12,7 @@ func ContextWithOverrideLevel(ctx context.Context, level Level) context.Context
func OverrideLevelFromContext(origin Level, ctx context.Context) Level { func OverrideLevelFromContext(origin Level, ctx context.Context) Level {
level, loaded := ctx.Value((*overrideLevelKey)(nil)).(Level) level, loaded := ctx.Value((*overrideLevelKey)(nil)).(Level)
if !loaded || origin < level { if !loaded || origin > level {
return origin return origin
} }
return level return level

99
ntp/service.go Normal file
View file

@ -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
}

View file

@ -12,6 +12,7 @@ import (
type _Options struct { type _Options struct {
Log *LogOptions `json:"log,omitempty"` Log *LogOptions `json:"log,omitempty"`
DNS *DNSOptions `json:"dns,omitempty"` DNS *DNSOptions `json:"dns,omitempty"`
NTP *NTPOptions `json:"ntp,omitempty"`
Inbounds []Inbound `json:"inbounds,omitempty"` Inbounds []Inbound `json:"inbounds,omitempty"`
Outbounds []Outbound `json:"outbounds,omitempty"` Outbounds []Outbound `json:"outbounds,omitempty"`
Route *RouteOptions `json:"route,omitempty"` Route *RouteOptions `json:"route,omitempty"`

8
option/ntp.go Normal file
View file

@ -0,0 +1,8 @@
package option
type NTPOptions struct {
Enabled bool `json:"enabled"`
Interval Duration `json:"interval,omitempty"`
ServerOptions
DialerOptions
}

View file

@ -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) { 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 { if err != nil {
return nil, err return nil, err
} }

View file

@ -74,6 +74,9 @@ func NewVMess(ctx context.Context, router adapter.Router, logger log.ContextLogg
return nil, E.New("unknown packet encoding: ", options.PacketEncoding) return nil, E.New("unknown packet encoding: ", options.PacketEncoding)
} }
var clientOptions []vmess.ClientOption var clientOptions []vmess.ClientOption
if timeFunc := router.TimeFunc(); timeFunc != nil {
clientOptions = append(clientOptions, vmess.ClientWithTimeFunc(timeFunc))
}
if options.GlobalPadding { if options.GlobalPadding {
clientOptions = append(clientOptions, vmess.ClientWithGlobalPadding()) clientOptions = append(clientOptions, vmess.ClientWithGlobalPadding())
} }

View file

@ -24,6 +24,7 @@ import (
C "github.com/sagernet/sing-box/constant" C "github.com/sagernet/sing-box/constant"
"github.com/sagernet/sing-box/experimental/libbox/platform" "github.com/sagernet/sing-box/experimental/libbox/platform"
"github.com/sagernet/sing-box/log" "github.com/sagernet/sing-box/log"
"github.com/sagernet/sing-box/ntp"
"github.com/sagernet/sing-box/option" "github.com/sagernet/sing-box/option"
"github.com/sagernet/sing-dns" "github.com/sagernet/sing-dns"
"github.com/sagernet/sing-tun" "github.com/sagernet/sing-tun"
@ -96,12 +97,21 @@ type Router struct {
interfaceMonitor tun.DefaultInterfaceMonitor interfaceMonitor tun.DefaultInterfaceMonitor
packageManager tun.PackageManager packageManager tun.PackageManager
processSearcher process.Searcher processSearcher process.Searcher
timeService adapter.TimeService
clashServer adapter.ClashServer clashServer adapter.ClashServer
v2rayServer adapter.V2RayServer v2rayServer adapter.V2RayServer
platformInterface platform.Interface 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 != "" { if options.DefaultInterface != "" {
warnDefaultInterfaceOnUnsupportedPlatform.Check() 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 return router, nil
} }
@ -460,6 +473,12 @@ func (r *Router) Start() error {
return E.Cause(err, "initialize DNS server[", i, "]") 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 return nil
} }
@ -487,6 +506,7 @@ func (r *Router) Close() error {
r.interfaceMonitor, r.interfaceMonitor,
r.networkMonitor, r.networkMonitor,
r.packageManager, r.packageManager,
r.timeService,
) )
} }
@ -783,6 +803,13 @@ func (r *Router) PackageManager() tun.PackageManager {
return r.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 { func (r *Router) ClashServer() adapter.ClashServer {
return r.clashServer return r.clashServer
} }