Add a customizable HTTP/HTTPS block page for sinkholed queries
Serves a page explaining why a domain was blocked instead of leaving a sinkholed client with a dead connection. Binds its own HTTP/HTTPS listeners with self-signed, per-hostname TLS certs generated on the fly, re-evaluates the requesting client against the policy engine per request, and renders an HTML template editable from Settings with a live preview. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TTKpGMQzpfDsvedu1hvSUf
This commit is contained in:
+27
-13
@@ -12,6 +12,7 @@ import (
|
||||
"github.com/owen/vibedns/internal/auditlog"
|
||||
"github.com/owen/vibedns/internal/auth"
|
||||
"github.com/owen/vibedns/internal/backup"
|
||||
"github.com/owen/vibedns/internal/blockpage"
|
||||
"github.com/owen/vibedns/internal/cache"
|
||||
"github.com/owen/vibedns/internal/config"
|
||||
"github.com/owen/vibedns/internal/database"
|
||||
@@ -30,19 +31,20 @@ const keyCSRFSecret = "security.csrf_key"
|
||||
// App wires every component together and exposes the operations the
|
||||
// management interface performs.
|
||||
type App struct {
|
||||
Boot config.Bootstrap
|
||||
DB *database.DB
|
||||
Runtime *runtimecfg.Manager
|
||||
Cache *cache.Cache
|
||||
Resolver *resolver.Resolver
|
||||
Limiter *ratelimit.Limiter
|
||||
Metrics *metrics.Metrics
|
||||
QueryLog *querylog.Logger
|
||||
Audit *auditlog.Logger
|
||||
Auth *auth.Authenticator
|
||||
Backups *backup.Manager
|
||||
DNS *dnsengine.Server
|
||||
Log *slog.Logger
|
||||
Boot config.Bootstrap
|
||||
DB *database.DB
|
||||
Runtime *runtimecfg.Manager
|
||||
Cache *cache.Cache
|
||||
Resolver *resolver.Resolver
|
||||
Limiter *ratelimit.Limiter
|
||||
Metrics *metrics.Metrics
|
||||
QueryLog *querylog.Logger
|
||||
Audit *auditlog.Logger
|
||||
Auth *auth.Authenticator
|
||||
Backups *backup.Manager
|
||||
DNS *dnsengine.Server
|
||||
BlockPage *blockpage.Server
|
||||
Log *slog.Logger
|
||||
|
||||
cancel context.CancelFunc
|
||||
started time.Time
|
||||
@@ -88,6 +90,7 @@ func New(ctx context.Context, boot config.Bootstrap, db *database.DB, log *slog.
|
||||
QueryLog: a.QueryLog,
|
||||
Log: log,
|
||||
})
|
||||
a.BlockPage = blockpage.New(rt, log)
|
||||
|
||||
// Every subsystem picks up new settings from the same reload event, so a
|
||||
// change in the UI takes effect without a restart.
|
||||
@@ -203,12 +206,23 @@ func (a *App) Start(ctx context.Context) error {
|
||||
a.cancel()
|
||||
return err
|
||||
}
|
||||
|
||||
if settings := a.Runtime.Settings(); settings.BlockPage.Enabled {
|
||||
if err := a.BlockPage.Start(settings.BlockPage.HTTPListen, settings.BlockPage.HTTPSListen); err != nil {
|
||||
a.cancel()
|
||||
_ = a.DNS.Shutdown(context.Background())
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Shutdown stops the DNS listeners and drains the background workers.
|
||||
func (a *App) Shutdown(ctx context.Context) error {
|
||||
err := a.DNS.Shutdown(ctx)
|
||||
if bpErr := a.BlockPage.Shutdown(ctx); bpErr != nil && err == nil {
|
||||
err = bpErr
|
||||
}
|
||||
if a.cancel != nil {
|
||||
a.cancel()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user