Files
KayandClaude Sonnet 5 5c8b5fd9d2 M8: Mehrere LAN-Interfaces + Netzwerk-Isolation (Firewall-Regeln pro Netzwerk)
lanConfig wird zu lanConfigs: [LanDhcpConfig] (analog zum VLAN-Listen-
Muster) — mehrere physische Interfaces mit je eigenem DHCP-Server.
Neues isolated-Feld auf LanDhcpConfig/VlanEntry: FirewallConfig erzeugt
daraus paarweise Forward-Drop-Regeln zwischen jedem isolierten Netzwerk
und allen anderen konfigurierten Netzwerken (Pair-Dedup bei gegenseitiger
Isolation). Behebt nebenbei, dass VlanStepView bisher Isolation im
Hilfetext behauptete, ohne dass eine Regel das durchsetzte.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01YYoWFMLHACvzzRC8u4iKF9
2026-09-13 19:57:15 +02:00

85 lines
3.4 KiB
Swift

import XCTest
@testable import RouterOSAssistant
final class FirewallConfigTests: XCTestCase {
func testBuildCommandsCoversNatAndSafeFilterDefaults() {
let config = FirewallConfig(wanInterface: "ether1")
let commands = config.buildCommands()
XCTAssertEqual(commands.count, 8)
XCTAssertEqual(commands[0].menuPath, "/ip firewall nat")
XCTAssertEqual(commands[0].arguments["action"], "masquerade")
XCTAssertEqual(commands[0].arguments["out-interface"], "ether1")
XCTAssertEqual(commands[0].arguments["place-before"], "0")
for command in commands.dropFirst() {
XCTAssertEqual(command.menuPath, "/ip firewall filter")
}
}
func testFilterRulesGetIncrementingPlaceBeforeInDeclaredOrder() {
let config = FirewallConfig(wanInterface: "ether1")
let filterCommands = config.buildCommands().dropFirst()
let placeBeforeValues = filterCommands.map { $0.arguments["place-before"] }
XCTAssertEqual(placeBeforeValues, ["0", "1", "2", "3", "4", "5", "6"])
}
func testFinalRuleBlocksUnsolicitedWanTrafficUnlessPortForwarded() {
let config = FirewallConfig(wanInterface: "ether1")
let commands = config.buildCommands()
let dropRule = commands.last!
XCTAssertEqual(dropRule.arguments["chain"], "forward")
XCTAssertEqual(dropRule.arguments["connection-nat-state"], "!dstnat")
XCTAssertEqual(dropRule.arguments["in-interface"], "ether1")
XCTAssertEqual(dropRule.arguments["action"], "drop")
}
func testIsolatedNetworkGetsBidirectionalDropRulesAgainstOtherNetworks() {
let config = FirewallConfig(
wanInterface: "ether1",
networks: [
FirewallConfig.NetworkSegment(interfaceName: "bridge", isolated: true),
FirewallConfig.NetworkSegment(interfaceName: "vlan20", isolated: false)
]
)
let commands = config.buildCommands()
let isolationCommands = commands.dropFirst(8)
XCTAssertEqual(isolationCommands.count, 2)
XCTAssertTrue(isolationCommands.allSatisfy { $0.arguments["chain"] == "forward" && $0.arguments["action"] == "drop" })
let directions = Set(isolationCommands.map { "\($0.arguments["in-interface"]!)->\($0.arguments["out-interface"]!)" })
XCTAssertEqual(directions, ["bridge->vlan20", "vlan20->bridge"])
XCTAssertEqual(isolationCommands.map { $0.arguments["place-before"] }, ["7", "8"])
}
func testMutuallyIsolatedNetworksProduceOnlyOnePairOfRules() {
let config = FirewallConfig(
wanInterface: "ether1",
networks: [
FirewallConfig.NetworkSegment(interfaceName: "bridge", isolated: true),
FirewallConfig.NetworkSegment(interfaceName: "vlan20", isolated: true)
]
)
let isolationCommands = config.buildCommands().dropFirst(8)
XCTAssertEqual(isolationCommands.count, 2)
}
func testNonIsolatedNetworksProduceNoIsolationRules() {
let config = FirewallConfig(
wanInterface: "ether1",
networks: [
FirewallConfig.NetworkSegment(interfaceName: "bridge", isolated: false),
FirewallConfig.NetworkSegment(interfaceName: "vlan20", isolated: false)
]
)
XCTAssertEqual(config.buildCommands().count, 8)
}
}