Remove n0emis as direct maintainer (#365023)
[NixPkgs.git] / nixos / modules / services / networking / nat.nix
blob71a719d6d8db8ef12071c9c524c5d215ffd85851
1 # This module enables Network Address Translation (NAT).
2 # XXX: todo: support multiple upstream links
3 # see http://yesican.chsoft.biz/lartc/MultihomedLinuxNetworking.html
6   config,
7   lib,
8   pkgs,
9   ...
12 with lib;
14 let
16   cfg = config.networking.nat;
22   options = {
24     networking.nat.enable = mkOption {
25       type = types.bool;
26       default = false;
27       description = ''
28         Whether to enable Network Address Translation (NAT). A
29         properly configured firewall or a trusted L2 on all network
30         interfaces is required to prevent unauthorized access to
31         the internal network.
32       '';
33     };
35     networking.nat.enableIPv6 = mkOption {
36       type = types.bool;
37       default = false;
38       description = ''
39         Whether to enable IPv6 NAT.
40       '';
41     };
43     networking.nat.internalInterfaces = mkOption {
44       type = types.listOf types.str;
45       default = [ ];
46       example = [ "eth0" ];
47       description = ''
48         The interfaces for which to perform NAT. Packets coming from
49         these interface and destined for the external interface will
50         be rewritten.
51       '';
52     };
54     networking.nat.internalIPs = mkOption {
55       type = types.listOf types.str;
56       default = [ ];
57       example = [ "192.168.1.0/24" ];
58       description = ''
59         The IP address ranges for which to perform NAT.  Packets
60         coming from these addresses (on any interface) and destined
61         for the external interface will be rewritten.
62       '';
63     };
65     networking.nat.internalIPv6s = mkOption {
66       type = types.listOf types.str;
67       default = [ ];
68       example = [ "fc00::/64" ];
69       description = ''
70         The IPv6 address ranges for which to perform NAT.  Packets
71         coming from these addresses (on any interface) and destined
72         for the external interface will be rewritten.
73       '';
74     };
76     networking.nat.externalInterface = mkOption {
77       type = types.nullOr types.str;
78       default = null;
79       example = "eth1";
80       description = ''
81         The name of the external network interface.
82       '';
83     };
85     networking.nat.externalIP = mkOption {
86       type = types.nullOr types.str;
87       default = null;
88       example = "203.0.113.123";
89       description = ''
90         The public IP address to which packets from the local
91         network are to be rewritten.  If this is left empty, the
92         IP address associated with the external interface will be
93         used.  Only connections made to this IP address will be
94         forwarded to the internal network when using forwardPorts.
95       '';
96     };
98     networking.nat.externalIPv6 = mkOption {
99       type = types.nullOr types.str;
100       default = null;
101       example = "2001:dc0:2001:11::175";
102       description = ''
103         The public IPv6 address to which packets from the local
104         network are to be rewritten.  If this is left empty, the
105         IP address associated with the external interface will be
106         used.  Only connections made to this IP address will be
107         forwarded to the internal network when using forwardPorts.
108       '';
109     };
111     networking.nat.forwardPorts = mkOption {
112       type =
113         with types;
114         listOf (submodule {
115           options = {
116             sourcePort = mkOption {
117               type = types.either types.int (types.strMatching "[[:digit:]]+:[[:digit:]]+");
118               example = 8080;
119               description = "Source port of the external interface; to specify a port range, use a string with a colon (e.g. \"60000:61000\")";
120             };
122             destination = mkOption {
123               type = types.str;
124               example = "10.0.0.1:80";
125               description = "Forward connection to destination ip:port (or [ipv6]:port); to specify a port range, use ip:start-end";
126             };
128             proto = mkOption {
129               type = types.str;
130               default = "tcp";
131               example = "udp";
132               description = "Protocol of forwarded connection";
133             };
135             loopbackIPs = mkOption {
136               type = types.listOf types.str;
137               default = [ ];
138               example = literalExpression ''[ "55.1.2.3" ]'';
139               description = "Public IPs for NAT reflection; for connections to `loopbackip:sourcePort` from the host itself and from other hosts behind NAT";
140             };
141           };
142         });
143       default = [ ];
144       example = [
145         {
146           sourcePort = 8080;
147           destination = "10.0.0.1:80";
148           proto = "tcp";
149         }
150         {
151           sourcePort = 8080;
152           destination = "[fc00::2]:80";
153           proto = "tcp";
154         }
155       ];
156       description = ''
157         List of forwarded ports from the external interface to
158         internal destinations by using DNAT. Destination can be
159         IPv6 if IPv6 NAT is enabled.
160       '';
161     };
163     networking.nat.dmzHost = mkOption {
164       type = types.nullOr types.str;
165       default = null;
166       example = "10.0.0.1";
167       description = ''
168         The local IP address to which all traffic that does not match any
169         forwarding rule is forwarded.
170       '';
171     };
173   };
175   config = mkIf config.networking.nat.enable {
177     assertions = [
178       {
179         assertion = cfg.enableIPv6 -> config.networking.enableIPv6;
180         message = "networking.nat.enableIPv6 requires networking.enableIPv6";
181       }
182       {
183         assertion = (cfg.dmzHost != null) -> (cfg.externalInterface != null);
184         message = "networking.nat.dmzHost requires networking.nat.externalInterface";
185       }
186       {
187         assertion = (cfg.forwardPorts != [ ]) -> (cfg.externalInterface != null);
188         message = "networking.nat.forwardPorts requires networking.nat.externalInterface";
189       }
190     ];
192     # Use the same iptables package as in config.networking.firewall.
193     # When the firewall is enabled, this should be deduplicated without any
194     # error.
195     environment.systemPackages = [ config.networking.firewall.package ];
197     boot = {
198       kernelModules = [ "nf_nat_ftp" ];
199       kernel.sysctl =
200         {
201           "net.ipv4.conf.all.forwarding" = mkOverride 99 true;
202           "net.ipv4.conf.default.forwarding" = mkOverride 99 true;
203         }
204         // optionalAttrs cfg.enableIPv6 {
205           # Do not prevent IPv6 autoconfiguration.
206           # See <http://strugglers.net/~andy/blog/2011/09/04/linux-ipv6-router-advertisements-and-forwarding/>.
207           "net.ipv6.conf.all.accept_ra" = mkOverride 99 2;
208           "net.ipv6.conf.default.accept_ra" = mkOverride 99 2;
210           # Forward IPv6 packets.
211           "net.ipv6.conf.all.forwarding" = mkOverride 99 true;
212           "net.ipv6.conf.default.forwarding" = mkOverride 99 true;
213         };
214     };
216   };