1
0
Fork 0
mirror of https://github.com/NixOS/nixpkgs.git synced 2025-06-30 04:55:25 +03:00

nixos/nat: Match iptables behavior with nftables, add externalIP check (#277016)

This commit is contained in:
misuzu 2024-12-02 12:02:45 +02:00 committed by GitHub
commit dd9a2e26ac
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 314 additions and 87 deletions

View file

@ -32,16 +32,21 @@ let
ip46tables -w -t nat -D OUTPUT -j nixos-nat-out 2>/dev/null || true
ip46tables -w -t nat -F nixos-nat-out 2>/dev/null || true
ip46tables -w -t nat -X nixos-nat-out 2>/dev/null || true
ip46tables -w -t filter -D FORWARD -j nixos-filter-forward 2>/dev/null || true
ip46tables -w -t filter -F nixos-filter-forward 2>/dev/null || true
ip46tables -w -t filter -X nixos-filter-forward 2>/dev/null || true
${cfg.extraStopCommands}
'';
mkSetupNat = { iptables, dest, internalIPs, forwardPorts }: ''
mkSetupNat = { iptables, dest, internalIPs, forwardPorts, externalIp }: ''
# 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 \
-i '${iface}' -j MARK --set-mark 1
${iptables} -w -t filter -A nixos-filter-forward \
-i '${iface}' ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} -j ACCEPT
'') cfg.internalInterfaces}
# NAT the marked packets.
@ -54,14 +59,23 @@ let
${concatMapStrings (range: ''
${iptables} -w -t nat -A nixos-nat-post \
-s '${range}' ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} ${dest}
${iptables} -w -t filter -A nixos-filter-forward \
-s '${range}' ${optionalString (cfg.externalInterface != null) "-o ${cfg.externalInterface}"} -j ACCEPT
'') internalIPs}
# Related connections are allowed
${iptables} -w -t filter -A nixos-filter-forward \
-m state --state ESTABLISHED,RELATED -j ACCEPT
# NAT from external ports to internal ports.
${concatMapStrings (fwd: ''
${iptables} -w -t nat -A nixos-nat-pre \
-i ${toString cfg.externalInterface} -p ${fwd.proto} \
--dport ${builtins.toString fwd.sourcePort} \
${optionalString (externalIp != null) "-d ${externalIp}"} --dport ${builtins.toString fwd.sourcePort} \
-j DNAT --to-destination ${fwd.destination}
${iptables} -w -t filter -A nixos-filter-forward \
-i ${toString cfg.externalInterface} -p ${fwd.proto} \
--dport ${builtins.toString fwd.sourcePort} -j ACCEPT
${concatMapStrings (loopbackip:
let
@ -77,15 +91,32 @@ let
-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 \
-d ${loopbackip} -p ${fwd.proto} \
--dport ${builtins.toString fwd.sourcePort} \
-j DNAT --to-destination ${fwd.destination}
${iptables} -w -t nat -A nixos-nat-post \
-d ${destinationIP} -p ${fwd.proto} \
--dport ${destinationPorts} \
-j SNAT --to-source ${loopbackip}
${concatMapStrings (range: ''
${iptables} -w -t nat -A nixos-nat-pre \
-d ${loopbackip} -p ${fwd.proto} -s '${range}' \
--dport ${builtins.toString fwd.sourcePort} \
-j DNAT --to-destination ${fwd.destination}
${iptables} -w -t nat -A nixos-nat-post \
-d ${destinationIP} -p ${fwd.proto} \
-s '${range}' --dport ${destinationPorts} \
-j SNAT --to-source ${loopbackip}
${iptables} -w -t filter -A nixos-filter-forward \
-d ${destinationIP} -p ${fwd.proto} \
-s '${range}' --dport ${destinationPorts} -j ACCEPT
'') internalIPs}
${concatMapStrings (iface: ''
${iptables} -w -t nat -A nixos-nat-pre \
-d ${loopbackip} -p ${fwd.proto} -i '${iface}' \
--dport ${builtins.toString fwd.sourcePort} \
-j DNAT --to-destination ${fwd.destination}
${iptables} -w -t nat -A nixos-nat-post \
-d ${destinationIP} -p ${fwd.proto} \
-i '${iface}' --dport ${destinationPorts} \
-j SNAT --to-source ${loopbackip}
${iptables} -w -t filter -A nixos-filter-forward \
-d ${destinationIP} -p ${fwd.proto} \
-i '${iface}' --dport ${destinationPorts} -j ACCEPT
'') cfg.internalInterfaces}
'') fwd.loopbackIPs}
'') forwardPorts}
'';
@ -96,12 +127,14 @@ let
ip46tables -w -t nat -N nixos-nat-pre
ip46tables -w -t nat -N nixos-nat-post
ip46tables -w -t nat -N nixos-nat-out
ip46tables -w -t filter -N nixos-filter-forward
${mkSetupNat {
iptables = "iptables";
inherit dest;
inherit (cfg) internalIPs;
forwardPorts = filter (x: !(isIPv6 x.destination)) cfg.forwardPorts;
externalIp = cfg.externalIP;
}}
${optionalString cfg.enableIPv6 (mkSetupNat {
@ -109,6 +142,7 @@ let
dest = destIPv6;
internalIPs = cfg.internalIPv6s;
forwardPorts = filter (x: isIPv6 x.destination) cfg.forwardPorts;
externalIp = cfg.externalIPv6;
})}
${optionalString (cfg.dmzHost != null) ''
@ -123,6 +157,7 @@ let
ip46tables -w -t nat -A PREROUTING -j nixos-nat-pre
ip46tables -w -t nat -A POSTROUTING -j nixos-nat-post
ip46tables -w -t nat -A OUTPUT -j nixos-nat-out
ip46tables -w -t filter -A FORWARD -j nixos-filter-forward
'';
in

View file

@ -33,14 +33,14 @@ let
ports = if m == null then throw "bad ip:ports `${IPPorts}'" else elemAt m 1;
};
mkTable = { ipVer, dest, ipSet, forwardPorts, dmzHost }:
mkTable = { ipVer, dest, ipSet, forwardPorts, dmzHost, externalIP }:
let
# nftables maps for port forward
# l4proto . dport : addr . port
# [daddr .] l4proto . dport : addr . port
fwdMap = toNftSet (map
(fwd:
with (splitIPPorts fwd.destination);
"${fwd.proto} . ${toNftRange fwd.sourcePort} : ${IP} . ${ports}"
"${optionalString (externalIP != null) "${externalIP} . "}${fwd.proto} . ${toNftRange fwd.sourcePort} : ${IP} . ${ports}"
)
forwardPorts);
@ -69,7 +69,7 @@ let
type nat hook prerouting priority dstnat;
${optionalString (fwdMap != "") ''
iifname "${cfg.externalInterface}" meta l4proto { tcp, udp } dnat meta l4proto . th dport map { ${fwdMap} } comment "port forward"
iifname "${cfg.externalInterface}" meta l4proto { tcp, udp } dnat ${optionalString (externalIP != null) "${ipVer} daddr . "}meta l4proto . th dport map { ${fwdMap} } comment "port forward"
''}
${optionalString (fwdLoopDnatMap != "") ''
@ -133,7 +133,7 @@ in
ipVer = "ip";
inherit dest ipSet;
forwardPorts = filter (x: !(isIPv6 x.destination)) cfg.forwardPorts;
inherit (cfg) dmzHost;
inherit (cfg) dmzHost externalIP;
};
};
"nixos-nat6" = mkIf cfg.enableIPv6 {
@ -145,6 +145,7 @@ in
ipSet = ipv6Set;
forwardPorts = filter (x: isIPv6 x.destination) cfg.forwardPorts;
dmzHost = null;
externalIP = cfg.externalIPv6;
};
};
};

View file

@ -20,7 +20,10 @@ in
type = types.bool;
default = false;
description = ''
Whether to enable Network Address Translation (NAT).
Whether to enable Network Address Translation (NAT). A
properly configured firewall or a trusted L2 on all network
interfaces is required to prevent unauthorized access to
the internal network.
'';
};
@ -82,7 +85,8 @@ in
The public IP 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.
used. Only connections made to this IP address will be
forwarded to the internal network when using forwardPorts.
'';
};
@ -94,7 +98,8 @@ in
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.
used. Only connections made to this IP address will be
forwarded to the internal network when using forwardPorts.
'';
};