Stub raus, vollständig implementiert:
* Migration 0014: dns_settings (single-row) + dns_zones.forward_to.
Default-Settings sind sinnvoll für die typische LAN-Resolver-Rolle
(1.1.1.1 + 9.9.9.9 upstream, localnet allow, DNSSEC + qname-min on).
* internal/services/dns: CRUD-Repo für zones, records, settings.
* internal/handlers/dns.go: REST /api/v1/dns/zones, /records, /settings
mit Auto-Reload nach jeder Mutation.
* internal/unbound/unbound.cfg.tpl + unbound.go: Renderer schreibt
/etc/unbound/unbound.conf.d/edgeguard.conf direkt (kein Symlink-
Dance, weil AppArmor unbound nur /etc/unbound erlaubt). Local-zones
authoritativ aus dns_records; forward-zones per stub-zone; default-
forwarders catchen alles sonst.
* main.go: dnsRepo + unbound-Reloader injiziert.
* render.go: unbound.New() bekommt Pool.
* postinst:
- Conf-Datei /etc/unbound/unbound.conf.d/edgeguard.conf wird als
edgeguard:edgeguard 0644 angelegt damit Renderer schreiben kann.
- /etc/edgeguard + Service-Subdirs auf 0755 (Squid + Unbound laufen
NICHT als edgeguard, brauchen Read-Traversal).
- Sudoers: systemctl reload unbound.service whitelisted.
* Template: chroot:"" (Conf liegt außerhalb /var/lib/unbound default-
chroot), DNSSEC-Trust-Anchor NICHT setzen (Distro hat schon
root-auto-trust-anchor-file.conf — sonst doppelter Anchor → start
failure).
* Frontend /dns: PageHeader + zwei Tabs (Zones + Resolver-Settings).
Zones-Tab mit Drawer für Records (CRUD pro Zone, A/AAAA/CNAME/TXT/
MX/SRV/NS/PTR/CAA). Sidebar-Eintrag unter Network.
* i18n DE/EN für dns.* Block.
Verified end-to-end: render → unbound restart → dig @127.0.0.1
example.com → 104.20.23.154 / 172.66.147.243.
Version 1.0.34 (mehrere Iterationen wegen AppArmor + chroot + perms).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
75 lines
2.1 KiB
Go
75 lines
2.1 KiB
Go
package main
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/configgen"
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/database"
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/firewall"
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/haproxy"
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/services/configorch"
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/services/secrets"
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/squid"
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/unbound"
|
|
"git.netcell-it.de/projekte/edgeguard-native/internal/wireguard"
|
|
)
|
|
|
|
// cmdRenderConfig regenerates every per-service config file from PG
|
|
// state. Used after package install (postinst), after admin
|
|
// mutations (UI button), or as a manual recovery action.
|
|
//
|
|
// Flags:
|
|
//
|
|
// --no-reload Write configs but skip systemctl reload.
|
|
// --only=svc1,svc2 Run only the named generators.
|
|
func cmdRenderConfig(args []string) int {
|
|
skipReload := false
|
|
var only []string
|
|
for i := 0; i < len(args); i++ {
|
|
switch {
|
|
case args[i] == "--no-reload":
|
|
skipReload = true
|
|
case strings.HasPrefix(args[i], "--only="):
|
|
val := strings.TrimPrefix(args[i], "--only=")
|
|
only = strings.Split(val, ",")
|
|
case args[i] == "-h" || args[i] == "--help":
|
|
fmt.Println("Usage: edgeguard-ctl render-config [--no-reload] [--only=svc1,svc2]")
|
|
return 0
|
|
}
|
|
}
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second)
|
|
defer cancel()
|
|
|
|
pool, err := database.Open(ctx, database.ConnStringFromEnv())
|
|
if err != nil {
|
|
fmt.Fprintln(os.Stderr, "render-config: open db:", err)
|
|
return 1
|
|
}
|
|
defer pool.Close()
|
|
|
|
hap := haproxy.New(pool)
|
|
fw := firewall.New(pool)
|
|
sq := squid.New(pool)
|
|
wg := wireguard.New(pool, secrets.New(""))
|
|
ub := unbound.New(pool)
|
|
if skipReload {
|
|
hap.SkipReload = true
|
|
fw.SkipReload = true
|
|
}
|
|
|
|
gens := []configgen.Generator{hap, fw, sq, wg, ub}
|
|
|
|
results, runErr := configorch.Run(ctx, gens, only)
|
|
fmt.Print(configorch.Summarise(results))
|
|
if runErr != nil {
|
|
fmt.Fprintln(os.Stderr, "render-config aborted:", runErr)
|
|
return 1
|
|
}
|
|
return 0
|
|
}
|