Loading nixos/lib/systemd-lib.nix +23 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ let concatStringsSep const elem elemAt filter filterAttrs flatten Loading @@ -21,11 +22,14 @@ let isFloat isList isPath isString length makeBinPath makeSearchPathOutput mapAttrs mapAttrsToList mapNullable match mkAfter mkIf optional Loading Loading @@ -101,6 +105,8 @@ in rec { optional (attr ? ${name} && ! isByteFormat attr.${name}) "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT]."; toIntBaseDetected = value: assert (match "[0-9]+|0x[0-9a-fA-F]+" value) != null; (builtins.fromTOML "v=${value}").v; hexChars = stringToCharacters "0123456789abcdefABCDEF"; isMacAddress = s: stringLength s == 17 Loading Loading @@ -156,6 +162,23 @@ in rec { optional (attr ? ${name} && !(((isInt attr.${name} || isFloat attr.${name}) && min <= attr.${name} && max >= attr.${name}) || elem attr.${name} values)) "Systemd ${group} field `${name}' is not a value in range [${toString min},${toString max}], or one of ${toString values}"; assertRangeWithOptionalMask = name: min: max: group: attr: if (attr ? ${name}) then if isInt attr.${name} then assertRange name min max group attr else if isString attr.${name} then let fields = match "([0-9]+|0x[0-9a-fA-F]+)(/([0-9]+|0x[0-9a-fA-F]+))?" attr.${name}; in if fields == null then ["Systemd ${group} field `${name}' must either be an integer or two integers separated by a slash (/)."] else let value = toIntBaseDetected (elemAt fields 0); mask = mapNullable toIntBaseDetected (elemAt fields 2); in optional (!(min <= value && max >= value)) "Systemd ${group} field `${name}' has main value outside the range [${toString min},${toString max}]." ++ optional (mask != null && !(min <= mask && max >= mask)) "Systemd ${group} field `${name}' has mask outside the range [${toString min},${toString max}]." else ["Systemd ${group} field `${name}' must either be an integer or a string."] else []; assertMinimum = name: min: group: attr: optional (attr ? ${name} && attr.${name} < min) "Systemd ${group} field `${name}' must be greater than or equal to ${toString min}"; Loading nixos/modules/system/boot/networkd.nix +1 −2 Original line number Diff line number Diff line Loading @@ -778,8 +778,7 @@ let ]) (assertInt "TypeOfService") (assertRange "TypeOfService" 0 255) (assertInt "FirewallMark") (assertRange "FirewallMark" 1 4294967295) (assertRangeWithOptionalMask "FirewallMark" 1 4294967295) (assertInt "Priority") (assertPortOrPortRange "SourcePort") (assertPortOrPortRange "DestinationPort") Loading nixos/tests/systemd-networkd.nix +6 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,8 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: { { Table = 30; From = "192.168.1.1"; To = "192.168.1.2"; SourcePort = 666 ; DestinationPort = 667; } { Table = 40; IPProtocol = "tcp"; InvertRule = true; } { Table = 50; IncomingInterface = "eth1"; Family = "ipv4"; } { Table = 60; FirewallMark = 4; } { Table = 70; FirewallMark = "16/0x1f"; } ]; }; }; Loading Loading @@ -119,5 +121,9 @@ testScript = '' ) # IPProtocol + InvertRule node1.succeed("sudo ip rule | grep 'not from all ipproto tcp lookup 40'") # FirewallMark without a mask node1.succeed("sudo ip rule | grep 'from all fwmark 0x4 lookup 60'") # FirewallMark with a mask node1.succeed("sudo ip rule | grep 'from all fwmark 0x10/0x1f lookup 70'") ''; }) Loading
nixos/lib/systemd-lib.nix +23 −0 Original line number Diff line number Diff line Loading @@ -12,6 +12,7 @@ let concatStringsSep const elem elemAt filter filterAttrs flatten Loading @@ -21,11 +22,14 @@ let isFloat isList isPath isString length makeBinPath makeSearchPathOutput mapAttrs mapAttrsToList mapNullable match mkAfter mkIf optional Loading Loading @@ -101,6 +105,8 @@ in rec { optional (attr ? ${name} && ! isByteFormat attr.${name}) "Systemd ${group} field `${name}' must be in byte format [0-9]+[KMGT]."; toIntBaseDetected = value: assert (match "[0-9]+|0x[0-9a-fA-F]+" value) != null; (builtins.fromTOML "v=${value}").v; hexChars = stringToCharacters "0123456789abcdefABCDEF"; isMacAddress = s: stringLength s == 17 Loading Loading @@ -156,6 +162,23 @@ in rec { optional (attr ? ${name} && !(((isInt attr.${name} || isFloat attr.${name}) && min <= attr.${name} && max >= attr.${name}) || elem attr.${name} values)) "Systemd ${group} field `${name}' is not a value in range [${toString min},${toString max}], or one of ${toString values}"; assertRangeWithOptionalMask = name: min: max: group: attr: if (attr ? ${name}) then if isInt attr.${name} then assertRange name min max group attr else if isString attr.${name} then let fields = match "([0-9]+|0x[0-9a-fA-F]+)(/([0-9]+|0x[0-9a-fA-F]+))?" attr.${name}; in if fields == null then ["Systemd ${group} field `${name}' must either be an integer or two integers separated by a slash (/)."] else let value = toIntBaseDetected (elemAt fields 0); mask = mapNullable toIntBaseDetected (elemAt fields 2); in optional (!(min <= value && max >= value)) "Systemd ${group} field `${name}' has main value outside the range [${toString min},${toString max}]." ++ optional (mask != null && !(min <= mask && max >= mask)) "Systemd ${group} field `${name}' has mask outside the range [${toString min},${toString max}]." else ["Systemd ${group} field `${name}' must either be an integer or a string."] else []; assertMinimum = name: min: group: attr: optional (attr ? ${name} && attr.${name} < min) "Systemd ${group} field `${name}' must be greater than or equal to ${toString min}"; Loading
nixos/modules/system/boot/networkd.nix +1 −2 Original line number Diff line number Diff line Loading @@ -778,8 +778,7 @@ let ]) (assertInt "TypeOfService") (assertRange "TypeOfService" 0 255) (assertInt "FirewallMark") (assertRange "FirewallMark" 1 4294967295) (assertRangeWithOptionalMask "FirewallMark" 1 4294967295) (assertInt "Priority") (assertPortOrPortRange "SourcePort") (assertPortOrPortRange "DestinationPort") Loading
nixos/tests/systemd-networkd.nix +6 −0 Original line number Diff line number Diff line Loading @@ -57,6 +57,8 @@ let generateNodeConf = { lib, pkgs, config, privk, pubk, peerId, nodeId, ...}: { { Table = 30; From = "192.168.1.1"; To = "192.168.1.2"; SourcePort = 666 ; DestinationPort = 667; } { Table = 40; IPProtocol = "tcp"; InvertRule = true; } { Table = 50; IncomingInterface = "eth1"; Family = "ipv4"; } { Table = 60; FirewallMark = 4; } { Table = 70; FirewallMark = "16/0x1f"; } ]; }; }; Loading Loading @@ -119,5 +121,9 @@ testScript = '' ) # IPProtocol + InvertRule node1.succeed("sudo ip rule | grep 'not from all ipproto tcp lookup 40'") # FirewallMark without a mask node1.succeed("sudo ip rule | grep 'from all fwmark 0x4 lookup 60'") # FirewallMark with a mask node1.succeed("sudo ip rule | grep 'from all fwmark 0x10/0x1f lookup 70'") ''; })