Add VLANs, firewall zones and inter-zone rules
LANs can sit on an 802.1Q VLAN (`vlan` on a trunk `interface`); networkd creates the device and brings the trunk up. LANs belong to a named `zone` (default: their own name). Traffic inside a zone is forwarded freely, traffic between zones is denied unless a `router.firewall.rules` entry allows it (protocol, ports, optional destination inside the target zone). Internet access is now opt-in per LAN (`internet`, default false), replacing the previous allow-out default. Assertions reject unknown zones, bad destinations, duplicate devices, over-long device names and a WAN trunk. Kea subnet IDs now come from the network address so adding LANs does not renumber them and orphan persistent leases. Tests: a five-VM `vlans` check (untagged + two VLANs, shared zone, one-way rules, per-host destination restriction), new assertion cases, parseNet unit tests, and shared test tooling in tests/common.nix. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
+127
-25
@@ -7,44 +7,146 @@ let
|
||||
ip = ipv4.parse;
|
||||
|
||||
failures = lib.runTests {
|
||||
testParse = { expr = ip "192.168.10.1"; expected = 3232238081; };
|
||||
testParseZero = { expr = ip "0.0.0.0"; expected = 0; };
|
||||
testParseMax = { expr = ip "255.255.255.255"; expected = 4294967295; };
|
||||
testParseBadOctet = { expr = ip "192.168.10.256"; expected = null; };
|
||||
testParseShort = { expr = ip "192.168.10"; expected = null; };
|
||||
testParseJunk = { expr = ip "192.168.10.x"; expected = null; };
|
||||
testFormatRoundTrip = { expr = ipv4.format (ip "10.20.30.40"); expected = "10.20.30.40"; };
|
||||
testFormatZero = { expr = ipv4.format 0; expected = "0.0.0.0"; };
|
||||
testNetMask24 = { expr = ipv4.format (ipv4.netMask 24); expected = "255.255.255.0"; };
|
||||
testNetMask20 = { expr = ipv4.format (ipv4.netMask 20); expected = "255.255.240.0"; };
|
||||
testNetMask8 = { expr = ipv4.format (ipv4.netMask 8); expected = "255.0.0.0"; };
|
||||
testCidr24 = { expr = ipv4.cidr "192.168.10.77" 24; expected = "192.168.10.0/24"; };
|
||||
testCidr20 = { expr = ipv4.cidr "172.16.37.1" 20; expected = "172.16.32.0/20"; };
|
||||
testCidr30 = { expr = ipv4.cidr "10.0.0.6" 30; expected = "10.0.0.4/30"; };
|
||||
testParse = {
|
||||
expr = ip "192.168.10.1";
|
||||
expected = 3232238081;
|
||||
};
|
||||
testParseZero = {
|
||||
expr = ip "0.0.0.0";
|
||||
expected = 0;
|
||||
};
|
||||
testParseMax = {
|
||||
expr = ip "255.255.255.255";
|
||||
expected = 4294967295;
|
||||
};
|
||||
testParseBadOctet = {
|
||||
expr = ip "192.168.10.256";
|
||||
expected = null;
|
||||
};
|
||||
testParseShort = {
|
||||
expr = ip "192.168.10";
|
||||
expected = null;
|
||||
};
|
||||
testParseJunk = {
|
||||
expr = ip "192.168.10.x";
|
||||
expected = null;
|
||||
};
|
||||
testParseNetHost = {
|
||||
expr = ipv4.parseNet "10.0.0.5";
|
||||
expected = {
|
||||
address = ip "10.0.0.5";
|
||||
prefixLength = 32;
|
||||
};
|
||||
};
|
||||
testParseNetCidr = {
|
||||
expr = ipv4.parseNet "192.168.10.0/24";
|
||||
expected = {
|
||||
address = ip "192.168.10.0";
|
||||
prefixLength = 24;
|
||||
};
|
||||
};
|
||||
testParseNetZeroPrefix = {
|
||||
expr = ipv4.parseNet "0.0.0.0/0";
|
||||
expected = {
|
||||
address = 0;
|
||||
prefixLength = 0;
|
||||
};
|
||||
};
|
||||
testParseNetPrefixTooLong = {
|
||||
expr = ipv4.parseNet "10.0.0.0/33";
|
||||
expected = null;
|
||||
};
|
||||
testParseNetBadAddress = {
|
||||
expr = ipv4.parseNet "10.0.0.256/24";
|
||||
expected = null;
|
||||
};
|
||||
testParseNetJunk = {
|
||||
expr = ipv4.parseNet "10.0.0.0/x";
|
||||
expected = null;
|
||||
};
|
||||
testFormatRoundTrip = {
|
||||
expr = ipv4.format (ip "10.20.30.40");
|
||||
expected = "10.20.30.40";
|
||||
};
|
||||
testFormatZero = {
|
||||
expr = ipv4.format 0;
|
||||
expected = "0.0.0.0";
|
||||
};
|
||||
testNetMask24 = {
|
||||
expr = ipv4.format (ipv4.netMask 24);
|
||||
expected = "255.255.255.0";
|
||||
};
|
||||
testNetMask20 = {
|
||||
expr = ipv4.format (ipv4.netMask 20);
|
||||
expected = "255.255.240.0";
|
||||
};
|
||||
testNetMask8 = {
|
||||
expr = ipv4.format (ipv4.netMask 8);
|
||||
expected = "255.0.0.0";
|
||||
};
|
||||
testCidr24 = {
|
||||
expr = ipv4.cidr "192.168.10.77" 24;
|
||||
expected = "192.168.10.0/24";
|
||||
};
|
||||
testCidr20 = {
|
||||
expr = ipv4.cidr "172.16.37.1" 20;
|
||||
expected = "172.16.32.0/20";
|
||||
};
|
||||
testCidr30 = {
|
||||
expr = ipv4.cidr "10.0.0.6" 30;
|
||||
expected = "10.0.0.4/30";
|
||||
};
|
||||
testInSubnetYes = {
|
||||
expr = ipv4.inSubnet { address = ip "192.168.10.1"; prefixLength = 24; } (ip "192.168.10.200");
|
||||
expr = ipv4.inSubnet {
|
||||
address = ip "192.168.10.1";
|
||||
prefixLength = 24;
|
||||
} (ip "192.168.10.200");
|
||||
expected = true;
|
||||
};
|
||||
testInSubnetNo = {
|
||||
expr = ipv4.inSubnet { address = ip "192.168.10.1"; prefixLength = 24; } (ip "192.168.11.1");
|
||||
expr = ipv4.inSubnet {
|
||||
address = ip "192.168.10.1";
|
||||
prefixLength = 24;
|
||||
} (ip "192.168.11.1");
|
||||
expected = false;
|
||||
};
|
||||
testOverlapNested = {
|
||||
expr = ipv4.overlaps
|
||||
{ address = ip "10.0.0.1"; prefixLength = 8; }
|
||||
{ address = ip "10.1.2.3"; prefixLength = 24; };
|
||||
expr =
|
||||
ipv4.overlaps
|
||||
{
|
||||
address = ip "10.0.0.1";
|
||||
prefixLength = 8;
|
||||
}
|
||||
{
|
||||
address = ip "10.1.2.3";
|
||||
prefixLength = 24;
|
||||
};
|
||||
expected = true;
|
||||
};
|
||||
testOverlapSame = {
|
||||
expr = ipv4.overlaps
|
||||
{ address = ip "192.168.10.1"; prefixLength = 24; }
|
||||
{ address = ip "192.168.10.9"; prefixLength = 24; };
|
||||
expr =
|
||||
ipv4.overlaps
|
||||
{
|
||||
address = ip "192.168.10.1";
|
||||
prefixLength = 24;
|
||||
}
|
||||
{
|
||||
address = ip "192.168.10.9";
|
||||
prefixLength = 24;
|
||||
};
|
||||
expected = true;
|
||||
};
|
||||
testOverlapDisjoint = {
|
||||
expr = ipv4.overlaps
|
||||
{ address = ip "192.168.10.1"; prefixLength = 24; }
|
||||
{ address = ip "192.168.11.1"; prefixLength = 24; };
|
||||
expr =
|
||||
ipv4.overlaps
|
||||
{
|
||||
address = ip "192.168.10.1";
|
||||
prefixLength = 24;
|
||||
}
|
||||
{
|
||||
address = ip "192.168.11.1";
|
||||
prefixLength = 24;
|
||||
};
|
||||
expected = false;
|
||||
};
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user