浏览代码

Add NTP service

世界 2 年之前
父节点
当前提交
611d6bbfc5

+ 2 - 0
adapter/router.go

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

+ 8 - 0
adapter/time.go

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

+ 1 - 0
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,
 	)

+ 1 - 1
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)
 	}
 }
 

+ 1 - 0
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 {

+ 6 - 3
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,

+ 3 - 2
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) {

+ 3 - 1
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 {

+ 3 - 2
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 {

+ 1 - 0
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 {

+ 2 - 4
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

+ 4 - 4
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=

+ 1 - 1
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
 		}

+ 1 - 1
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
 	}

+ 1 - 1
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
 		}

+ 1 - 1
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)
 	}

+ 1 - 0
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

+ 1 - 1
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
 		}

+ 4 - 1
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
 		}

+ 1 - 1
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

+ 99 - 0
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
+}

+ 1 - 0
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"`

+ 8 - 0
option/ntp.go

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

+ 1 - 1
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
 	}

+ 3 - 0
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())
 	}

+ 28 - 1
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
 }