aboutsummaryrefslogtreecommitdiff
path: root/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix
diff options
context:
space:
mode:
Diffstat (limited to 'infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix')
-rw-r--r--infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix120
1 files changed, 97 insertions, 23 deletions
diff --git a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix
index 21ae9eb8b6d4..45eb500fe8ce 100644
--- a/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix
+++ b/infra/libkookie/nixpkgs/nixos/modules/services/networking/nat.nix
@@ -9,7 +9,14 @@ with lib;
let
cfg = config.networking.nat;
- dest = if cfg.externalIP == null then "-j MASQUERADE" else "-j SNAT --to-source ${cfg.externalIP}";
+ mkDest = externalIP: if externalIP == null
+ then "-j MASQUERADE"
+ else "-j SNAT --to-source ${externalIP}";
+ dest = mkDest cfg.externalIP;
+ destIPv6 = mkDest cfg.externalIPv6;
+
+ # Whether given IP (plus optional port) is an IPv6.
+ isIPv6 = ip: builtins.length (lib.splitString ":" ip) > 2;
helpers = import ./helpers.nix { inherit config lib; };
@@ -28,63 +35,80 @@ let
${cfg.extraStopCommands}
'';
- setupNat = ''
- ${helpers}
- # Create subchain where we store rules
- ip46tables -w -t nat -N nixos-nat-pre
- ip46tables -w -t nat -N nixos-nat-post
- ip46tables -w -t nat -N nixos-nat-out
-
+ mkSetupNat = { iptables, dest, internalIPs, forwardPorts }: ''
# We can't match on incoming interface in POSTROUTING, so
# mark packets coming from the internal interfaces.
${concatMapStrings (iface: ''
- iptables -w -t nat -A nixos-nat-pre \
+ ${iptables} -w -t nat -A nixos-nat-pre \
-i '${iface}' -j MARK --set-mark 1
'') cfg.internalInterfaces}
# NAT the marked packets.
${optionalString (cfg.internalInterfaces != []) ''
- iptables -w -t nat -A nixos-nat-post -m mark --mark 1 \
+ ${iptables} -w -t nat -A nixos-nat-post -m mark --mark 1 \
${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} ${dest}
''}
# NAT packets coming from the internal IPs.
${concatMapStrings (range: ''
- iptables -w -t nat -A nixos-nat-post \
+ ${iptables} -w -t nat -A nixos-nat-post \
-s '${range}' ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} ${dest}
- '') cfg.internalIPs}
+ '') internalIPs}
# NAT from external ports to internal ports.
${concatMapStrings (fwd: ''
- iptables -w -t nat -A nixos-nat-pre \
+ ${iptables} -w -t nat -A nixos-nat-pre \
-i ${toString cfg.externalInterface} -p ${fwd.proto} \
--dport ${builtins.toString fwd.sourcePort} \
-j DNAT --to-destination ${fwd.destination}
${concatMapStrings (loopbackip:
let
- m = builtins.match "([0-9.]+):([0-9-]+)" fwd.destination;
- destinationIP = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0;
- destinationPorts = if (m == null) then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (elemAt m 1);
+ matchIP = if isIPv6 fwd.destination then "[[]([0-9a-fA-F:]+)[]]" else "([0-9.]+)";
+ m = builtins.match "${matchIP}:([0-9-]+)" fwd.destination;
+ destinationIP = if m == null then throw "bad ip:ports `${fwd.destination}'" else elemAt m 0;
+ destinationPorts = if m == null then throw "bad ip:ports `${fwd.destination}'" else builtins.replaceStrings ["-"] [":"] (elemAt m 1);
in ''
# Allow connections to ${loopbackip}:${toString fwd.sourcePort} from the host itself
- iptables -w -t nat -A nixos-nat-out \
+ ${iptables} -w -t nat -A nixos-nat-out \
-d ${loopbackip} -p ${fwd.proto} \
--dport ${builtins.toString fwd.sourcePort} \
-j DNAT --to-destination ${fwd.destination}
# Allow connections to ${loopbackip}:${toString fwd.sourcePort} from other hosts behind NAT
- iptables -w -t nat -A nixos-nat-pre \
+ ${iptables} -w -t nat -A nixos-nat-pre \
-d ${loopbackip} -p ${fwd.proto} \
--dport ${builtins.toString fwd.sourcePort} \
-j DNAT --to-destination ${fwd.destination}
- iptables -w -t nat -A nixos-nat-post \
+ ${iptables} -w -t nat -A nixos-nat-post \
-d ${destinationIP} -p ${fwd.proto} \
--dport ${destinationPorts} \
-j SNAT --to-source ${loopbackip}
'') fwd.loopbackIPs}
- '') cfg.forwardPorts}
+ '') forwardPorts}
+ '';
+
+ setupNat = ''
+ ${helpers}
+ # Create subchains where we store rules
+ ip46tables -w -t nat -N nixos-nat-pre
+ ip46tables -w -t nat -N nixos-nat-post
+ ip46tables -w -t nat -N nixos-nat-out
+
+ ${mkSetupNat {
+ iptables = "iptables";
+ inherit dest;
+ inherit (cfg) internalIPs;
+ forwardPorts = filter (x: !(isIPv6 x.destination)) cfg.forwardPorts;
+ }}
+
+ ${optionalString cfg.enableIPv6 (mkSetupNat {
+ iptables = "ip6tables";
+ dest = destIPv6;
+ internalIPs = cfg.internalIPv6s;
+ forwardPorts = filter (x: isIPv6 x.destination) cfg.forwardPorts;
+ })}
${optionalString (cfg.dmzHost != null) ''
iptables -w -t nat -A nixos-nat-pre \
@@ -117,6 +141,15 @@ in
'';
};
+ networking.nat.enableIPv6 = mkOption {
+ type = types.bool;
+ default = false;
+ description =
+ ''
+ Whether to enable IPv6 NAT.
+ '';
+ };
+
networking.nat.internalInterfaces = mkOption {
type = types.listOf types.str;
default = [];
@@ -141,6 +174,18 @@ in
'';
};
+ networking.nat.internalIPv6s = mkOption {
+ type = types.listOf types.str;
+ default = [];
+ example = [ "fc00::/64" ];
+ description =
+ ''
+ The IPv6 address ranges for which to perform NAT. Packets
+ coming from these addresses (on any interface) and destined
+ for the external interface will be rewritten.
+ '';
+ };
+
networking.nat.externalInterface = mkOption {
type = types.nullOr types.str;
default = null;
@@ -164,6 +209,19 @@ in
'';
};
+ networking.nat.externalIPv6 = mkOption {
+ type = types.nullOr types.str;
+ default = null;
+ example = "2001:dc0:2001:11::175";
+ description =
+ ''
+ The public IPv6 address to which packets from the local
+ network are to be rewritten. If this is left empty, the
+ IP address associated with the external interface will be
+ used.
+ '';
+ };
+
networking.nat.forwardPorts = mkOption {
type = with types; listOf (submodule {
options = {
@@ -176,7 +234,7 @@ in
destination = mkOption {
type = types.str;
example = "10.0.0.1:80";
- description = "Forward connection to destination ip:port; to specify a port range, use ip:start-end";
+ description = "Forward connection to destination ip:port (or [ipv6]:port); to specify a port range, use ip:start-end";
};
proto = mkOption {
@@ -195,11 +253,15 @@ in
};
});
default = [];
- example = [ { sourcePort = 8080; destination = "10.0.0.1:80"; proto = "tcp"; } ];
+ example = [
+ { sourcePort = 8080; destination = "10.0.0.1:80"; proto = "tcp"; }
+ { sourcePort = 8080; destination = "[fc00::2]:80"; proto = "tcp"; }
+ ];
description =
''
List of forwarded ports from the external interface to
- internal destinations by using DNAT.
+ internal destinations by using DNAT. Destination can be
+ IPv6 if IPv6 NAT is enabled.
'';
};
@@ -246,6 +308,9 @@ in
(mkIf config.networking.nat.enable {
assertions = [
+ { assertion = cfg.enableIPv6 -> config.networking.enableIPv6;
+ message = "networking.nat.enableIPv6 requires networking.enableIPv6";
+ }
{ assertion = (cfg.dmzHost != null) -> (cfg.externalInterface != null);
message = "networking.nat.dmzHost requires networking.nat.externalInterface";
}
@@ -261,6 +326,15 @@ in
kernel.sysctl = {
"net.ipv4.conf.all.forwarding" = mkOverride 99 true;
"net.ipv4.conf.default.forwarding" = mkOverride 99 true;
+ } // optionalAttrs cfg.enableIPv6 {
+ # Do not prevent IPv6 autoconfiguration.
+ # See <http://strugglers.net/~andy/blog/2011/09/04/linux-ipv6-router-advertisements-and-forwarding/>.
+ "net.ipv6.conf.all.accept_ra" = mkOverride 99 2;
+ "net.ipv6.conf.default.accept_ra" = mkOverride 99 2;
+
+ # Forward IPv6 packets.
+ "net.ipv6.conf.all.forwarding" = mkOverride 99 true;
+ "net.ipv6.conf.default.forwarding" = mkOverride 99 true;
};
};