mirror of
https://github.com/AdguardTeam/AdGuardHome.git
synced 2025-10-26 11:27:18 +00:00
Merge branch 'master' into AGDNS-3061-config-modifier
This commit is contained in:
commit
97b798af6a
25
CHANGELOG.md
25
CHANGELOG.md
@ -9,14 +9,21 @@ The format is based on [*Keep a Changelog*](https://keepachangelog.com/en/1.0.0/
|
||||
<!--
|
||||
## [v0.108.0] – TBA
|
||||
|
||||
## [v0.107.64] - 2025-07-15 (APPROX.)
|
||||
## [v0.107.65] - 2025-07-30 (APPROX.)
|
||||
|
||||
See also the [v0.107.64 GitHub milestone][ms-v0.107.64].
|
||||
See also the [v0.107.65 GitHub milestone][ms-v0.107.65].
|
||||
|
||||
[ms-v0.107.64]: https://github.com/AdguardTeam/AdGuardHome/milestone/99?closed=1
|
||||
[ms-v0.107.65]: https://github.com/AdguardTeam/AdGuardHome/milestone/100?closed=1
|
||||
|
||||
NOTE: Add new changes BELOW THIS COMMENT.
|
||||
-->
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
-->
|
||||
|
||||
## [v0.107.64] - 2025-07-28
|
||||
|
||||
See also the [v0.107.64 GitHub milestone][ms-v0.107.64].
|
||||
|
||||
### Security
|
||||
|
||||
@ -31,10 +38,7 @@ NOTE: Add new changes BELOW THIS COMMENT.
|
||||
[#7903]: https://github.com/AdguardTeam/AdGuardHome/issues/7903
|
||||
|
||||
[go-1.24.5]: https://groups.google.com/g/golang-announce/c/gTNJnDXmn34
|
||||
|
||||
<!--
|
||||
NOTE: Add new changes ABOVE THIS COMMENT.
|
||||
-->
|
||||
[ms-v0.107.64]: https://github.com/AdguardTeam/AdGuardHome/milestone/99?closed=1
|
||||
|
||||
## [v0.107.63] - 2025-06-26
|
||||
|
||||
@ -3173,11 +3177,12 @@ See also the [v0.104.2 GitHub milestone][ms-v0.104.2].
|
||||
[ms-v0.104.2]: https://github.com/AdguardTeam/AdGuardHome/milestone/28?closed=1
|
||||
|
||||
<!--
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.64...HEAD
|
||||
[v0.107.64]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.63...v0.107.64
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.65...HEAD
|
||||
[v0.107.65]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.64...v0.107.65
|
||||
-->
|
||||
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.63...HEAD
|
||||
[Unreleased]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.64...HEAD
|
||||
[v0.107.64]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.63...v0.107.64
|
||||
[v0.107.63]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.62...v0.107.63
|
||||
[v0.107.62]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.61...v0.107.62
|
||||
[v0.107.61]: https://github.com/AdguardTeam/AdGuardHome/compare/v0.107.60...v0.107.61
|
||||
|
||||
@ -245,7 +245,7 @@
|
||||
"block_for_this_client_only": "Yalnızca bu istemci için engelle",
|
||||
"unblock_for_this_client_only": "Yalnızca bu istemci için engellemeyi kaldır",
|
||||
"add_persistent_client": "Kalıcı istemci olarak ekle",
|
||||
"time_table_header": "Saat",
|
||||
"time_table_header": "Süre",
|
||||
"date": "Tarih",
|
||||
"domain_name_table_header": "Alan adı",
|
||||
"domain_or_client": "Alan adı veya istemci",
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package aghnet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
@ -102,7 +103,9 @@ func NewHostsContainer(
|
||||
func (hc *HostsContainer) Close() (err error) {
|
||||
log.Debug("%s: closing", hostsContainerPrefix)
|
||||
|
||||
err = errors.Annotate(hc.watcher.Close(), "closing fs watcher: %w")
|
||||
// TODO(s.chzhen): Pass context.
|
||||
ctx := context.TODO()
|
||||
err = errors.Annotate(hc.watcher.Shutdown(ctx), "closing fs watcher: %w")
|
||||
|
||||
// Go on and close the container either way.
|
||||
close(hc.done)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package aghnet_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/netip"
|
||||
"path"
|
||||
"sync/atomic"
|
||||
@ -67,10 +68,10 @@ func TestNewHostsContainer(t *testing.T) {
|
||||
}
|
||||
|
||||
hc, err := aghnet.NewHostsContainer(testFS, &aghtest.FSWatcher{
|
||||
OnStart: func() (_ error) { panic("not implemented") },
|
||||
OnEvents: onEvents,
|
||||
OnAdd: onAdd,
|
||||
OnClose: func() (err error) { return nil },
|
||||
OnStart: func(_ context.Context) (_ error) { panic("not implemented") },
|
||||
OnEvents: onEvents,
|
||||
OnAdd: onAdd,
|
||||
OnShutdown: func(_ context.Context) (err error) { return nil },
|
||||
}, tc.paths...)
|
||||
if tc.wantErr != nil {
|
||||
require.ErrorIs(t, err, tc.wantErr)
|
||||
@ -94,11 +95,11 @@ func TestNewHostsContainer(t *testing.T) {
|
||||
t.Run("nil_fs", func(t *testing.T) {
|
||||
require.Panics(t, func() {
|
||||
_, _ = aghnet.NewHostsContainer(nil, &aghtest.FSWatcher{
|
||||
OnStart: func() (_ error) { panic("not implemented") },
|
||||
OnStart: func(_ context.Context) (_ error) { panic("not implemented") },
|
||||
// Those shouldn't panic.
|
||||
OnEvents: func() (e <-chan struct{}) { return nil },
|
||||
OnAdd: func(name string) (err error) { return nil },
|
||||
OnClose: func() (err error) { return nil },
|
||||
OnEvents: func() (e <-chan struct{}) { return nil },
|
||||
OnAdd: func(name string) (err error) { return nil },
|
||||
OnShutdown: func(_ context.Context) (err error) { return nil },
|
||||
}, p)
|
||||
})
|
||||
})
|
||||
@ -113,10 +114,10 @@ func TestNewHostsContainer(t *testing.T) {
|
||||
const errOnAdd errors.Error = "error"
|
||||
|
||||
errWatcher := &aghtest.FSWatcher{
|
||||
OnStart: func() (_ error) { panic("not implemented") },
|
||||
OnEvents: func() (e <-chan struct{}) { panic("not implemented") },
|
||||
OnAdd: func(name string) (err error) { return errOnAdd },
|
||||
OnClose: func() (err error) { return nil },
|
||||
OnStart: func(_ context.Context) (_ error) { panic("not implemented") },
|
||||
OnEvents: func() (e <-chan struct{}) { panic("not implemented") },
|
||||
OnAdd: func(name string) (err error) { return errOnAdd },
|
||||
OnShutdown: func(_ context.Context) (err error) { return nil },
|
||||
}
|
||||
|
||||
hc, err := aghnet.NewHostsContainer(testFS, errWatcher, p)
|
||||
@ -158,14 +159,14 @@ func TestHostsContainer_refresh(t *testing.T) {
|
||||
t.Cleanup(func() { close(eventsCh) })
|
||||
|
||||
w := &aghtest.FSWatcher{
|
||||
OnStart: func() (_ error) { panic("not implemented") },
|
||||
OnStart: func(_ context.Context) (_ error) { panic("not implemented") },
|
||||
OnEvents: func() (e <-chan event) { return eventsCh },
|
||||
OnAdd: func(name string) (err error) {
|
||||
assert.Equal(t, "dir", name)
|
||||
|
||||
return nil
|
||||
},
|
||||
OnClose: func() (err error) { return nil },
|
||||
OnShutdown: func(_ context.Context) (err error) { return nil },
|
||||
}
|
||||
|
||||
hc, err := aghnet.NewHostsContainer(testFS, w, "dir")
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
package aghos_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testutil.DiscardLogOutput(m)
|
||||
}
|
||||
@ -13,29 +13,33 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestFileWalker_Walk(t *testing.T) {
|
||||
const attribute = `000`
|
||||
// Common file-walker constants.
|
||||
const (
|
||||
attribute = "000"
|
||||
nl = "\n"
|
||||
)
|
||||
|
||||
makeFileWalker := func(_ string) (fw aghos.FileWalker) {
|
||||
return func(r io.Reader) (patterns []string, cont bool, err error) {
|
||||
s := bufio.NewScanner(r)
|
||||
for s.Scan() {
|
||||
line := s.Text()
|
||||
if line == attribute {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
if len(line) != 0 {
|
||||
patterns = append(patterns, path.Join(".", line))
|
||||
}
|
||||
// newFileWalker returns a new file-walker function that reads patterns from an
|
||||
// [io.Reader].
|
||||
func newFileWalker() (fw aghos.FileWalker) {
|
||||
return func(r io.Reader) (patterns []string, cont bool, err error) {
|
||||
s := bufio.NewScanner(r)
|
||||
for s.Scan() {
|
||||
line := s.Text()
|
||||
if line == attribute {
|
||||
return nil, false, nil
|
||||
}
|
||||
|
||||
return patterns, true, s.Err()
|
||||
if len(line) != 0 {
|
||||
patterns = append(patterns, path.Join(".", line))
|
||||
}
|
||||
}
|
||||
|
||||
return patterns, true, s.Err()
|
||||
}
|
||||
}
|
||||
|
||||
const nl = "\n"
|
||||
|
||||
func TestFileWalker_Walk(t *testing.T) {
|
||||
testCases := []struct {
|
||||
testFS fstest.MapFS
|
||||
want assert.BoolAssertionFunc
|
||||
@ -88,7 +92,7 @@ func TestFileWalker_Walk(t *testing.T) {
|
||||
}}
|
||||
|
||||
for _, tc := range testCases {
|
||||
fw := makeFileWalker("")
|
||||
fw := newFileWalker()
|
||||
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ok, err := fw.Walk(tc.testFS, tc.initPattern)
|
||||
@ -100,7 +104,7 @@ func TestFileWalker_Walk(t *testing.T) {
|
||||
|
||||
t.Run("pattern_malformed", func(t *testing.T) {
|
||||
f := fstest.MapFS{}
|
||||
ok, err := makeFileWalker("").Walk(f, "[]")
|
||||
ok, err := newFileWalker().Walk(f, "[]")
|
||||
require.Error(t, err)
|
||||
|
||||
assert.False(t, ok)
|
||||
|
||||
@ -1,15 +1,17 @@
|
||||
package aghos
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/AdguardTeam/golibs/container"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/osutil"
|
||||
"github.com/AdguardTeam/golibs/service"
|
||||
"github.com/fsnotify/fsnotify"
|
||||
)
|
||||
|
||||
@ -23,11 +25,7 @@ type event = struct{}
|
||||
//
|
||||
// TODO(e.burkov): Add tests.
|
||||
type FSWatcher interface {
|
||||
// Start starts watching the added files.
|
||||
Start() (err error)
|
||||
|
||||
// Close stops watching the files and closes an update channel.
|
||||
io.Closer
|
||||
service.Interface
|
||||
|
||||
// Events returns the channel to notify about the file system events.
|
||||
Events() (e <-chan event)
|
||||
@ -39,6 +37,9 @@ type FSWatcher interface {
|
||||
|
||||
// osWatcher tracks the file system provided by the OS.
|
||||
type osWatcher struct {
|
||||
// logger is used for logging the operations of the osWatcher.
|
||||
logger *slog.Logger
|
||||
|
||||
// watcher is the actual notifier that is handled by osWatcher.
|
||||
watcher *fsnotify.Watcher
|
||||
|
||||
@ -54,8 +55,8 @@ type osWatcher struct {
|
||||
const osWatcherPref = "os watcher"
|
||||
|
||||
// NewOSWritesWatcher creates FSWatcher that tracks the real file system of the
|
||||
// OS and notifies only about writing events.
|
||||
func NewOSWritesWatcher() (w FSWatcher, err error) {
|
||||
// OS and notifies only about writing events. l must not be nil.
|
||||
func NewOSWritesWatcher(l *slog.Logger) (w FSWatcher, err error) {
|
||||
defer func() { err = errors.Annotate(err, "%s: %w", osWatcherPref) }()
|
||||
|
||||
var watcher *fsnotify.Watcher
|
||||
@ -65,6 +66,7 @@ func NewOSWritesWatcher() (w FSWatcher, err error) {
|
||||
}
|
||||
|
||||
return &osWatcher{
|
||||
logger: l,
|
||||
watcher: watcher,
|
||||
events: make(chan event, 1),
|
||||
files: container.NewMapSet[string](),
|
||||
@ -74,16 +76,16 @@ func NewOSWritesWatcher() (w FSWatcher, err error) {
|
||||
// type check
|
||||
var _ FSWatcher = (*osWatcher)(nil)
|
||||
|
||||
// Start implements the FSWatcher interface for *osWatcher.
|
||||
func (w *osWatcher) Start() (err error) {
|
||||
go w.handleErrors()
|
||||
go w.handleEvents()
|
||||
// Start implements the [FSWatcher] interface for *osWatcher.
|
||||
func (w *osWatcher) Start(ctx context.Context) (err error) {
|
||||
go w.handleErrors(ctx)
|
||||
go w.handleEvents(ctx)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close implements the FSWatcher interface for *osWatcher.
|
||||
func (w *osWatcher) Close() (err error) {
|
||||
// Shutdown implements the [FSWatcher] interface for *osWatcher.
|
||||
func (w *osWatcher) Shutdown(_ context.Context) (err error) {
|
||||
return w.watcher.Close()
|
||||
}
|
||||
|
||||
@ -120,8 +122,8 @@ func (w *osWatcher) Add(name string) (err error) {
|
||||
|
||||
// handleEvents notifies about the received file system's event if needed. It
|
||||
// is intended to be used as a goroutine.
|
||||
func (w *osWatcher) handleEvents() {
|
||||
defer log.OnPanic(fmt.Sprintf("%s: handling events", osWatcherPref))
|
||||
func (w *osWatcher) handleEvents(ctx context.Context) {
|
||||
defer slogutil.RecoverAndLog(ctx, w.logger)
|
||||
|
||||
defer close(w.events)
|
||||
|
||||
@ -131,33 +133,37 @@ func (w *osWatcher) handleEvents() {
|
||||
continue
|
||||
}
|
||||
|
||||
// Skip the following events assuming that sometimes the same event
|
||||
// occurs several times.
|
||||
for ok := true; ok; {
|
||||
select {
|
||||
case _, ok = <-ch:
|
||||
// Go on.
|
||||
default:
|
||||
ok = false
|
||||
}
|
||||
}
|
||||
skipDuplicates(ch)
|
||||
|
||||
select {
|
||||
case w.events <- event{}:
|
||||
// Go on.
|
||||
default:
|
||||
log.Debug("%s: events buffer is full", osWatcherPref)
|
||||
w.logger.DebugContext(ctx, "events buffer is full")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// skipDuplicates drains the given channel of events, assuming that some events
|
||||
// might occur multiple times.
|
||||
func skipDuplicates(ch <-chan fsnotify.Event) {
|
||||
for {
|
||||
select {
|
||||
case <-ch:
|
||||
// Go on.
|
||||
default:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// handleErrors handles accompanying errors. It used to be called in a separate
|
||||
// goroutine.
|
||||
func (w *osWatcher) handleErrors() {
|
||||
defer log.OnPanic(fmt.Sprintf("%s: handling errors", osWatcherPref))
|
||||
func (w *osWatcher) handleErrors(ctx context.Context) {
|
||||
defer slogutil.RecoverAndLog(ctx, w.logger)
|
||||
|
||||
for err := range w.watcher.Errors {
|
||||
log.Error("%s: %s", osWatcherPref, err)
|
||||
w.logger.ErrorContext(ctx, "handling error", slogutil.KeyError, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,13 +176,13 @@ var _ FSWatcher = EmptyFSWatcher{}
|
||||
|
||||
// Start implements the [FSWatcher] interface for EmptyFSWatcher. It always
|
||||
// returns nil error.
|
||||
func (EmptyFSWatcher) Start() (err error) {
|
||||
func (EmptyFSWatcher) Start(_ context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close implements the [FSWatcher] interface for EmptyFSWatcher. It always
|
||||
// Shutdown implements the [FSWatcher] interface for EmptyFSWatcher. It always
|
||||
// returns nil error.
|
||||
func (EmptyFSWatcher) Close() (err error) {
|
||||
func (EmptyFSWatcher) Shutdown(_ context.Context) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
|
||||
@ -5,9 +5,11 @@ package aghos
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
@ -17,7 +19,6 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
)
|
||||
|
||||
// Default file, binary, and directory permissions.
|
||||
@ -67,8 +68,14 @@ func RunCommand(command string, arguments ...string) (code int, output []byte, e
|
||||
}
|
||||
|
||||
// PIDByCommand searches for process named command and returns its PID ignoring
|
||||
// the PIDs from except. If no processes found, the error returned.
|
||||
func PIDByCommand(command string, except ...int) (pid int, err error) {
|
||||
// the PIDs from except. If no processes found, the error returned. l must not
|
||||
// be nil.
|
||||
func PIDByCommand(
|
||||
ctx context.Context,
|
||||
l *slog.Logger,
|
||||
command string,
|
||||
except ...int,
|
||||
) (pid int, err error) {
|
||||
// Don't use -C flag here since it's a feature of linux's ps
|
||||
// implementation. Use POSIX-compatible flags instead.
|
||||
//
|
||||
@ -101,7 +108,7 @@ func PIDByCommand(command string, except ...int) (pid int, err error) {
|
||||
case 1:
|
||||
// Go on.
|
||||
default:
|
||||
log.Info("warning: %d %s instances found", instNum, command)
|
||||
l.WarnContext(ctx, "instances found", "num", instNum, "command", command)
|
||||
}
|
||||
|
||||
if code := cmd.ProcessState.ExitCode(); code != 0 {
|
||||
|
||||
@ -25,23 +25,23 @@ import (
|
||||
|
||||
// FSWatcher is a fake [aghos.FSWatcher] implementation for tests.
|
||||
type FSWatcher struct {
|
||||
OnStart func() (err error)
|
||||
OnClose func() (err error)
|
||||
OnEvents func() (e <-chan struct{})
|
||||
OnAdd func(name string) (err error)
|
||||
OnStart func(ctx context.Context) (err error)
|
||||
OnShutdown func(ctx context.Context) (err error)
|
||||
OnEvents func() (e <-chan struct{})
|
||||
OnAdd func(name string) (err error)
|
||||
}
|
||||
|
||||
// type check
|
||||
var _ aghos.FSWatcher = (*FSWatcher)(nil)
|
||||
|
||||
// Start implements the [aghos.FSWatcher] interface for *FSWatcher.
|
||||
func (w *FSWatcher) Start() (err error) {
|
||||
return w.OnStart()
|
||||
func (w *FSWatcher) Start(ctx context.Context) (err error) {
|
||||
return w.OnStart(ctx)
|
||||
}
|
||||
|
||||
// Close implements the [aghos.FSWatcher] interface for *FSWatcher.
|
||||
func (w *FSWatcher) Close() (err error) {
|
||||
return w.OnClose()
|
||||
// Shutdown implements the [aghos.FSWatcher] interface for *FSWatcher.
|
||||
func (w *FSWatcher) Shutdown(ctx context.Context) (err error) {
|
||||
return w.OnShutdown(ctx)
|
||||
}
|
||||
|
||||
// Events implements the [aghos.FSWatcher] interface for *FSWatcher.
|
||||
|
||||
@ -2,26 +2,29 @@
|
||||
package aghtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"slices"
|
||||
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/netutil"
|
||||
)
|
||||
|
||||
// init makes sure that the cipher name map is filled.
|
||||
// Init populates the cipherSuites map with the name-to-ID mapping of cipher
|
||||
// suites from crypto/tls. It must be called only once, and it must be called
|
||||
// before any function that calls [ParseCiphers].
|
||||
//
|
||||
// TODO(a.garipov): Propose a similar API to crypto/tls.
|
||||
func init() {
|
||||
func Init(ctx context.Context, l *slog.Logger) {
|
||||
suites := tls.CipherSuites()
|
||||
cipherSuites = make(map[string]uint16, len(suites))
|
||||
for _, s := range suites {
|
||||
cipherSuites[s.Name] = s.ID
|
||||
}
|
||||
|
||||
log.Debug("tls: known ciphers: %q", cipherSuites)
|
||||
l.DebugContext(ctx, "known ciphers", "ciphers", cipherSuites)
|
||||
}
|
||||
|
||||
// cipherSuites are a name-to-ID mapping of cipher suites from crypto/tls. It
|
||||
|
||||
@ -3,17 +3,20 @@ package aghtls_test
|
||||
import (
|
||||
"crypto/tls"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtls"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/testutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
testutil.DiscardLogOutput(m)
|
||||
}
|
||||
// testTimeout is a common timeout for tests and contexts.
|
||||
const testTimeout time.Duration = 1 * time.Second
|
||||
|
||||
func TestParseCiphers(t *testing.T) {
|
||||
aghtls.Init(testutil.ContextWithTimeout(t, testTimeout), slogutil.NewDiscardLogger())
|
||||
|
||||
testCases := []struct {
|
||||
name string
|
||||
wantErrMsg string
|
||||
|
||||
@ -1,7 +1,9 @@
|
||||
package aghtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
// SystemRootCAs tries to load root certificates from the operating system. It
|
||||
@ -9,6 +11,6 @@ import (
|
||||
// default algorithm to find system root CA list.
|
||||
//
|
||||
// See https://github.com/AdguardTeam/AdGuardHome/issues/1311.
|
||||
func SystemRootCAs() (roots *x509.CertPool) {
|
||||
return rootCAs()
|
||||
func SystemRootCAs(ctx context.Context, l *slog.Logger) (roots *x509.CertPool) {
|
||||
return rootCAs(ctx, l)
|
||||
}
|
||||
|
||||
@ -3,15 +3,17 @@
|
||||
package aghtls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
)
|
||||
|
||||
func rootCAs() (roots *x509.CertPool) {
|
||||
func rootCAs(ctx context.Context, l *slog.Logger) (roots *x509.CertPool) {
|
||||
// Directories with the system root certificates, which aren't supported by
|
||||
// Go's crypto/x509.
|
||||
dirs := []string{
|
||||
@ -21,36 +23,51 @@ func rootCAs() (roots *x509.CertPool) {
|
||||
|
||||
roots = x509.NewCertPool()
|
||||
for _, dir := range dirs {
|
||||
dirEnts, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
continue
|
||||
}
|
||||
|
||||
// TODO(a.garipov): Improve error handling here and in other places.
|
||||
log.Error("aghtls: opening directory %q: %s", dir, err)
|
||||
}
|
||||
|
||||
var rootsAdded bool
|
||||
for _, de := range dirEnts {
|
||||
var certData []byte
|
||||
rootFile := filepath.Join(dir, de.Name())
|
||||
certData, err = os.ReadFile(rootFile)
|
||||
if err != nil {
|
||||
log.Error("aghtls: reading root cert: %s", err)
|
||||
} else {
|
||||
if roots.AppendCertsFromPEM(certData) {
|
||||
rootsAdded = true
|
||||
} else {
|
||||
log.Error("aghtls: could not add root from %q", rootFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if rootsAdded {
|
||||
if addCertsFromDir(ctx, l, roots, dir) {
|
||||
return roots
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// addCertsFromDir appends all readable PEM files from dir to pool. It returns
|
||||
// true if at least one certificate was accepted.
|
||||
func addCertsFromDir(
|
||||
ctx context.Context,
|
||||
l *slog.Logger,
|
||||
pool *x509.CertPool,
|
||||
dir string,
|
||||
) (ok bool) {
|
||||
dirEnts, err := os.ReadDir(dir)
|
||||
if err != nil {
|
||||
if !errors.Is(err, os.ErrNotExist) {
|
||||
// TODO(a.garipov): Improve error handling here and in other places.
|
||||
l.ErrorContext(ctx, "opening directory", slogutil.KeyError, err)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
var rootsAdded bool
|
||||
for _, de := range dirEnts {
|
||||
var certData []byte
|
||||
rootFile := filepath.Join(dir, de.Name())
|
||||
certData, err = os.ReadFile(rootFile)
|
||||
if err != nil {
|
||||
l.ErrorContext(ctx, "reading root cert", slogutil.KeyError, err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
if !pool.AppendCertsFromPEM(certData) {
|
||||
l.ErrorContext(ctx, "adding root cert", "file", rootFile, slogutil.KeyError, err)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
rootsAdded = true
|
||||
}
|
||||
|
||||
return rootsAdded
|
||||
}
|
||||
|
||||
@ -2,8 +2,12 @@
|
||||
|
||||
package aghtls
|
||||
|
||||
import "crypto/x509"
|
||||
import (
|
||||
"context"
|
||||
"crypto/x509"
|
||||
"log/slog"
|
||||
)
|
||||
|
||||
func rootCAs() (roots *x509.CertPool) {
|
||||
func rootCAs(_ context.Context, _ *slog.Logger) (roots *x509.CertPool) {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -2,6 +2,7 @@ package dnsforward
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"crypto/ecdsa"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
@ -1454,7 +1455,7 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||
|
||||
var eventsCalledCounter uint32
|
||||
hc, err := aghnet.NewHostsContainer(testFS, &aghtest.FSWatcher{
|
||||
OnStart: func() (_ error) { panic("not implemented") },
|
||||
OnStart: func(_ context.Context) (_ error) { panic("not implemented") },
|
||||
OnEvents: func() (e <-chan struct{}) {
|
||||
assert.Equal(t, uint32(1), atomic.AddUint32(&eventsCalledCounter, 1))
|
||||
|
||||
@ -1465,7 +1466,7 @@ func TestPTRResponseFromHosts(t *testing.T) {
|
||||
|
||||
return nil
|
||||
},
|
||||
OnClose: func() (err error) { panic("not implemented") },
|
||||
OnShutdown: func(_ context.Context) (err error) { panic("not implemented") },
|
||||
}, hostsFilename)
|
||||
require.NoError(t, err)
|
||||
t.Cleanup(func() {
|
||||
|
||||
@ -2,6 +2,7 @@ package dnsforward
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net"
|
||||
@ -360,10 +361,10 @@ func TestServer_HandleTestUpstreamDNS(t *testing.T) {
|
||||
},
|
||||
},
|
||||
&aghtest.FSWatcher{
|
||||
OnStart: func() (_ error) { panic("not implemented") },
|
||||
OnEvents: func() (e <-chan struct{}) { return nil },
|
||||
OnAdd: func(_ string) (err error) { return nil },
|
||||
OnClose: func() (err error) { return nil },
|
||||
OnStart: func(_ context.Context) (_ error) { panic("not implemented") },
|
||||
OnEvents: func() (e <-chan struct{}) { return nil },
|
||||
OnAdd: func(_ string) (err error) { return nil },
|
||||
OnShutdown: func(_ context.Context) (err error) { return nil },
|
||||
},
|
||||
hostsFileName,
|
||||
)
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package filtering_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"testing"
|
||||
@ -43,10 +44,10 @@ func TestDNSFilter_CheckHost_hostsContainer(t *testing.T) {
|
||||
},
|
||||
}
|
||||
watcher := &aghtest.FSWatcher{
|
||||
OnStart: func() (_ error) { panic("not implemented") },
|
||||
OnEvents: func() (e <-chan struct{}) { return nil },
|
||||
OnAdd: func(name string) (err error) { return nil },
|
||||
OnClose: func() (err error) { return nil },
|
||||
OnStart: func(_ context.Context) (_ error) { panic("not implemented") },
|
||||
OnEvents: func() (e <-chan struct{}) { return nil },
|
||||
OnAdd: func(name string) (err error) { return nil },
|
||||
OnShutdown: func(_ context.Context) (err error) { return nil },
|
||||
}
|
||||
hc, err := aghnet.NewHostsContainer(files, watcher, "hosts")
|
||||
require.NoError(t, err)
|
||||
|
||||
@ -502,6 +502,16 @@ var blockedServices = []blockedService{{
|
||||
"||globosat.globo.com^",
|
||||
"||gsatmulti.globo.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "chatgpt",
|
||||
Name: "ChatGPT",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 50 50\"><path d=\"M45.403 25.562c-.506-1.89-1.518-3.553-2.906-4.862 1.134-2.665.963-5.724-.487-8.237-1.391-2.408-3.636-4.131-6.322-4.851-1.891-.506-3.839-.462-5.669.088C28.276 5.382 25.562 4 22.647 4c-4.906 0-9.021 3.416-10.116 7.991-.01.001-.019-.003-.029-.002-2.902.36-5.404 2.019-6.865 4.549-1.391 2.408-1.76 5.214-1.04 7.9.507 1.891 1.519 3.556 2.909 4.865-1.134 2.666-.97 5.714.484 8.234 1.391 2.408 3.636 4.131 6.322 4.851.896.24 1.807.359 2.711.359 1.003 0 1.995-.161 2.957-.45C21.722 44.619 24.425 46 27.353 46c4.911 0 9.028-3.422 10.12-8.003 2.88-.35 5.431-2.006 6.891-4.535 1.39-2.408 1.759-5.214 1.039-7.9zM35.17 9.543c2.171.581 3.984 1.974 5.107 3.919 1.049 1.817 1.243 4 .569 5.967-.099-.062-.193-.131-.294-.19l-9.169-5.294a1.0072 1.0072 0 0 0-1.01.006l-10.198 6.041-.052-4.607 8.663-5.001C30.733 9.26 33 8.963 35.17 9.543zm-5.433 12.652.062 5.504-4.736 2.805-4.799-2.699-.062-5.504 4.736-2.805 4.799 2.699zm-15.502-7.783C14.235 9.773 18.009 6 22.647 6c2.109 0 4.092.916 5.458 2.488-.105.056-.214.103-.318.163l-9.17 5.294c-.312.181-.504.517-.5.877l.133 11.851-4.015-2.258V14.412zm-7.707 9.509c-.581-2.17-.282-4.438.841-6.383 1.06-1.836 2.823-3.074 4.884-3.474-.004.116-.018.23-.018.348V25c0 .361.195.694.51.872l10.329 5.81-3.964 2.348-8.662-5.002c-1.946-1.123-3.338-2.936-3.92-5.107zm8.302 16.536c-2.171-.581-3.984-1.974-5.107-3.919-1.053-1.824-1.249-4.001-.573-5.97.101.063.196.133.299.193l9.169 5.294a.9998.9998 0 0 0 1.01-.006l10.198-6.041.052 4.607-8.663 5.001c-1.946 1.125-4.214 1.424-6.385.841zm20.935-4.869c0 4.639-3.773 8.412-8.412 8.412-2.119 0-4.094-.919-5.459-2.494.105-.056.216-.098.32-.158l9.17-5.294c.312-.181.504-.517.5-.877l-.134-11.85 4.015 2.258v10.003zm6.866-3.126c-1.056 1.83-2.84 3.086-4.884 3.483.004-.12.018-.237.018-.357V25c0-.361-.195-.694-.51-.872l-10.329-5.81 3.964-2.348 8.662 5.002c1.946 1.123 3.338 2.937 3.92 5.107.581 2.17.282 4.438-.841 6.383z\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||chatgpt.com^",
|
||||
"||oaistatic.com^",
|
||||
"||oaiusercontent.com^",
|
||||
"||openai.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "claro",
|
||||
Name: "Claro",
|
||||
@ -530,6 +540,14 @@ var blockedServices = []blockedService{{
|
||||
"||clarovideo.com^",
|
||||
"||usclaro.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "claude",
|
||||
Name: "Claude",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 40 40\"><path d=\"m7.8 26.3 7.7-4.4.1-.4v-.2h-1.8L9.4 21H5.5l-3.7-.2-1-.2-.8-1.2v-.6l.9-.5H2l2.5.3 3.8.2 2.7.2 4 .4h.7v-.3l-.2-.1-.1-.2-4-2.6-4.1-2.8L5 11.8 3.9 11l-.6-.8L3 8.6l1.1-1.2h1.4l.4.2 1.5 1.1 3.1 2.4 4.1 3 .6.6.3-.2v-.1l-.3-.5-2.2-4-2.4-4.1-1-1.7-.3-1A4.9 4.9 0 0 1 9 1.9L10.3.2 11 0l1.7.2.7.6 1 2.3L16 6.8l2.6 5 .7 1.5.4 1.4.2.4h.2v-.3l.2-2.8.4-3.4.4-4.5.1-1.2.7-1.5L23 .6l1 .4.8 1.2-.2.7-.4 3-1 4.8-.5 3.2h.3l.4-.4 1.6-2.1L27.8 8 29 6.6l1.4-1.5 1-.7H33l1.3 1.9-.6 1.9-1.7 2.2-1.5 1.9-2 2.8-1.4 2.2.2.2h.3l4.7-1 2.5-.5 3-.5 1.4.6.2.7-.6 1.3-3.2.8-3.8.8L26 21v.2l2.6.2h3.7l5 .4 1.3 1 .8 1-.1.8-2 1-2.7-.7-6.3-1.5-2.2-.5H26v.2l1.8 1.7 3.3 3 4.1 3.9.2 1-.5.7-.5-.1-3.7-2.7-1.4-1.3-3.1-2.7h-.3v.3l.8 1.1 3.8 5.8.2 1.8-.2.6-1 .3-1.1-.2-2.3-3.2-2.3-3.5-2-3.2-.1.1-1.1 12-.6.6-1.2.4-1-.7-.5-1.3.5-2.4.7-3.2.5-2.5.5-3.1.2-1v-.1h-.2L17 28.4l-3.6 4.9-2.8 3-.7.3-1.2-.6.2-1.1.6-1 4-5 2.3-3 1.5-1.9v-.2L6.7 30.6l-1.9.2L4 30l.1-1.2.4-.4 3.2-2.1Z\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||anthropic.com^",
|
||||
"||claude.ai^",
|
||||
},
|
||||
}, {
|
||||
ID: "cloudflare",
|
||||
Name: "Cloudflare",
|
||||
@ -600,6 +618,13 @@ var blockedServices = []blockedService{{
|
||||
"||dm-event.net^",
|
||||
"||dmcdn.net^",
|
||||
},
|
||||
}, {
|
||||
ID: "deepseek",
|
||||
Name: "DeepSeek",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"0 0 30 30\"><path d=\"M29.7 5.8c-.3-.1-.5.2-.7.3l-.1.2c-.5.5-1 .8-1.7.8a3 3 0 0 0-2.7 1c-.2-1-.8-1.5-1.6-2-.4-.1-.9-.3-1.2-.7l-.4-1c0-.2-.1-.4-.3-.4-.3 0-.4.1-.5.3-.4.7-.5 1.5-.5 2.3a5 5 0 0 0 2.3 4.3c.1 0 .2.2.1.4l-.3 1c0 .2-.2.3-.4.2-.8-.4-1.5-.9-2.2-1.5-1-1-2-2.2-3.2-3a13.8 13.8 0 0 0-.9-.7c-1.2-1.2.2-2.1.5-2.3.3 0 .1-.5-1-.5-1 0-2 .4-3.3.9a3.8 3.8 0 0 1-.6.1 12 12 0 0 0-3.6 0 7.8 7.8 0 0 0-5.6 3.2 9.6 9.6 0 0 0-1.6 7.6c.5 2.8 2 5.2 4.2 7 2.3 2 5 2.9 8 2.7 1.9 0 4-.3 6.3-2.3a7.3 7.3 0 0 0 4.4.3c.9-.2.8-1 .5-1.2-2.4-.8-2.7-1.1-2.7-1.1 1.4-1.7 3.4-3.3 4.3-8.8v-1c0-.3 0-.3.2-.4a5.2 5.2 0 0 0 2-.6c1.7-1 2.4-2.5 2.6-4.3 0-.3 0-.6-.3-.8zm-15.2 17C11.9 20.6 10.6 20 10 20c-.5 0-.4.6-.3 1l.4.9c.2.2.3.5 0 .7-1 .6-2.4-.1-2.5-.2a12.2 12.2 0 0 1-5.7-9.7c0-.5.1-.7.6-.7a5.9 5.9 0 0 1 1.9 0c2.7.3 5 1.5 6.8 3.4 1.1 1 2 2.3 2.8 3.6a17.3 17.3 0 0 0 4.2 4.5c-1 0-2.7.1-3.8-.8zm1.2-8.1a.4.4 0 0 1 .5-.4.4.4 0 0 1 .3.4.4.4 0 0 1-.4.3.4.4 0 0 1-.4-.3zm4 2-.8.2c-.4 0-.8-.2-1-.4-.4-.2-.6-.4-.7-1V15c.1-.5 0-.7-.3-1l-.8-.2a.7.7 0 0 1-.4-.1c-.1 0-.2-.2-.1-.4l.2-.3c.5-.3 1-.2 1.5 0 .4.2.7.5 1.2 1l.9 1.1.5 1c.1.3 0 .5-.3.7z\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||deepseek.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "deezer",
|
||||
Name: "Deezer",
|
||||
@ -2059,6 +2084,16 @@ var blockedServices = []blockedService{{
|
||||
"||nvidianews.com^",
|
||||
"||tegrazone.com^",
|
||||
},
|
||||
}, {
|
||||
ID: "odysee",
|
||||
Name: "Odysee",
|
||||
IconSVG: []byte("<svg xmlns=\"http://www.w3.org/2000/svg\" fill=\"currentColor\" viewBox=\"-11 2 178 178\"><path d=\"M82 57c-14 5-20-2-21-14-1-13 12-17 12-17 14-5 18 2 21 12s1 14-12 19m65 85-9-28a67 67 0 0 0-21-23 5 5 0 0 1 0-8c7-6 18-18 22-25 3-4 7-13 8-20 0-6-1-12-8-15s-11 1-11 1c-5 3-6 12-9 21-4 10-10 11-13 11s-1-3-9-24c-7-21-26-17-40-9-19 11-11 35-6 50-3 2-12 4-21 9l-15 8c-6 6-9 11-7 19a12 12 0 0 0 6 7c5 2 13-1 24-10 9-6 19-9 19-9l13 24c7 13-7 17-8 17-2 0-23-2-18 16s31 12 44 3c14-9 10-38 10-38 13-2 17 12 19 19 1 7-2 19 11 20a21 21 0 0 0 6-1c7-2 11-5 13-9a9 9 0 0 0 0-6M88 33a9 9 0 0 0-2-3h-2v2l1 2 1 1h1l1-3m0 7-1 2a7 7 0 0 1 1 5l1 2h1l1-1c1-3 0-5-1-7l-2-1\"/></svg>"),
|
||||
Rules: []string{
|
||||
"||odycdn.com^",
|
||||
"||odysee.com^",
|
||||
"||odysee.live^",
|
||||
"||odysee.tv^",
|
||||
},
|
||||
}, {
|
||||
ID: "ok",
|
||||
Name: "OK.ru",
|
||||
|
||||
@ -28,7 +28,7 @@ func newClientsContainer(t *testing.T) (c *clientsContainer) {
|
||||
&filtering.Config{
|
||||
Logger: testLogger,
|
||||
},
|
||||
newSignalHandler(nil, nil),
|
||||
newSignalHandler(testLogger, nil, nil),
|
||||
agh.EmptyConfigModifier{},
|
||||
)
|
||||
|
||||
|
||||
@ -23,6 +23,7 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghnet"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghslog"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghtls"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/arpdb"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dhcpd"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/dnsforward"
|
||||
@ -115,13 +116,19 @@ func Main(clientBuildFS fs.FS) {
|
||||
// package flag.
|
||||
opts := loadCmdLineOpts()
|
||||
|
||||
ls := getLogSettings(opts)
|
||||
|
||||
// TODO(a.garipov): Use slog everywhere.
|
||||
baseLogger := newSlogLogger(ls)
|
||||
|
||||
done := make(chan struct{})
|
||||
|
||||
signals := make(chan os.Signal, 1)
|
||||
signal.Notify(signals, syscall.SIGINT, syscall.SIGTERM, syscall.SIGHUP, syscall.SIGQUIT)
|
||||
|
||||
ctx := context.Background()
|
||||
sigHdlr := newSignalHandler(signals, func(ctx context.Context) {
|
||||
sigHdlrLogger := baseLogger.With(slogutil.KeyPrefix, "signalhdlr")
|
||||
sigHdlr := newSignalHandler(sigHdlrLogger, signals, func(ctx context.Context) {
|
||||
cleanup(ctx)
|
||||
cleanupAlways()
|
||||
close(done)
|
||||
@ -130,24 +137,34 @@ func Main(clientBuildFS fs.FS) {
|
||||
go sigHdlr.handle(ctx)
|
||||
|
||||
if opts.serviceControlAction != "" {
|
||||
handleServiceControlAction(opts, clientBuildFS, signals, done, sigHdlr)
|
||||
svcLogger := baseLogger.With(slogutil.KeyPrefix, "service")
|
||||
handleServiceControlAction(
|
||||
ctx,
|
||||
baseLogger,
|
||||
svcLogger,
|
||||
opts,
|
||||
clientBuildFS,
|
||||
signals,
|
||||
done,
|
||||
sigHdlr,
|
||||
)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// run the protection
|
||||
run(opts, clientBuildFS, done, sigHdlr)
|
||||
run(ctx, baseLogger, opts, clientBuildFS, done, sigHdlr)
|
||||
}
|
||||
|
||||
// setupContext initializes [globalContext] fields. It also reads and upgrades
|
||||
// config file if necessary.
|
||||
func setupContext(opts options) (err error) {
|
||||
// config file if necessary. baseLogger must not be nil.
|
||||
func setupContext(ctx context.Context, baseLogger *slog.Logger, opts options) (err error) {
|
||||
globalContext.firstRun = detectFirstRun()
|
||||
|
||||
globalContext.mux = http.NewServeMux()
|
||||
|
||||
if !opts.noEtcHosts {
|
||||
err = setupHostsContainer()
|
||||
err = setupHostsContainer(ctx, baseLogger)
|
||||
if err != nil {
|
||||
// Don't wrap the error, because it's informative enough as is.
|
||||
return err
|
||||
@ -231,9 +248,9 @@ func configureOS(conf *configuration) (err error) {
|
||||
}
|
||||
|
||||
// setupHostsContainer initializes the structures to keep up-to-date the hosts
|
||||
// provided by the OS.
|
||||
func setupHostsContainer() (err error) {
|
||||
hostsWatcher, err := aghos.NewOSWritesWatcher()
|
||||
// provided by the OS. baseLogger must not be nil.
|
||||
func setupHostsContainer(ctx context.Context, baseLogger *slog.Logger) (err error) {
|
||||
hostsWatcher, err := aghos.NewOSWritesWatcher(baseLogger.With(slogutil.KeyPrefix, "oswatcher"))
|
||||
if err != nil {
|
||||
log.Info("WARNING: initializing filesystem watcher: %s; not watching for changes", err)
|
||||
|
||||
@ -247,7 +264,7 @@ func setupHostsContainer() (err error) {
|
||||
|
||||
globalContext.etcHosts, err = aghnet.NewHostsContainer(osutil.RootDirFS(), hostsWatcher, paths...)
|
||||
if err != nil {
|
||||
closeErr := hostsWatcher.Close()
|
||||
closeErr := hostsWatcher.Shutdown(ctx)
|
||||
if errors.Is(err, aghnet.ErrNoHostsPaths) {
|
||||
log.Info("warning: initing hosts container: %s", err)
|
||||
|
||||
@ -257,7 +274,7 @@ func setupHostsContainer() (err error) {
|
||||
return errors.Join(fmt.Errorf("initializing hosts container: %w", err), closeErr)
|
||||
}
|
||||
|
||||
return hostsWatcher.Start()
|
||||
return hostsWatcher.Start(ctx)
|
||||
}
|
||||
|
||||
// setupOpts sets up command-line options.
|
||||
@ -609,7 +626,14 @@ func fatalOnError(err error) {
|
||||
// run configures and starts AdGuard Home.
|
||||
//
|
||||
// TODO(e.burkov): Make opts a pointer.
|
||||
func run(opts options, clientBuildFS fs.FS, done chan struct{}, sigHdlr *signalHandler) {
|
||||
func run(
|
||||
ctx context.Context,
|
||||
slogLogger *slog.Logger,
|
||||
opts options,
|
||||
clientBuildFS fs.FS,
|
||||
done chan struct{},
|
||||
sigHdlr *signalHandler,
|
||||
) {
|
||||
// Configure working dir.
|
||||
err := initWorkingDir(opts)
|
||||
fatalOnError(err)
|
||||
@ -623,10 +647,6 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}, sigHdlr *signalH
|
||||
err = configureLogger(ls)
|
||||
fatalOnError(err)
|
||||
|
||||
// TODO(a.garipov): Use slog everywhere.
|
||||
slogLogger := newSlogLogger(ls)
|
||||
sigHdlr.swapLogger(slogLogger)
|
||||
|
||||
// Print the first message after logger is configured.
|
||||
log.Info("%s", version.Full())
|
||||
log.Debug("current working directory is %s", globalContext.workDir)
|
||||
@ -634,15 +654,14 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}, sigHdlr *signalH
|
||||
log.Info("AdGuard Home is running as a service")
|
||||
}
|
||||
|
||||
err = setupContext(opts)
|
||||
aghtls.Init(ctx, slogLogger.With(slogutil.KeyPrefix, "aghtls"))
|
||||
|
||||
err = setupContext(ctx, slogLogger, opts)
|
||||
fatalOnError(err)
|
||||
|
||||
err = configureOS(config)
|
||||
fatalOnError(err)
|
||||
|
||||
// TODO(s.chzhen): Use it for the entire initialization process.
|
||||
ctx := context.Background()
|
||||
|
||||
// Clients package uses filtering package's static data
|
||||
// (filtering.BlockedSvcKnown()), so we have to initialize filtering static
|
||||
// data first, but also to avoid relying on automatic Go init() function.
|
||||
@ -657,6 +676,7 @@ func run(opts options, clientBuildFS fs.FS, done chan struct{}, sigHdlr *signalH
|
||||
fatalOnError(err)
|
||||
|
||||
tlsMgrLogger := slogLogger.With(slogutil.KeyPrefix, "tls_manager")
|
||||
|
||||
tlsMgr, err := newTLSManager(ctx, &tlsManagerConfig{
|
||||
logger: tlsMgrLogger,
|
||||
confModifier: confModifier,
|
||||
@ -1154,7 +1174,7 @@ func cmdlineUpdate(
|
||||
err = upd.Update(ctx, globalContext.firstRun)
|
||||
fatalOnError(err)
|
||||
|
||||
err = restartService()
|
||||
err = restartService(ctx, l)
|
||||
if err != nil {
|
||||
l.DebugContext(ctx, "restarting service", slogutil.KeyError, err)
|
||||
l.InfoContext(ctx, "AdGuard Home was not installed as a service. "+
|
||||
|
||||
@ -1,8 +1,10 @@
|
||||
package home
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io/fs"
|
||||
"log/slog"
|
||||
"os"
|
||||
"runtime"
|
||||
"strconv"
|
||||
@ -13,8 +15,9 @@ import (
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/aghos"
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/version"
|
||||
"github.com/AdguardTeam/golibs/errors"
|
||||
"github.com/AdguardTeam/golibs/log"
|
||||
"github.com/AdguardTeam/golibs/logutil/slogutil"
|
||||
"github.com/AdguardTeam/golibs/netutil/urlutil"
|
||||
"github.com/AdguardTeam/golibs/osutil"
|
||||
"github.com/kardianos/service"
|
||||
)
|
||||
|
||||
@ -32,10 +35,14 @@ const (
|
||||
// program represents the program that will be launched by as a service or a
|
||||
// daemon.
|
||||
type program struct {
|
||||
// TODO(s.chzhen): Remove this.
|
||||
ctx context.Context
|
||||
clientBuildFS fs.FS
|
||||
signals chan os.Signal
|
||||
done chan struct{}
|
||||
opts options
|
||||
baseLogger *slog.Logger
|
||||
logger *slog.Logger
|
||||
sigHdlr *signalHandler
|
||||
}
|
||||
|
||||
@ -48,14 +55,14 @@ func (p *program) Start(_ service.Service) (err error) {
|
||||
args := p.opts
|
||||
args.runningAsService = true
|
||||
|
||||
go run(args, p.clientBuildFS, p.done, p.sigHdlr)
|
||||
go run(p.ctx, p.baseLogger, args, p.clientBuildFS, p.done, p.sigHdlr)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Stop implements service.Interface interface for *program.
|
||||
func (p *program) Stop(_ service.Service) (err error) {
|
||||
log.Info("service: stopping: waiting for cleanup")
|
||||
p.logger.InfoContext(p.ctx, "stopping: waiting for cleanup")
|
||||
|
||||
aghos.SendShutdownSignal(p.signals)
|
||||
|
||||
@ -84,14 +91,14 @@ func svcStatus(s service.Service) (status service.Status, err error) {
|
||||
return status, err
|
||||
}
|
||||
|
||||
// svcAction performs the action on the service.
|
||||
// svcAction performs the action on the service. l must not be nil.
|
||||
//
|
||||
// On OpenWrt, the service utility may not exist. We use our service script
|
||||
// directly in this case.
|
||||
func svcAction(s service.Service, action string) (err error) {
|
||||
func svcAction(ctx context.Context, l *slog.Logger, s service.Service, action string) (err error) {
|
||||
if action == "start" {
|
||||
if err = aghos.PreCheckActionStart(); err != nil {
|
||||
log.Error("starting service: %s", err)
|
||||
l.ErrorContext(ctx, "starting service", slogutil.KeyError, err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -105,10 +112,10 @@ func svcAction(s service.Service, action string) (err error) {
|
||||
}
|
||||
|
||||
// Send SIGHUP to a process with PID taken from our .pid file. If it doesn't
|
||||
// exist, find our PID using 'ps' command.
|
||||
func sendSigReload() {
|
||||
// exist, find our PID using 'ps' command. baseLogger and l must not be nil.
|
||||
func sendSigReload(ctx context.Context, baseLogger, l *slog.Logger) {
|
||||
if runtime.GOOS == "windows" {
|
||||
log.Error("service: not implemented on windows")
|
||||
l.ErrorContext(ctx, "not implemented on windows")
|
||||
|
||||
return
|
||||
}
|
||||
@ -117,25 +124,26 @@ func sendSigReload() {
|
||||
var pid int
|
||||
data, err := os.ReadFile(pidFile)
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
if pid, err = aghos.PIDByCommand(serviceName, os.Getpid()); err != nil {
|
||||
log.Error("service: finding AdGuardHome process: %s", err)
|
||||
aghosLogger := baseLogger.With(slogutil.KeyPrefix, "aghos")
|
||||
if pid, err = aghos.PIDByCommand(ctx, aghosLogger, serviceName, os.Getpid()); err != nil {
|
||||
l.ErrorContext(ctx, "finding adguardhome process", slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
log.Error("service: reading pid file %s: %s", pidFile, err)
|
||||
l.ErrorContext(ctx, "reading", "pid_file", pidFile, slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
} else {
|
||||
parts := strings.SplitN(string(data), "\n", 2)
|
||||
if len(parts) == 0 {
|
||||
log.Error("service: parsing pid file %s: bad value", pidFile)
|
||||
l.ErrorContext(ctx, "splitting", "pid_file", pidFile, slogutil.KeyError, "bad value")
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if pid, err = strconv.Atoi(strings.TrimSpace(parts[0])); err != nil {
|
||||
log.Error("service: parsing pid from file %s: %s", pidFile, err)
|
||||
l.ErrorContext(ctx, "parsing", "pid_file", pidFile, slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
@ -143,23 +151,23 @@ func sendSigReload() {
|
||||
|
||||
var proc *os.Process
|
||||
if proc, err = os.FindProcess(pid); err != nil {
|
||||
log.Error("service: finding process for pid %d: %s", pid, err)
|
||||
l.ErrorContext(ctx, "finding process for", "pid", pid, slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if err = proc.Signal(syscall.SIGHUP); err != nil {
|
||||
log.Error("service: sending signal HUP to pid %d: %s", pid, err)
|
||||
l.ErrorContext(ctx, "sending sighup to", "pid", pid, slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
log.Debug("service: sent signal to pid %d", pid)
|
||||
l.DebugContext(ctx, "sent sighup to", "pid", pid)
|
||||
}
|
||||
|
||||
// restartService restarts the service. It returns error if the service is not
|
||||
// running.
|
||||
func restartService() (err error) {
|
||||
// running. l must not be nil.
|
||||
func restartService(ctx context.Context, l *slog.Logger) (err error) {
|
||||
// Call chooseSystem explicitly to introduce OpenBSD support for service
|
||||
// package. It's a noop for other GOOS values.
|
||||
chooseSystem()
|
||||
@ -182,7 +190,7 @@ func restartService() (err error) {
|
||||
return fmt.Errorf("initializing service: %w", err)
|
||||
}
|
||||
|
||||
if err = svcAction(s, "restart"); err != nil {
|
||||
if err = svcAction(ctx, l, s, "restart"); err != nil {
|
||||
return fmt.Errorf("restarting service: %w", err)
|
||||
}
|
||||
|
||||
@ -201,6 +209,9 @@ func restartService() (err error) {
|
||||
// it is specified when we register a service, and it indicates to the app
|
||||
// that it is being run as a service/daemon.
|
||||
func handleServiceControlAction(
|
||||
ctx context.Context,
|
||||
baseLogger *slog.Logger,
|
||||
l *slog.Logger,
|
||||
opts options,
|
||||
clientBuildFS fs.FS,
|
||||
signals chan os.Signal,
|
||||
@ -212,25 +223,26 @@ func handleServiceControlAction(
|
||||
chooseSystem()
|
||||
|
||||
action := opts.serviceControlAction
|
||||
log.Info("%s", version.Full())
|
||||
log.Info("service: control action: %s", action)
|
||||
l.InfoContext(ctx, version.Full())
|
||||
l.InfoContext(ctx, "control", "action", action)
|
||||
|
||||
if action == "reload" {
|
||||
sendSigReload()
|
||||
sendSigReload(ctx, baseLogger, l)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
pwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
log.Fatalf("service: getting current directory: %s", err)
|
||||
l.ErrorContext(ctx, "getting current directory", slogutil.KeyError, err)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
|
||||
runOpts := opts
|
||||
runOpts.serviceControlAction = "run"
|
||||
|
||||
args := optsToArgs(runOpts)
|
||||
log.Debug("service: using args %q", args)
|
||||
l.DebugContext(ctx, "using", "args", args)
|
||||
|
||||
svcConfig := &service.Config{
|
||||
Name: serviceName,
|
||||
@ -242,33 +254,45 @@ func handleServiceControlAction(
|
||||
configureService(svcConfig)
|
||||
|
||||
s, err := service.New(&program{
|
||||
ctx: ctx,
|
||||
clientBuildFS: clientBuildFS,
|
||||
signals: signals,
|
||||
done: done,
|
||||
opts: runOpts,
|
||||
baseLogger: l,
|
||||
logger: l.With(slogutil.KeyPrefix, "service"),
|
||||
sigHdlr: sigHdlr,
|
||||
}, svcConfig)
|
||||
if err != nil {
|
||||
log.Fatalf("service: initializing service: %s", err)
|
||||
l.ErrorContext(ctx, "initializing service", slogutil.KeyError, err)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
|
||||
err = handleServiceCommand(s, action, opts)
|
||||
err = handleServiceCommand(ctx, l, s, action, opts)
|
||||
if err != nil {
|
||||
log.Fatalf("service: %s", err)
|
||||
l.ErrorContext(ctx, "handling command", slogutil.KeyError, err)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
|
||||
log.Printf(
|
||||
"service: action %s has been done successfully on %s",
|
||||
action,
|
||||
service.ChosenSystem(),
|
||||
l.InfoContext(
|
||||
ctx,
|
||||
"action has been done successfully",
|
||||
"action", action,
|
||||
"system", service.ChosenSystem(),
|
||||
)
|
||||
}
|
||||
|
||||
// handleServiceCommand handles service command.
|
||||
func handleServiceCommand(s service.Service, action string, opts options) (err error) {
|
||||
func handleServiceCommand(
|
||||
ctx context.Context,
|
||||
l *slog.Logger,
|
||||
s service.Service,
|
||||
action string,
|
||||
opts options,
|
||||
) (err error) {
|
||||
switch action {
|
||||
case "status":
|
||||
handleServiceStatusCommand(s)
|
||||
handleServiceStatusCommand(ctx, l, s)
|
||||
case "run":
|
||||
if err = s.Run(); err != nil {
|
||||
return fmt.Errorf("failed to run service: %w", err)
|
||||
@ -280,11 +304,11 @@ func handleServiceCommand(s service.Service, action string, opts options) (err e
|
||||
|
||||
initConfigFilename(opts)
|
||||
|
||||
handleServiceInstallCommand(s)
|
||||
handleServiceInstallCommand(ctx, l, s)
|
||||
case "uninstall":
|
||||
handleServiceUninstallCommand(s)
|
||||
handleServiceUninstallCommand(ctx, l, s)
|
||||
default:
|
||||
if err = svcAction(s, action); err != nil {
|
||||
if err = svcAction(ctx, l, s, action); err != nil {
|
||||
return fmt.Errorf("executing action %q: %w", action, err)
|
||||
}
|
||||
}
|
||||
@ -297,29 +321,35 @@ func handleServiceCommand(s service.Service, action string, opts options) (err e
|
||||
const statusRestartOnFail = service.StatusStopped + 1
|
||||
|
||||
// handleServiceStatusCommand handles service "status" command.
|
||||
func handleServiceStatusCommand(s service.Service) {
|
||||
func handleServiceStatusCommand(
|
||||
ctx context.Context,
|
||||
l *slog.Logger,
|
||||
s service.Service,
|
||||
) {
|
||||
status, errSt := svcStatus(s)
|
||||
if errSt != nil {
|
||||
log.Fatalf("service: failed to get service status: %s", errSt)
|
||||
l.ErrorContext(ctx, "failed to get service status", slogutil.KeyError, errSt)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
|
||||
switch status {
|
||||
case service.StatusUnknown:
|
||||
log.Printf("service: status is unknown")
|
||||
l.InfoContext(ctx, "status is unknown")
|
||||
case service.StatusStopped:
|
||||
log.Printf("service: stopped")
|
||||
l.InfoContext(ctx, "stopped")
|
||||
case service.StatusRunning:
|
||||
log.Printf("service: running")
|
||||
l.InfoContext(ctx, "running")
|
||||
case statusRestartOnFail:
|
||||
log.Printf("service: restarting after failed start")
|
||||
l.InfoContext(ctx, "restarting after failed start")
|
||||
}
|
||||
}
|
||||
|
||||
// handleServiceInstallCommand handles service "install" command.
|
||||
func handleServiceInstallCommand(s service.Service) {
|
||||
err := svcAction(s, "install")
|
||||
func handleServiceInstallCommand(ctx context.Context, l *slog.Logger, s service.Service) {
|
||||
err := svcAction(ctx, l, s, "install")
|
||||
if err != nil {
|
||||
log.Fatalf("service: executing action %q: %s", "install", err)
|
||||
l.ErrorContext(ctx, "executing install", slogutil.KeyError, err)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
|
||||
if aghos.IsOpenWrt() {
|
||||
@ -328,56 +358,60 @@ func handleServiceInstallCommand(s service.Service) {
|
||||
// startup.
|
||||
_, err = runInitdCommand("enable")
|
||||
if err != nil {
|
||||
log.Fatalf("service: running init enable: %s", err)
|
||||
l.ErrorContext(ctx, "running init enable", slogutil.KeyError, err)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
}
|
||||
|
||||
// Start automatically after install.
|
||||
err = svcAction(s, "start")
|
||||
err = svcAction(ctx, l, s, "start")
|
||||
if err != nil {
|
||||
log.Fatalf("service: starting: %s", err)
|
||||
l.ErrorContext(ctx, "starting", slogutil.KeyError, err)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
log.Printf("service: started")
|
||||
l.InfoContext(ctx, "started")
|
||||
|
||||
if detectFirstRun() {
|
||||
log.Printf(`Almost ready!
|
||||
AdGuard Home is successfully installed and will automatically start on boot.
|
||||
There are a few more things that must be configured before you can use it.
|
||||
Click on the link below and follow the Installation Wizard steps to finish setup.
|
||||
AdGuard Home is now available at the following addresses:`)
|
||||
slogutil.PrintLines(ctx, l, slog.LevelInfo, "", "Almost ready!\n"+
|
||||
"AdGuard Home is successfully installed and will automatically start on boot.\n"+
|
||||
"There are a few more things that must be configured before you can use it.\n"+
|
||||
"Click on the link below and follow the Installation Wizard steps to finish setup.\n"+
|
||||
"AdGuard Home is now available at the following addresses:")
|
||||
printHTTPAddresses(urlutil.SchemeHTTP, nil)
|
||||
}
|
||||
}
|
||||
|
||||
// handleServiceUninstallCommand handles service "uninstall" command.
|
||||
func handleServiceUninstallCommand(s service.Service) {
|
||||
func handleServiceUninstallCommand(ctx context.Context, l *slog.Logger, s service.Service) {
|
||||
if aghos.IsOpenWrt() {
|
||||
// On OpenWrt it is important to run disable command first
|
||||
// as it will remove the symlink
|
||||
_, err := runInitdCommand("disable")
|
||||
if err != nil {
|
||||
log.Fatalf("service: running init disable: %s", err)
|
||||
l.ErrorContext(ctx, "running init disable", slogutil.KeyError, err)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
}
|
||||
|
||||
if err := svcAction(s, "stop"); err != nil {
|
||||
log.Debug("service: executing action %q: %s", "stop", err)
|
||||
if err := svcAction(ctx, l, s, "stop"); err != nil {
|
||||
l.DebugContext(ctx, "executing action stop", slogutil.KeyError, err)
|
||||
}
|
||||
|
||||
if err := svcAction(s, "uninstall"); err != nil {
|
||||
log.Fatalf("service: executing action %q: %s", "uninstall", err)
|
||||
if err := svcAction(ctx, l, s, "uninstall"); err != nil {
|
||||
l.ErrorContext(ctx, "executing action uninstall", slogutil.KeyError, err)
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}
|
||||
|
||||
if runtime.GOOS == "darwin" {
|
||||
// Remove log files on cleanup and log errors.
|
||||
err := os.Remove(launchdStdoutPath)
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Info("service: warning: removing stdout file: %s", err)
|
||||
l.WarnContext(ctx, "removing stdout file", slogutil.KeyError, err)
|
||||
}
|
||||
|
||||
err = os.Remove(launchdStderrPath)
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Info("service: warning: removing stderr file: %s", err)
|
||||
l.WarnContext(ctx, "removing stderr file", slogutil.KeyError, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ import (
|
||||
"log/slog"
|
||||
"os"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"syscall"
|
||||
|
||||
"github.com/AdguardTeam/AdGuardHome/internal/client"
|
||||
@ -16,10 +15,8 @@ import (
|
||||
// signalHandler processes incoming signals. It reloads configurations of
|
||||
// stored entities on SIGHUP and performs cleanup on all other signals.
|
||||
type signalHandler struct {
|
||||
// logger is used to log the operation of the signal handler. Initially,
|
||||
// [slog.Default] is used, but it should be swapped later using
|
||||
// [signalHandler.swapLogger].
|
||||
logger *atomic.Pointer[slog.Logger]
|
||||
// logger is used to log the operation of the signal handler.
|
||||
logger *slog.Logger
|
||||
|
||||
// mu protects clientStorage and tlsManager.
|
||||
mu *sync.Mutex
|
||||
@ -41,24 +38,16 @@ type signalHandler struct {
|
||||
|
||||
// newSignalHandler returns a new properly initialized *signalHandler.
|
||||
func newSignalHandler(
|
||||
l *slog.Logger,
|
||||
signals <-chan os.Signal,
|
||||
cleanup func(ctx context.Context),
|
||||
) (h *signalHandler) {
|
||||
h = &signalHandler{
|
||||
logger: &atomic.Pointer[slog.Logger]{},
|
||||
return &signalHandler{
|
||||
logger: l,
|
||||
mu: &sync.Mutex{},
|
||||
signals: signals,
|
||||
cleanup: cleanup,
|
||||
}
|
||||
|
||||
h.logger.Store(slog.Default())
|
||||
|
||||
return h
|
||||
}
|
||||
|
||||
// swapLogger replaces the stored logger with the given logger.
|
||||
func (h *signalHandler) swapLogger(logger *slog.Logger) {
|
||||
h.logger.Swap(logger)
|
||||
}
|
||||
|
||||
// addClientStorage stores the client storage.
|
||||
@ -89,14 +78,14 @@ func (h *signalHandler) handle(ctx context.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
slogutil.PrintRecovered(ctx, h.logger.Load(), v)
|
||||
slogutil.PrintRecovered(ctx, h.logger, v)
|
||||
|
||||
os.Exit(osutil.ExitCodeFailure)
|
||||
}()
|
||||
|
||||
for {
|
||||
sig := <-h.signals
|
||||
h.logger.Load().InfoContext(ctx, "received signal", "signal", sig)
|
||||
h.logger.InfoContext(ctx, "received signal", "signal", sig)
|
||||
switch sig {
|
||||
case syscall.SIGHUP:
|
||||
h.reloadConfig(ctx)
|
||||
|
||||
@ -99,7 +99,7 @@ func newTLSManager(ctx context.Context, conf *tlsManagerConfig) (m *tlsManager,
|
||||
servePlainDNS: conf.servePlainDNS,
|
||||
}
|
||||
|
||||
m.rootCerts = aghtls.SystemRootCAs()
|
||||
m.rootCerts = aghtls.SystemRootCAs(ctx, conf.logger)
|
||||
|
||||
if len(conf.tlsSettings.OverrideTLSCiphers) > 0 {
|
||||
m.customCipherIDs, err = aghtls.ParseCiphers(config.TLS.OverrideTLSCiphers)
|
||||
|
||||
@ -145,19 +145,15 @@ func NewUpdater(conf *Config) *Updater {
|
||||
}
|
||||
}
|
||||
|
||||
// Update performs the auto-update. It returns an error if the update failed.
|
||||
// Update performs the auto-update. It returns an error if the update fails.
|
||||
// If firstRun is true, it assumes the configuration file doesn't exist.
|
||||
func (u *Updater) Update(ctx context.Context, firstRun bool) (err error) {
|
||||
u.mu.Lock()
|
||||
defer u.mu.Unlock()
|
||||
|
||||
u.logger.InfoContext(ctx, "staring update", "first_run", firstRun)
|
||||
u.logger.InfoContext(ctx, "starting update", "first_run", firstRun)
|
||||
defer func() {
|
||||
if err != nil {
|
||||
u.logger.ErrorContext(ctx, "update failed", slogutil.KeyError, err)
|
||||
} else {
|
||||
u.logger.InfoContext(ctx, "update finished")
|
||||
}
|
||||
u.logUpdateResult(ctx, err)
|
||||
}()
|
||||
|
||||
err = u.prepare(ctx)
|
||||
@ -197,6 +193,17 @@ func (u *Updater) Update(ctx context.Context, firstRun bool) (err error) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// logUpdateResult logs the result of the update operation.
|
||||
func (u *Updater) logUpdateResult(ctx context.Context, err error) {
|
||||
if err != nil {
|
||||
u.logger.ErrorContext(ctx, "update failed", slogutil.KeyError, err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
u.logger.InfoContext(ctx, "update finished")
|
||||
}
|
||||
|
||||
// NewVersion returns the available new version.
|
||||
func (u *Updater) NewVersion() (nv string) {
|
||||
u.mu.RLock()
|
||||
|
||||
@ -169,12 +169,7 @@ run_linter gocognit --over='19' \
|
||||
./internal/home/ \
|
||||
;
|
||||
|
||||
run_linter gocognit --over='18' \
|
||||
./internal/aghtls/ \
|
||||
;
|
||||
|
||||
run_linter gocognit --over='15' \
|
||||
./internal/aghos/ \
|
||||
./internal/filtering/ \
|
||||
;
|
||||
|
||||
@ -190,15 +185,13 @@ run_linter gocognit --over='12' \
|
||||
./internal/filtering/rewrite/ \
|
||||
;
|
||||
|
||||
run_linter gocognit --over='11' \
|
||||
./internal/updater/ \
|
||||
;
|
||||
|
||||
run_linter gocognit --over='10' \
|
||||
./internal/aghalg/ \
|
||||
./internal/aghhttp/ \
|
||||
./internal/aghos/ \
|
||||
./internal/aghrenameio/ \
|
||||
./internal/aghtest/ \
|
||||
./internal/aghtls/ \
|
||||
./internal/aghuser/ \
|
||||
./internal/arpdb/ \
|
||||
./internal/client/ \
|
||||
@ -213,6 +206,7 @@ run_linter gocognit --over='10' \
|
||||
./internal/rdns/ \
|
||||
./internal/schedule/ \
|
||||
./internal/stats/ \
|
||||
./internal/updater/ \
|
||||
./internal/version/ \
|
||||
./internal/whois/ \
|
||||
./scripts/ \
|
||||
|
||||
Loading…
Reference in New Issue
Block a user