Build / build (push) Canceled after 0s
Neuer Wizard-Schritt "Modus wählen" nach der Geräte-Erkennung, mit dem zwischen dem geführten Assistenten und einem Experten-Modus gewählt werden kann. Im Experten-Modus zeigen die bestehenden Schritte zusätzliche, technischere Felder (DHCP-Feinsteuerung, MTU, WPA3, Portbereiche, IP-Sperrlisten, VLAN-Isolation u.a.), die im Laien-Modus verborgen bleiben. Alle neuen Settings-Felder sind optional mit Defaults, die das bisherige Verhalten unverändert lassen (45 Tests grün, 7 davon neu für die Experten-Felder). Zusätzlich zwei beim Live-Testen gefundene Bugs behoben: der letzte Schritt zeigte einen dauerhaft ausgegrauten "Weiter"-Button statt eines "Beenden"-Buttons, und die Texte im neuen Moduswahl-Schritt wurden abgeschnitten (horizontales StackPanel gab TextBlocks unbegrenzte Breite zum Messen, dadurch griff TextWrapping nicht — behoben durch Grid mit fester Spaltenbreite). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
104 lines
4.8 KiB
C#
104 lines
4.8 KiB
C#
namespace MikrotikInstaller.Core.Configuration;
|
|
|
|
/// <summary>
|
|
/// Erzeugt aus den Wizard-Eingaben zusätzliche, logisch getrennte Netzwerke: je VLAN eine eigene
|
|
/// VLAN-Schnittstelle auf der Heimnetz-Bridge mit eigenem Adressbereich und eigenem DHCP-Server.
|
|
/// </summary>
|
|
public static class VlanConfigurator
|
|
{
|
|
public static IReadOnlyList<ConfigurationAction> BuildActions(string parentBridgeName, IReadOnlyList<VlanDefinition> vlans)
|
|
{
|
|
var actions = new List<ConfigurationAction>();
|
|
|
|
foreach (var vlan in vlans)
|
|
{
|
|
var interfaceName = $"vlan{vlan.VlanId}";
|
|
var routerAddress = vlan.RouterAddressCidr.Split('/')[0];
|
|
var networkCidr = IpNetworkHelper.GetNetworkCidr(vlan.RouterAddressCidr);
|
|
var poolName = $"pool-{interfaceName}";
|
|
var dhcpServerName = $"dhcp-{interfaceName}";
|
|
|
|
actions.Add(new ConfigurationAction(
|
|
$"VLAN „{vlan.Name}\" (ID {vlan.VlanId}) auf „{parentBridgeName}\" anlegen",
|
|
(client, ct) => client.AddAsync("/interface/vlan", new Dictionary<string, string>
|
|
{
|
|
["name"] = interfaceName,
|
|
["interface"] = parentBridgeName,
|
|
["vlan-id"] = vlan.VlanId.ToString(),
|
|
}, ct)));
|
|
|
|
actions.Add(new ConfigurationAction(
|
|
$"IP-Adresse {vlan.RouterAddressCidr} für VLAN „{vlan.Name}\" einrichten",
|
|
(client, ct) => client.AddAsync("/ip/address", new Dictionary<string, string>
|
|
{
|
|
["address"] = vlan.RouterAddressCidr,
|
|
["interface"] = interfaceName,
|
|
}, ct)));
|
|
|
|
actions.Add(new ConfigurationAction(
|
|
$"IP-Adressbereich {vlan.DhcpPoolStart}-{vlan.DhcpPoolEnd} für VLAN „{vlan.Name}\" reservieren",
|
|
(client, ct) => client.AddAsync("/ip/pool", new Dictionary<string, string>
|
|
{
|
|
["name"] = poolName,
|
|
["ranges"] = $"{vlan.DhcpPoolStart}-{vlan.DhcpPoolEnd}",
|
|
}, ct)));
|
|
|
|
var dhcpServerParameters = new Dictionary<string, string>
|
|
{
|
|
["name"] = dhcpServerName,
|
|
["interface"] = interfaceName,
|
|
["address-pool"] = poolName,
|
|
["disabled"] = "no",
|
|
};
|
|
if (!string.IsNullOrWhiteSpace(vlan.DhcpLeaseTime))
|
|
{
|
|
dhcpServerParameters["lease-time"] = vlan.DhcpLeaseTime;
|
|
}
|
|
|
|
actions.Add(new ConfigurationAction(
|
|
$"DHCP-Server für VLAN „{vlan.Name}\" aktivieren",
|
|
(client, ct) => client.AddAsync("/ip/dhcp-server", dhcpServerParameters, ct)));
|
|
|
|
actions.Add(new ConfigurationAction(
|
|
$"Netzwerk-Einstellungen (Gateway {routerAddress}) für VLAN „{vlan.Name}\" hinterlegen",
|
|
(client, ct) => client.AddAsync("/ip/dhcp-server/network", new Dictionary<string, string>
|
|
{
|
|
["address"] = networkCidr,
|
|
["gateway"] = routerAddress,
|
|
["dns-server"] = string.IsNullOrWhiteSpace(vlan.DnsServerOverride) ? routerAddress : vlan.DnsServerOverride,
|
|
}, ct)));
|
|
|
|
if (vlan.IsolateFromLan)
|
|
{
|
|
actions.Add(new ConfigurationAction(
|
|
$"VLAN „{vlan.Name}\" vom Heimnetz „{parentBridgeName}\" isolieren",
|
|
(client, ct) => client.AddAsync("/ip/firewall/filter", new Dictionary<string, string>
|
|
{
|
|
["chain"] = "forward",
|
|
["in-interface"] = interfaceName,
|
|
["out-interface"] = parentBridgeName,
|
|
["action"] = "drop",
|
|
}, ct)));
|
|
|
|
actions.Add(new ConfigurationAction(
|
|
$"Heimnetz „{parentBridgeName}\" vor Zugriff aus VLAN „{vlan.Name}\" schützen",
|
|
(client, ct) => client.AddAsync("/ip/firewall/filter", new Dictionary<string, string>
|
|
{
|
|
["chain"] = "forward",
|
|
["in-interface"] = parentBridgeName,
|
|
["out-interface"] = interfaceName,
|
|
["action"] = "drop",
|
|
}, ct)));
|
|
}
|
|
}
|
|
|
|
return actions;
|
|
}
|
|
|
|
/// <summary>Kurze, laientaugliche Zusammenfassung für den Zusammenfassungs-Schritt (keine RouterOS-Fachbegriffe).</summary>
|
|
public static IReadOnlyList<string> BuildFriendlySummary(IReadOnlyList<VlanDefinition> vlans) =>
|
|
vlans
|
|
.Select(vlan => $"„{vlan.Name}\" — ein eigenes, getrenntes Netzwerk ({IpNetworkHelper.GetNetworkCidr(vlan.RouterAddressCidr)}).")
|
|
.ToList();
|
|
}
|