TP10: Mesh-WARP-Quelle fuer FM/DW-Spokes auf BF-IP NATen

Spoke-FritzBoxen akzeptieren am WG-Peer nur Quell-IPs aus 10.40.0.0/16; WARP-Clients kommen ueber cf-mesh mit 100.96.0.0/12 und wurden verworfen. src-nat auf wg-hub-Egress legt die Quelle in den AllowedIPs-Raum.

Template (Soll) + idempotenter Job tp10-mesh-nat (manual Plan, nie full-intended). Compliance 145/145, end-to-end verifiziert (Mac/WARP -> 10.95.10.1).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-03 15:56:44 +02:00
parent 08a1aaa80d
commit 1fddf5d798
2 changed files with 30 additions and 0 deletions

View File

@@ -926,6 +926,34 @@ def job_tp45_c_dns():
return [(["crs326-core"], "\n".join(lines), "TP45-c-dns")] return [(["crs326-core"], "\n".join(lines), "TP45-c-dns")]
def job_tp10_mesh_nat():
"""TP10 (2026-10-03): Mesh-WARP-Verkehr Richtung FM/DW-Spokes auf eine BF-IP NATen.
WARUM: die Spoke-FritzBoxen akzeptieren am WG-Peer nur Quell-IPs aus 10.40.0.0/16
(AllowedIPs). WARP-Clients kommen ueber cf-mesh mit 100.96.0.0/12 -> die FritzBox
verwirft den Verkehr (bewiesen: ping src=100.96.0.6 -> 100% Loss, src=10.40.20.1
-> 0%). Eine src-nat auf dem wg-hub-Egress legt die Quelle in den AllowedIPs-Raum.
`action=src-nat` (NICHT masquerade): wg-hub hat keine Interface-IP, masquerade
haette keine Quelle. src-nat auf eine feste BF-IP (10.40.10.1) haelt zudem das
Connection-Tracking -- die Antwort an 10.40.10.1 wird im prerouting auf die
Mesh-IP zurueckuebersetzt und via cf-mesh geroutet.
KEIN LOCKOUT-RISIKO: reine srcnat-Ergaenzung; der no-NAT-accept (dst 10.40.0.0/16)
und der WAN-masquerade bleiben unberuehrt, die Regel matcht nur out-interface=wg-hub.
"""
cmt = "TP10: NAT mesh source to WG spokes (AllowedIPs)"
find = f'find where comment="{cmt}"'
add = (f'/ip firewall nat add action=src-nat chain=srcnat comment="{cmt}" '
f'out-interface=wg-hub src-address=100.96.0.0/12 to-addresses=10.40.10.1')
lines = [
f':if ([:len [/ip firewall nat {find}]] = 0) do={{ {add} }} '
f'else={{ :log info "tp10-mesh-nat: Regel existiert schon" }}',
f':log info ("tp10-mesh-nat: regeln=" . [:tostr [:len [/ip firewall nat {find}]]])',
]
return [(["crs326-core"], "\n".join(lines), "TP10-mesh-nat")]
JOBS = { JOBS = {
"drift-cleanup": job_drift_cleanup, "drift-cleanup": job_drift_cleanup,
"mgmt-acl": job_mgmt_acl, "mgmt-acl": job_mgmt_acl,
@@ -938,6 +966,7 @@ JOBS = {
"tp45-v30-leases": job_tp45_v30_leases, "tp45-v30-leases": job_tp45_v30_leases,
"tp45-v30-revert": job_tp45_v30_revert, "tp45-v30-revert": job_tp45_v30_revert,
"tp45-v30-restore": job_tp45_v30_restore, "tp45-v30-restore": job_tp45_v30_restore,
"tp10-mesh-nat": job_tp10_mesh_nat,
} }

View File

@@ -359,6 +359,7 @@
# [7] NAT # [7] NAT
/ip firewall nat add action=accept chain=srcnat comment="TP4: no-NAT inter-VLAN (LAN-internal, before masquerade)" dst-address=10.40.0.0/16 /ip firewall nat add action=accept chain=srcnat comment="TP4: no-NAT inter-VLAN (LAN-internal, before masquerade)" dst-address=10.40.0.0/16
/ip firewall nat add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN /ip firewall nat add action=masquerade chain=srcnat comment="defconf: masquerade" ipsec-policy=out,none out-interface-list=WAN
/ip firewall nat add action=src-nat chain=srcnat comment="TP10: NAT mesh source to WG spokes (AllowedIPs)" out-interface=wg-hub src-address=100.96.0.0/12 to-addresses=10.40.10.1
# [7b] FIREWALL FILTER (TP26, 2026-08-17). Kommt als DATEN aus # [7b] FIREWALL FILTER (TP26, 2026-08-17). Kommt als DATEN aus
# local_config_context_data.firewall_filter, nicht als Templatezeilen — # local_config_context_data.firewall_filter, nicht als Templatezeilen —