diff --git a/lib/strings.nix b/lib/strings.nix index aca9ef45e61..9cbd1494a2b 100644 --- a/lib/strings.nix +++ b/lib/strings.nix @@ -219,6 +219,14 @@ rec { */ escapeShellArgs = concatMapStringsSep " " escapeShellArg; + /* Turn a string into a Nix expression representing that string + + Example: + escapeNixString "hello\${}\n" + => "\"hello\\\${}\\n\"" + */ + escapeNixString = s: escape ["$"] (builtins.toJSON s); + /* Obsolete - use replaceStrings instead. */ replaceChars = builtins.replaceStrings or ( del: new: s: diff --git a/lib/types.nix b/lib/types.nix index 46ed05d288f..88fc90d0597 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -174,6 +174,13 @@ rec { merge = mergeOneOption; }; + strMatching = pattern: mkOptionType { + name = "strMatching ${escapeNixString pattern}"; + description = "string matching the pattern ${pattern}"; + check = x: str.check x && builtins.match pattern x != null; + inherit (str) merge; + }; + # Merge multiple definitions by concatenating them (with the given # separator between the values). separatedString = sep: mkOptionType rec { diff --git a/nixos/doc/manual/development/option-types.xml b/nixos/doc/manual/development/option-types.xml index 83dcf0232d9..ec940d5d2b8 100644 --- a/nixos/doc/manual/development/option-types.xml +++ b/nixos/doc/manual/development/option-types.xml @@ -110,6 +110,12 @@ A string. Multiple definitions are concatenated with a collon ":". + + types.strMatching + A string matching a specific regular expression. Multiple + definitions cannot be merged. The regular expression is processed using + builtins.match. + diff --git a/nixos/modules/services/networking/nat.nix b/nixos/modules/services/networking/nat.nix index 9b04cf557fa..bfaf30c1178 100644 --- a/nixos/modules/services/networking/nat.nix +++ b/nixos/modules/services/networking/nat.nix @@ -131,15 +131,15 @@ in type = with types; listOf (submodule { options = { sourcePort = mkOption { - type = types.int; + type = types.either types.int (types.strMatching "[[:digit:]]+:[[:digit:]]+"); example = 8080; - description = "Source port of the external interface"; + description = "Source port of the external interface; to specify a port range, use a string with a colon (e.g. \"60000:61000\")"; }; destination = mkOption { type = types.str; example = "10.0.0.1:80"; - description = "Forward connection to destination ip:port"; + description = "Forward connection to destination ip:port; to specify a port range, use ip:start-end"; }; proto = mkOption {