nixos/networkd: allow specifying FirewallMark mask

This commit is contained in:
František Hanzlík 2024-07-22 23:51:18 +02:00
parent e7ce68d67b
commit 8b4cd01f90
No known key found for this signature in database
GPG Key ID: 933D4B36973F32F3
3 changed files with 30 additions and 2 deletions

View File

@ -12,6 +12,7 @@ let
concatStringsSep
const
elem
elemAt
filter
filterAttrs
flatten
@ -21,11 +22,14 @@ let
isFloat
isList
isPath
isString
length
makeBinPath
makeSearchPathOutput
mapAttrs
mapAttrsToList
mapNullable
match
mkAfter
mkIf
optional
@ -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
@ -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}";

View File

@ -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")

View File

@ -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"; }
];
};
};
@ -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'")
'';
})