Fix start lifecycle
This commit is contained in:
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"runtime/debug"
|
||||
"time"
|
||||
@@ -43,6 +44,8 @@ var _ adapter.SimpleLifecycle = (*Box)(nil)
|
||||
|
||||
type Box struct {
|
||||
createdAt time.Time
|
||||
debugOptions option.DebugOptions
|
||||
debugHTTPServer *http.Server
|
||||
logFactory log.Factory
|
||||
logger log.ContextLogger
|
||||
network *route.NetworkManager
|
||||
@@ -142,7 +145,8 @@ func New(options Options) (*Box, error) {
|
||||
|
||||
ctx = pause.WithDefaultManager(ctx)
|
||||
experimentalOptions := common.PtrValueOrDefault(options.Experimental)
|
||||
err := applyDebugOptions(common.PtrValueOrDefault(experimentalOptions.Debug))
|
||||
debugOptions := common.PtrValueOrDefault(experimentalOptions.Debug)
|
||||
err := checkDebugOptions(debugOptions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -470,6 +474,7 @@ func New(options Options) (*Box, error) {
|
||||
router: router,
|
||||
httpClientService: httpClientService,
|
||||
createdAt: createdAt,
|
||||
debugOptions: debugOptions,
|
||||
logFactory: logFactory,
|
||||
logger: logFactory.Logger(),
|
||||
internalService: internalServices,
|
||||
@@ -523,6 +528,11 @@ func (s *Box) preStart() error {
|
||||
if err != nil {
|
||||
return E.Cause(err, "start logger")
|
||||
}
|
||||
applyDebugOptions(s.debugOptions)
|
||||
s.debugHTTPServer, err = startDebugHTTPServer(s.debugOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = adapter.StartNamed(s.logger, adapter.StartStateInitialize, s.internalService) // cache-file clash-api v2ray-api
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -594,6 +604,12 @@ func (s *Box) Close() error {
|
||||
close(s.done)
|
||||
}
|
||||
var err error
|
||||
if s.debugHTTPServer != nil {
|
||||
err = E.Append(err, s.debugHTTPServer.Close(), func(err error) error {
|
||||
return E.Cause(err, "close debug HTTP server")
|
||||
})
|
||||
s.debugHTTPServer = nil
|
||||
}
|
||||
for _, closeItem := range []struct {
|
||||
name string
|
||||
service adapter.Lifecycle
|
||||
|
||||
@@ -96,6 +96,15 @@ type appleTransport struct {
|
||||
closed bool
|
||||
}
|
||||
|
||||
func validateAppleTransport(ctx context.Context, options option.HTTPClientOptions) error {
|
||||
sessionConfig, err := newAppleSessionConfig(ctx, options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sessionConfig.close()
|
||||
return nil
|
||||
}
|
||||
|
||||
func newAppleTransport(ctx context.Context, logger logger.ContextLogger, rawDialer N.Dialer, options option.HTTPClientOptions) (innerTransport, error) {
|
||||
sessionConfig, err := newAppleSessionConfig(ctx, options)
|
||||
if err != nil {
|
||||
@@ -111,6 +120,10 @@ func newAppleTransport(ctx context.Context, logger logger.ContextLogger, rawDial
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = bridge.Start()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
shared := &appleTransportShared{
|
||||
logger: logger,
|
||||
bridge: bridge,
|
||||
|
||||
@@ -11,6 +11,10 @@ import (
|
||||
N "github.com/sagernet/sing/common/network"
|
||||
)
|
||||
|
||||
func validateAppleTransport(ctx context.Context, options option.HTTPClientOptions) error {
|
||||
return E.New("Apple HTTP engine is not available on non-Apple platforms")
|
||||
}
|
||||
|
||||
func newAppleTransport(ctx context.Context, logger logger.ContextLogger, rawDialer N.Dialer, options option.HTTPClientOptions) (innerTransport, error) {
|
||||
return nil, E.New("Apple HTTP engine is not available on non-Apple platforms")
|
||||
}
|
||||
|
||||
@@ -35,11 +35,11 @@ func NewTransport(ctx context.Context, logger logger.ContextLogger, tag string,
|
||||
var cheapRebuild bool
|
||||
switch options.Engine {
|
||||
case C.TLSEngineApple:
|
||||
inner, transportErr := newAppleTransport(ctx, logger, rawDialer, options)
|
||||
if transportErr != nil {
|
||||
return nil, transportErr
|
||||
err = validateAppleTransport(ctx, options)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
managedTransport := &ManagedTransport{
|
||||
return &ManagedTransport{
|
||||
dialer: rawDialer,
|
||||
headers: headers,
|
||||
host: host,
|
||||
@@ -47,9 +47,7 @@ func NewTransport(ctx context.Context, logger logger.ContextLogger, tag string,
|
||||
factory: func() (innerTransport, error) {
|
||||
return newAppleTransport(ctx, logger, rawDialer, options)
|
||||
},
|
||||
}
|
||||
managedTransport.epoch.Store(&transportEpoch{transport: inner})
|
||||
return managedTransport, nil
|
||||
}, nil
|
||||
case "", C.TLSEngineGo:
|
||||
cheapRebuild = true
|
||||
default:
|
||||
|
||||
@@ -34,23 +34,26 @@ type Bridge struct {
|
||||
func New(ctx context.Context, logger logger.ContextLogger, tag string, dialer N.Dialer) (*Bridge, error) {
|
||||
username := randomHex(16)
|
||||
password := randomHex(16)
|
||||
tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
bridge := &Bridge{
|
||||
return &Bridge{
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
tag: tag,
|
||||
dialer: dialer,
|
||||
connection: service.FromContext[adapter.ConnectionManager](ctx),
|
||||
tcpListener: tcpListener,
|
||||
username: username,
|
||||
password: password,
|
||||
authenticator: auth.NewAuthenticator([]auth.User{{Username: username, Password: password}}),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (b *Bridge) Start() error {
|
||||
tcpListener, err := net.ListenTCP("tcp", &net.TCPAddr{IP: net.IPv4(127, 0, 0, 1)})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
go bridge.acceptLoop()
|
||||
return bridge, nil
|
||||
b.tcpListener = tcpListener
|
||||
go b.acceptLoop()
|
||||
return nil
|
||||
}
|
||||
|
||||
func randomHex(size int) string {
|
||||
@@ -72,7 +75,7 @@ func (b *Bridge) Password() string {
|
||||
}
|
||||
|
||||
func (b *Bridge) Close() error {
|
||||
return common.Close(b.tcpListener)
|
||||
return common.Close(common.PtrOrNil(b.tcpListener))
|
||||
}
|
||||
|
||||
func (b *Bridge) acceptLoop() {
|
||||
|
||||
+44
-21
@@ -26,21 +26,45 @@ import (
|
||||
)
|
||||
|
||||
type acmeWrapper struct {
|
||||
ctx context.Context
|
||||
cfg *certmagic.Config
|
||||
cache *certmagic.Cache
|
||||
domain []string
|
||||
ctx context.Context
|
||||
cfg *certmagic.Config
|
||||
cache *certmagic.Cache
|
||||
zapLogger *zap.Logger
|
||||
dataDirectory string
|
||||
domain []string
|
||||
}
|
||||
|
||||
func (w *acmeWrapper) Start() error {
|
||||
if w.dataDirectory != "" {
|
||||
err := filemanager.MkdirAll(w.ctx, w.dataDirectory, 0o700)
|
||||
if err != nil {
|
||||
return E.Cause(err, "create ACME data directory")
|
||||
}
|
||||
}
|
||||
config := w.cfg
|
||||
cache := certmagic.NewCache(certmagic.CacheOptions{
|
||||
GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) {
|
||||
return config, nil
|
||||
},
|
||||
Logger: w.zapLogger,
|
||||
})
|
||||
config = certmagic.New(cache, *config)
|
||||
w.cfg = config
|
||||
w.cache = cache
|
||||
return w.cfg.ManageSync(w.ctx, w.domain)
|
||||
}
|
||||
|
||||
func (w *acmeWrapper) Close() error {
|
||||
w.cache.Stop()
|
||||
if w.cache != nil {
|
||||
w.cache.Stop()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *acmeWrapper) GetCertificate(hello *tls.ClientHelloInfo) (*tls.Certificate, error) {
|
||||
return w.cfg.GetCertificate(hello)
|
||||
}
|
||||
|
||||
func startACME(ctx context.Context, logger logger.Logger, options option.InboundACMEOptions) (*tls.Config, adapter.SimpleLifecycle, error) {
|
||||
var acmeServer string
|
||||
switch options.Provider {
|
||||
@@ -54,13 +78,12 @@ func startACME(ctx context.Context, logger logger.Logger, options option.Inbound
|
||||
}
|
||||
acmeServer = options.Provider
|
||||
}
|
||||
var storage certmagic.Storage
|
||||
var (
|
||||
storage certmagic.Storage
|
||||
dataDirectory string
|
||||
)
|
||||
if options.DataDirectory != "" {
|
||||
dataDirectory := filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
|
||||
err := filemanager.MkdirAll(ctx, dataDirectory, 0o700)
|
||||
if err != nil {
|
||||
return nil, nil, E.Cause(err, "create ACME data directory")
|
||||
}
|
||||
dataDirectory = filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
|
||||
storage = &certmagic.FileStorage{
|
||||
Path: dataDirectory,
|
||||
}
|
||||
@@ -126,23 +149,23 @@ func startACME(ctx context.Context, logger logger.Logger, options option.Inbound
|
||||
acmeConfig.ExternalAccount = (*acme.EAB)(options.ExternalAccount)
|
||||
}
|
||||
config.Issuers = []certmagic.Issuer{certmagic.NewACMEIssuer(config, acmeConfig)}
|
||||
cache := certmagic.NewCache(certmagic.CacheOptions{
|
||||
GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) {
|
||||
return config, nil
|
||||
},
|
||||
Logger: zapLogger,
|
||||
})
|
||||
config = certmagic.New(cache, *config)
|
||||
wrapper := &acmeWrapper{
|
||||
ctx: ctx,
|
||||
cfg: config,
|
||||
zapLogger: zapLogger,
|
||||
dataDirectory: dataDirectory,
|
||||
domain: options.Domain,
|
||||
}
|
||||
var tlsConfig *tls.Config
|
||||
if acmeConfig.DisableTLSALPNChallenge || acmeConfig.DNS01Solver != nil {
|
||||
tlsConfig = &tls.Config{
|
||||
GetCertificate: config.GetCertificate,
|
||||
GetCertificate: wrapper.GetCertificate,
|
||||
}
|
||||
} else {
|
||||
tlsConfig = &tls.Config{
|
||||
GetCertificate: config.GetCertificate,
|
||||
GetCertificate: wrapper.GetCertificate,
|
||||
NextProtos: []string{C.ACMETLS1Protocol},
|
||||
}
|
||||
}
|
||||
return tlsConfig, &acmeWrapper{ctx: ctx, cfg: config, cache: cache, domain: options.Domain}, nil
|
||||
return tlsConfig, wrapper, nil
|
||||
}
|
||||
|
||||
@@ -50,13 +50,10 @@ type Manager struct {
|
||||
}
|
||||
|
||||
func NewManager(outbound adapter.OutboundManager) *Manager {
|
||||
manager := &Manager{
|
||||
return &Manager{
|
||||
outbound: outbound,
|
||||
eventSubscriber: observable.NewSubscriber[ConnectionEvent](256),
|
||||
}
|
||||
manager.eventObserver = observable.NewObserver(manager.eventSubscriber, 64)
|
||||
manager.cleaner = cleanup.Add(manager.Clear)
|
||||
return manager
|
||||
}
|
||||
|
||||
func (m *Manager) Name() string {
|
||||
@@ -64,12 +61,21 @@ func (m *Manager) Name() string {
|
||||
}
|
||||
|
||||
func (m *Manager) Start(stage adapter.StartStage) error {
|
||||
if stage == adapter.StartStateInitialize {
|
||||
m.eventObserver = observable.NewObserver(m.eventSubscriber, 64)
|
||||
m.cleaner = cleanup.Add(m.Clear)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) Close() error {
|
||||
m.cleaner.Close()
|
||||
return m.eventObserver.Close()
|
||||
if m.cleaner != nil {
|
||||
m.cleaner.Close()
|
||||
}
|
||||
if m.eventObserver != nil {
|
||||
return m.eventObserver.Close()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m *Manager) SubscribeEvents() (observable.Subscription[ConnectionEvent], <-chan struct{}, error) {
|
||||
|
||||
@@ -7,8 +7,14 @@ import (
|
||||
E "github.com/sagernet/sing/common/exceptions"
|
||||
)
|
||||
|
||||
func applyDebugOptions(options option.DebugOptions) error {
|
||||
applyDebugListenOption(options)
|
||||
func checkDebugOptions(options option.DebugOptions) error {
|
||||
if options.OOMKiller != nil {
|
||||
return E.New("legacy oom_killer in debug options is removed, use oom-killer service instead")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func applyDebugOptions(options option.DebugOptions) {
|
||||
if options.GCPercent != nil {
|
||||
debug.SetGCPercent(*options.GCPercent)
|
||||
}
|
||||
@@ -27,8 +33,4 @@ func applyDebugOptions(options option.DebugOptions) error {
|
||||
if options.MemoryLimit.Value() != 0 {
|
||||
debug.SetMemoryLimit(int64(float64(options.MemoryLimit.Value()) / 1.5))
|
||||
}
|
||||
if options.OOMKiller != nil {
|
||||
return E.New("legacy oom_killer in debug options is removed, use oom-killer service instead")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
+10
-10
@@ -1,6 +1,7 @@
|
||||
package box
|
||||
|
||||
import (
|
||||
"net"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
"runtime"
|
||||
@@ -17,15 +18,9 @@ import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
var debugHTTPServer *http.Server
|
||||
|
||||
func applyDebugListenOption(options option.DebugOptions) {
|
||||
if debugHTTPServer != nil {
|
||||
debugHTTPServer.Close()
|
||||
debugHTTPServer = nil
|
||||
}
|
||||
func startDebugHTTPServer(options option.DebugOptions) (*http.Server, error) {
|
||||
if options.Listen == "" {
|
||||
return
|
||||
return nil, nil
|
||||
}
|
||||
r := chi.NewMux()
|
||||
r.Route("/debug", func(r chi.Router) {
|
||||
@@ -63,14 +58,19 @@ func applyDebugListenOption(options option.DebugOptions) {
|
||||
r.HandleFunc("/trace", pprof.Trace)
|
||||
})
|
||||
})
|
||||
debugHTTPServer = &http.Server{
|
||||
server := &http.Server{
|
||||
Addr: options.Listen,
|
||||
Handler: r,
|
||||
}
|
||||
listener, err := net.Listen("tcp", options.Listen)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "listen debug HTTP server")
|
||||
}
|
||||
go func() {
|
||||
err := debugHTTPServer.ListenAndServe()
|
||||
err := server.Serve(listener)
|
||||
if err != nil && !E.IsClosed(err) {
|
||||
log.Error(E.Cause(err, "serve debug HTTP server"))
|
||||
}
|
||||
}()
|
||||
return server, nil
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"slices"
|
||||
|
||||
"github.com/sagernet/sing-box/experimental/locale"
|
||||
|
||||
@@ -14,11 +15,7 @@ func setLocaleFromContext(ctx context.Context) {
|
||||
if !loaded {
|
||||
return
|
||||
}
|
||||
for _, localeID := range requestMetadata.Get("accept-language") {
|
||||
if locale.Set(localeID) {
|
||||
return
|
||||
}
|
||||
}
|
||||
slices.ContainsFunc(requestMetadata.Get("accept-language"), locale.Set)
|
||||
}
|
||||
|
||||
func unaryLocaleInterceptor(ctx context.Context, request any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||
|
||||
@@ -5,7 +5,7 @@ func init() {
|
||||
Locale: "fa",
|
||||
DeprecatedMessage: "%s از sing-box %s منسوخ شده است و در sing-box %s حذف خواهد شد؛ لطفاً راهنمای مهاجرت را ببینید.",
|
||||
DeprecatedMessageNoLink: "%s از sing-box %s منسوخ شده است و در sing-box %s حذف خواهد شد.",
|
||||
InsecureFeatureMessage: "%s در کلاینت گرافیکی sing-box برای Windows ناامن تلقی میشود. برای استفاده، `حالت ناامن` را در `تنظیمات - هسته - حالت ناامن` فعال کنید.",
|
||||
ExternalPathFeature: "دسترسی به %s (خارج از پوشهٔ کاری) در کلاینت گرافیکی sing-box برای Windows ناامن تلقی میشود. برای استفاده، `حالت ناامن` را در `تنظیمات - هسته - حالت ناامن` فعال کنید.",
|
||||
InsecureFeatureMessage: "%s در کلاینت گرافیکی sing-box برای Windows ناامن تلقی می\u200cشود. برای استفاده، `حالت ناامن` را در `تنظیمات - هسته - حالت ناامن` فعال کنید.",
|
||||
ExternalPathFeature: "دسترسی به %s (خارج از پوشهٔ کاری) در کلاینت گرافیکی sing-box برای Windows ناامن تلقی می\u200cشود. برای استفاده، `حالت ناامن` را در `تنظیمات - هسته - حالت ناامن` فعال کنید.",
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -56,9 +56,6 @@ func NewDefaultFactory(
|
||||
/*if platformWriter != nil {
|
||||
factory.platformFormatter.DisableColors = platformWriter.DisableColors()
|
||||
}*/
|
||||
if needObservable {
|
||||
factory.observer = observable.NewObserver[Entry](factory.subscriber, 64)
|
||||
}
|
||||
return factory
|
||||
}
|
||||
|
||||
@@ -71,6 +68,9 @@ func (f *defaultFactory) Start() error {
|
||||
f.writer = logFile
|
||||
f.file = logFile
|
||||
}
|
||||
if f.needObservable {
|
||||
f.observer = observable.NewObserver[Entry](f.subscriber, 64)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
+24
-14
@@ -27,17 +27,20 @@ func RegisterOutbound(registry *outbound.Registry) {
|
||||
|
||||
type Outbound struct {
|
||||
outbound.Adapter
|
||||
dialer tls.Dialer
|
||||
server M.Socksaddr
|
||||
tlsConfig tls.Config
|
||||
client *anytls.Client
|
||||
uotClient *uot.Client
|
||||
logger log.ContextLogger
|
||||
ctx context.Context
|
||||
dialer tls.Dialer
|
||||
server M.Socksaddr
|
||||
tlsConfig tls.Config
|
||||
clientOptions anytls.ClientConfig
|
||||
client *anytls.Client
|
||||
uotClient *uot.Client
|
||||
logger log.ContextLogger
|
||||
}
|
||||
|
||||
func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextLogger, tag string, options option.AnyTLSOutboundOptions) (adapter.Outbound, error) {
|
||||
outbound := &Outbound{
|
||||
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeAnyTLS, tag, []string{N.NetworkTCP, N.NetworkUDP}, options.DialerOptions),
|
||||
ctx: ctx,
|
||||
server: options.ServerOptions.Build(),
|
||||
logger: logger,
|
||||
}
|
||||
@@ -69,24 +72,31 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
|
||||
outbound.dialer = tls.NewDialer(outboundDialer, tlsConfig)
|
||||
|
||||
client, err := anytls.NewClient(ctx, anytls.ClientConfig{
|
||||
outbound.clientOptions = anytls.ClientConfig{
|
||||
Password: options.Password,
|
||||
IdleSessionCheckInterval: options.IdleSessionCheckInterval.Build(),
|
||||
IdleSessionTimeout: options.IdleSessionTimeout.Build(),
|
||||
MinIdleSession: options.MinIdleSession,
|
||||
DialOut: outbound.dialOut,
|
||||
Logger: logger,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
outbound.client = client
|
||||
return outbound, nil
|
||||
}
|
||||
|
||||
outbound.uotClient = &uot.Client{
|
||||
func (h *Outbound) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateInitialize {
|
||||
return nil
|
||||
}
|
||||
client, err := anytls.NewClient(h.ctx, h.clientOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
h.client = client
|
||||
h.uotClient = &uot.Client{
|
||||
Dialer: (anytlsDialer)(client.CreateProxy),
|
||||
Version: uot.Version,
|
||||
}
|
||||
return outbound, nil
|
||||
return nil
|
||||
}
|
||||
|
||||
type anytlsDialer func(ctx context.Context, destination M.Socksaddr) (net.Conn, error)
|
||||
@@ -127,5 +137,5 @@ func (h *Outbound) ListenPacket(ctx context.Context, destination M.Socksaddr) (n
|
||||
}
|
||||
|
||||
func (h *Outbound) Close() error {
|
||||
return common.Close(h.client)
|
||||
return common.Close(common.PtrOrNil(h.client))
|
||||
}
|
||||
|
||||
@@ -151,10 +151,6 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
}
|
||||
stateDirectory = filemanager.BasePath(ctx, os.ExpandEnv(stateDirectory))
|
||||
stateDirectory, _ = filepath.Abs(stateDirectory)
|
||||
mkdirErr := filemanager.MkdirAll(ctx, stateDirectory, 0o700)
|
||||
if mkdirErr != nil {
|
||||
return nil, E.Cause(mkdirErr, "create state directory")
|
||||
}
|
||||
if options.SSHServer != nil && options.SSHServer.Enabled {
|
||||
err := adapter.CheckSecurityFeature(ctx, "Tailscale `ssh_server`")
|
||||
if err != nil {
|
||||
@@ -259,6 +255,10 @@ func NewEndpoint(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
func (t *Endpoint) Start(stage adapter.StartStage) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
mkdirErr := filemanager.MkdirAll(t.ctx, t.server.Dir, 0o700)
|
||||
if mkdirErr != nil {
|
||||
return E.Cause(mkdirErr, "create state directory")
|
||||
}
|
||||
t.server.PeerDNSQueryHandler = (*peerDNSQueryHandler)(t)
|
||||
case adapter.StartStateStart:
|
||||
return t.start()
|
||||
|
||||
+41
-21
@@ -35,6 +35,7 @@ type Outbound struct {
|
||||
outbound.Adapter
|
||||
ctx context.Context
|
||||
logger logger.ContextLogger
|
||||
dialer N.Dialer
|
||||
proxy *proxybridge.Bridge
|
||||
startConf *tor.StartConf
|
||||
options map[string]string
|
||||
@@ -51,10 +52,6 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
}
|
||||
startConf.TempDataDirBase = filemanager.TempPath(ctx)
|
||||
if startConf.DataDir != "" {
|
||||
err := filemanager.MkdirAll(ctx, startConf.DataDir, 0o755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dataDirAbs, _ := filepath.Abs(startConf.DataDir)
|
||||
geoIPPath := filepath.Join(dataDirAbs, "geoip")
|
||||
geoIPInfo, err := filemanager.Stat(ctx, geoIPPath)
|
||||
@@ -68,14 +65,9 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
}
|
||||
torrcFile := filepath.Join(startConf.DataDir, "torrc")
|
||||
torrcInfo, err := filemanager.Stat(ctx, torrcFile)
|
||||
if os.IsNotExist(err) {
|
||||
err = filemanager.WriteFile(ctx, torrcFile, []byte(""), 0o600)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
} else if err != nil {
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return nil, err
|
||||
} else if torrcInfo.IsDir() {
|
||||
} else if err == nil && torrcInfo.IsDir() {
|
||||
return nil, E.New("Tor configuration path is a directory: ", torrcFile)
|
||||
}
|
||||
startConf.TorrcFile = torrcFile
|
||||
@@ -94,26 +86,54 @@ func NewOutbound(ctx context.Context, router adapter.Router, logger log.ContextL
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
proxy, err := proxybridge.New(ctx, logger, "proxy", outboundDialer)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Outbound{
|
||||
Adapter: outbound.NewAdapterWithDialerOptions(C.TypeTor, tag, []string{N.NetworkTCP}, options.DialerOptions),
|
||||
ctx: ctx,
|
||||
logger: logger,
|
||||
proxy: proxy,
|
||||
dialer: outboundDialer,
|
||||
startConf: &startConf,
|
||||
options: options.Options,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (t *Outbound) Start() error {
|
||||
err := t.start()
|
||||
if err != nil {
|
||||
t.Close()
|
||||
func (t *Outbound) Start(stage adapter.StartStage) error {
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
if t.startConf.DataDir == "" {
|
||||
return nil
|
||||
}
|
||||
err := filemanager.MkdirAll(t.ctx, t.startConf.DataDir, 0o755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
torrcInfo, err := filemanager.Stat(t.ctx, t.startConf.TorrcFile)
|
||||
if os.IsNotExist(err) {
|
||||
err = filemanager.WriteFile(t.ctx, t.startConf.TorrcFile, []byte(""), 0o600)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else if err != nil {
|
||||
return err
|
||||
} else if torrcInfo.IsDir() {
|
||||
return E.New("Tor configuration path is a directory: ", t.startConf.TorrcFile)
|
||||
}
|
||||
case adapter.StartStateStart:
|
||||
proxy, err := proxybridge.New(t.ctx, t.logger, "proxy", t.dialer)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
t.proxy = proxy
|
||||
err = proxy.Start()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
err = t.start()
|
||||
if err != nil {
|
||||
t.Close()
|
||||
return err
|
||||
}
|
||||
}
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
var torLogEvents = []control.EventCode{
|
||||
|
||||
@@ -113,6 +113,7 @@ func (s *LocalRuleSet) reloadFile(path string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer setFile.Close()
|
||||
ruleSet, err = srs.Read(setFile, false)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
+40
-27
@@ -48,11 +48,13 @@ var (
|
||||
|
||||
type Service struct {
|
||||
certificate.Adapter
|
||||
ctx context.Context
|
||||
config *certmagic.Config
|
||||
cache *certmagic.Cache
|
||||
domain []string
|
||||
nextProtos []string
|
||||
ctx context.Context
|
||||
config *certmagic.Config
|
||||
cache *certmagic.Cache
|
||||
zapLogger *zap.Logger
|
||||
dataDirectory string
|
||||
domain []string
|
||||
nextProtos []string
|
||||
}
|
||||
|
||||
func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag string, options option.ACMECertificateProviderOptions) (adapter.CertificateProviderService, error) {
|
||||
@@ -78,13 +80,12 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
|
||||
return nil, E.New("email is required to use the ZeroSSL ACME endpoint without external_account or account_key")
|
||||
}
|
||||
|
||||
var storage certmagic.Storage
|
||||
var (
|
||||
storage certmagic.Storage
|
||||
dataDirectory string
|
||||
)
|
||||
if options.DataDirectory != "" {
|
||||
dataDirectory := filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
|
||||
err := filemanager.MkdirAll(ctx, dataDirectory, 0o700)
|
||||
if err != nil {
|
||||
return nil, E.Cause(err, "create ACME data directory")
|
||||
}
|
||||
dataDirectory = filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
|
||||
storage = &certmagic.FileStorage{Path: dataDirectory}
|
||||
} else {
|
||||
storage = certmagic.Default.Storage
|
||||
@@ -169,33 +170,45 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
|
||||
}
|
||||
reflect.NewAt(httpClientField.Type(), unsafe.Pointer(httpClientField.UnsafeAddr())).Elem().Set(reflect.ValueOf(acmeHTTPClient))
|
||||
config.Issuers = []certmagic.Issuer{certmagicIssuer}
|
||||
cache := certmagic.NewCache(certmagic.CacheOptions{
|
||||
GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) {
|
||||
return config, nil
|
||||
},
|
||||
Logger: zapLogger,
|
||||
})
|
||||
config = certmagic.New(cache, *config)
|
||||
|
||||
var nextProtos []string
|
||||
if !acmeIssuer.DisableTLSALPNChallenge && acmeIssuer.DNS01Solver == nil {
|
||||
nextProtos = []string{C.ACMETLS1Protocol}
|
||||
}
|
||||
return &Service{
|
||||
Adapter: certificate.NewAdapter(C.TypeACME, tag),
|
||||
ctx: ctx,
|
||||
config: config,
|
||||
cache: cache,
|
||||
domain: options.Domain,
|
||||
nextProtos: nextProtos,
|
||||
Adapter: certificate.NewAdapter(C.TypeACME, tag),
|
||||
ctx: ctx,
|
||||
config: config,
|
||||
zapLogger: zapLogger,
|
||||
dataDirectory: dataDirectory,
|
||||
domain: options.Domain,
|
||||
nextProtos: nextProtos,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Service) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
switch stage {
|
||||
case adapter.StartStateInitialize:
|
||||
if s.dataDirectory != "" {
|
||||
err := filemanager.MkdirAll(s.ctx, s.dataDirectory, 0o700)
|
||||
if err != nil {
|
||||
return E.Cause(err, "create ACME data directory")
|
||||
}
|
||||
}
|
||||
config := s.config
|
||||
cache := certmagic.NewCache(certmagic.CacheOptions{
|
||||
GetConfigForCert: func(certificate certmagic.Certificate) (*certmagic.Config, error) {
|
||||
return config, nil
|
||||
},
|
||||
Logger: s.zapLogger,
|
||||
})
|
||||
config = certmagic.New(cache, *config)
|
||||
s.config = config
|
||||
s.cache = cache
|
||||
case adapter.StartStateStart:
|
||||
return s.config.ManageAsync(s.ctx, s.domain)
|
||||
}
|
||||
return s.config.ManageAsync(s.ctx, s.domain)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Service) Close() error {
|
||||
|
||||
@@ -65,6 +65,7 @@ type Service struct {
|
||||
timeFunc func() time.Time
|
||||
httpClient *http.Client
|
||||
storage certmagic.Storage
|
||||
dataDirectory string
|
||||
storageIssuerKey string
|
||||
storageNamesKey string
|
||||
storageLockKey string
|
||||
@@ -109,14 +110,12 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
|
||||
cancel()
|
||||
return nil, err
|
||||
}
|
||||
var storage certmagic.Storage
|
||||
var (
|
||||
storage certmagic.Storage
|
||||
dataDirectory string
|
||||
)
|
||||
if options.DataDirectory != "" {
|
||||
dataDirectory := filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
|
||||
mkdirErr := filemanager.MkdirAll(ctx, dataDirectory, 0o700)
|
||||
if mkdirErr != nil {
|
||||
cancel()
|
||||
return nil, E.Cause(mkdirErr, "create data directory")
|
||||
}
|
||||
dataDirectory = filemanager.BasePath(ctx, os.ExpandEnv(options.DataDirectory))
|
||||
storage = &certmagic.FileStorage{Path: dataDirectory}
|
||||
} else {
|
||||
storage = certmagic.Default.Storage
|
||||
@@ -140,6 +139,7 @@ func NewCertificateProvider(ctx context.Context, logger log.ContextLogger, tag s
|
||||
timeFunc: timeFunc,
|
||||
httpClient: httpClient,
|
||||
storage: storage,
|
||||
dataDirectory: dataDirectory,
|
||||
storageIssuerKey: storageIssuerKey,
|
||||
storageNamesKey: storageNamesKey,
|
||||
storageLockKey: storageLockKey,
|
||||
@@ -162,7 +162,16 @@ func originCAHTTPClient(ctx context.Context, logger log.ContextLogger, options o
|
||||
}
|
||||
|
||||
func (s *Service) Start(stage adapter.StartStage) error {
|
||||
if stage != adapter.StartStateStart {
|
||||
if stage == adapter.StartStateInitialize {
|
||||
if s.dataDirectory == "" {
|
||||
return nil
|
||||
}
|
||||
err := filemanager.MkdirAll(s.ctx, s.dataDirectory, 0o700)
|
||||
if err != nil {
|
||||
return E.Cause(err, "create data directory")
|
||||
}
|
||||
return nil
|
||||
} else if stage != adapter.StartStateStart {
|
||||
return nil
|
||||
}
|
||||
cachedCertificate, cachedLeaf, err := s.loadCachedCertificate()
|
||||
|
||||
Reference in New Issue
Block a user