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:
commit
dd9a2e26ac
6 changed files with 314 additions and 87 deletions
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
@ -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.
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue