Add per-server NAT egress, ip_forward auto-enable, OPNsense import review checklist

- ServerSetting gains WanInterface/EgressSNATIP for optional per-server
  masquerade/SNAT of client traffic, isolated in each server's own
  nftables table
- wireguard.Start/Restart now ensure net.ipv4.ip_forward and
  net.ipv6.conf.all.forwarding are enabled before bringing an interface up
- OPNsense config.xml import now parses staticroutes/filter/nat rules and
  surfaces them as a manual-review checklist in the preview UI (never
  auto-applied)

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ATVUwTa4Pqwq26orW5BcDW
This commit is contained in:
sysops
2026-07-29 13:08:52 +02:00
co-authored by Claude Sonnet 5
parent cf9c136874
commit 83b1da291f
7 changed files with 1132 additions and 5 deletions
+31
View File
@@ -142,6 +142,16 @@ All Servers
<input type="text" class="form-control" id="_settings_lan_interface" placeholder="e.g. eth0, br-lan">
<small class="form-text text-muted">Optional. Used only for the Firewall Preview - lets peers forward to this interface.</small>
</div>
<div class="form-group">
<label for="_settings_wan_interface" class="control-label">WAN Interface (egress)</label>
<input type="text" class="form-control" id="_settings_wan_interface" placeholder="e.g. eth0">
<small class="form-text text-muted">Optional. Set for full-tunnel/internet-egress clients - NATs this server's client traffic out this interface. Leave empty for site-to-site only (no NAT).</small>
</div>
<div class="form-group">
<label for="_settings_egress_snat_ip" class="control-label">Egress SNAT IP</label>
<input type="text" class="form-control" id="_settings_egress_snat_ip" placeholder="e.g. 203.0.113.5">
<small class="form-text text-muted">Optional. Only needed on multi-IP hosts to pin the source address; leave empty to use plain masquerade.</small>
</div>
<div class="form-group">
<label for="_settings_dns_servers" class="control-label">DNS Servers (override)</label>
<input type="text" class="form-control" id="_settings_dns_servers"
@@ -695,6 +705,8 @@ All Servers
modal.find("#_settings_firewall_mark").val("");
modal.find("#_settings_table").val("");
modal.find("#_settings_lan_interface").val("");
modal.find("#_settings_wan_interface").val("");
modal.find("#_settings_egress_snat_ip").val("");
modal.find("#_settings_dns_servers").val("");
modal.find("#_settings_mtu").val("");
@@ -710,6 +722,8 @@ All Servers
modal.find("#_settings_firewall_mark").val(settings.firewall_mark);
modal.find("#_settings_table").val(settings.table);
modal.find("#_settings_lan_interface").val(settings.lan_interface);
modal.find("#_settings_wan_interface").val(settings.wan_interface);
modal.find("#_settings_egress_snat_ip").val(settings.egress_snat_ip);
modal.find("#_settings_dns_servers").val((settings.dns_servers || []).join(", "));
modal.find("#_settings_mtu").val(settings.mtu || "");
},
@@ -733,6 +747,8 @@ All Servers
"firewall_mark": $("#_settings_firewall_mark").val(),
"table": $("#_settings_table").val(),
"lan_interface": $("#_settings_lan_interface").val(),
"wan_interface": $("#_settings_wan_interface").val(),
"egress_snat_ip": $("#_settings_egress_snat_ip").val(),
"dns_servers": dnsServers,
"mtu": parseInt($("#_settings_mtu").val(), 10) || 0
};
@@ -1099,6 +1115,21 @@ All Servers
area.append(html);
});
if (preview.review_checklist && preview.review_checklist.length) {
const kindLabels = {static_route: "Static route", filter_rule: "Firewall rule", nat_rule: "Outbound NAT"};
let checklistHtml = '<div class="card mb-3 border-warning"><div class="card-header py-1 bg-warning">' +
'<strong>Manual review needed - not imported</strong></div>' +
'<div class="card-body py-2"><p class="text-muted mb-2">' +
'These items existed in the OPNsense config.xml but have no equivalent import path. ' +
'Recreate them manually (e.g. via the WAN Interface/Egress SNAT IP server settings or a custom firewall rule) before cutover.</p>' +
'<ul class="mb-0">';
$.each(preview.review_checklist, function (i, item) {
checklistHtml += '<li><strong>' + (kindLabels[item.kind] || item.kind) + ':</strong> ' + item.description + '</li>';
});
checklistHtml += '</ul></div></div>';
area.append(checklistHtml);
}
$("#btn_opnsense_confirm").show();
}