feat: Squid Forward-Proxy — vollständig (Renderer + Handler + UI)

Stub raus, vollständig implementiert:

* internal/services/forwardproxy: CRUD-Repo gegen forward_proxy_acls
  (priority desc, action allow|deny).
* internal/handlers/forwardproxy.go: REST /api/v1/forward-proxy/acls
  mit Validation (acl_type-Whitelist verhindert Squid-Reload-Crash
  bei Tippfehlern). Auto-Reload nach jeder Mutation.
* internal/squid/squid.cfg.tpl + squid.go: Renderer schreibt
  /etc/edgeguard/squid/squid.conf, atomic + Symlink von
  /etc/squid/squid.conf (Squid liest Distro-Pfad — gleicher
  Pattern-Fix wie wg-quick). cache_dir 100MB, cache_mem 64MB,
  http_port 3128. Default-Policy: nur localnet (10/8, 172.16/12,
  192.168/16) — verhindert Open-Relay, falls Operator keine ACLs
  anlegt.
* main.go: forwardproxy-Repo + squid-Reloader instanziiert + Handler
  registriert.
* render.go: squid.New() bekommt Pool (war () vorher, Stub-Signatur).
* postinst sudoers: edgeguard darf systemctl reload squid.service.
* Frontend /forward-proxy: PageHeader + DataTable + ACL-Modal mit
  acl_type-Dropdown (13 Squid-Vokabular-Typen), action-Select,
  Priority. Sidebar-Eintrag unter Security.
* i18n DE/EN für fwd.* Block + nav.forwardProxy.

Verified end-to-end: ACL-Insert via SQL, render → squid reload →
curl -x http://127.0.0.1:3128 http://example.com/ → 200.

Version 1.0.26.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Debian
2026-05-11 00:27:05 +02:00
parent e379162a7f
commit 72269f5b7c
16 changed files with 677 additions and 15 deletions

View File

@@ -13,6 +13,7 @@
"ssl": "SSL-Zertifikate",
"vpn": "VPN",
"wireguard": "WireGuard",
"forwardProxy": "Forward-Proxy",
"firewall": "Firewall",
"cluster": "Cluster",
"settings": "Einstellungen",
@@ -398,6 +399,25 @@
"wg": "WireGuard"
}
},
"fwd": {
"title": "Forward-Proxy (Squid)",
"intro": "Squid-basierter Forward-Proxy auf :3128. ACLs werden top-down nach Priority ausgewertet — first-match wins. Wenn keine Regel passt, gewinnt der Default: nur localnet (10/8, 172.16/12, 192.168/16) darf raus.",
"helpTitle": "Tipp zur ACL-Reihenfolge",
"helpBody": "Höhere Priority = wird zuerst geprüft. Beispiel: 'deny .badsite.com' (priority 200) vor 'allow .com' (priority 100). Werte können Listen sein (mehrere Zeilen), Regex je nach acl_type.",
"name": "Name",
"nameExtra": "Squid-konformer Bezeichner — Kleinbuchstaben + _, kein Leerzeichen.",
"aclType": "Typ",
"aclTypeExtra": "Was Squid prüft (Quelle, Domain, Port, …).",
"value": "Wert",
"valueExtra": "Format hängt vom Typ ab — IPs/CIDRs für src/dst, Domain mit führendem . für dstdomain (.example.com matcht auch sub.example.com), Regex für *_regex-Typen.",
"action": "Aktion",
"priority": "Priority",
"priorityExtra": "Höher = wird zuerst geprüft.",
"comment": "Kommentar",
"add": "ACL hinzufügen",
"edit": "ACL bearbeiten",
"deleteConfirm": "ACL {{name}} wirklich löschen?"
},
"common": {
"yes": "Ja",
"no": "Nein",

View File

@@ -13,6 +13,7 @@
"ssl": "SSL certificates",
"vpn": "VPN",
"wireguard": "WireGuard",
"forwardProxy": "Forward proxy",
"firewall": "Firewall",
"cluster": "Cluster",
"settings": "Settings",
@@ -398,6 +399,25 @@
"wg": "WireGuard"
}
},
"fwd": {
"title": "Forward proxy (Squid)",
"intro": "Squid-based forward proxy on :3128. ACLs are evaluated top-down by priority — first match wins. If no rule matches, the default permits only localnet (10/8, 172.16/12, 192.168/16).",
"helpTitle": "ACL ordering tip",
"helpBody": "Higher priority = evaluated first. Example: 'deny .badsite.com' (priority 200) before 'allow .com' (priority 100). Values can be lists (multiple lines), regex depending on acl_type.",
"name": "Name",
"nameExtra": "Squid-conformant identifier — lowercase + _, no spaces.",
"aclType": "Type",
"aclTypeExtra": "What Squid matches (source, domain, port, …).",
"value": "Value",
"valueExtra": "Format depends on type — IPs/CIDRs for src/dst, domain with leading dot for dstdomain (.example.com also matches sub.example.com), regex for *_regex types.",
"action": "Action",
"priority": "Priority",
"priorityExtra": "Higher = evaluated first.",
"comment": "Comment",
"add": "Add ACL",
"edit": "Edit ACL",
"deleteConfirm": "Really delete ACL {{name}}?"
},
"common": {
"yes": "Yes",
"no": "No",