| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  | # This module enables Network Address Translation (NAT). | 
					
						
							| 
									
										
										
										
											2012-10-05 22:11:57 -07:00
										 |  |  | # XXX: todo: support multiple upstream links | 
					
						
							|  |  |  | # see http://yesican.chsoft.biz/lartc/MultihomedLinuxNetworking.html | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 16:26:48 +02:00
										 |  |  | { config, lib, pkgs, ... }: | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-14 16:26:48 +02:00
										 |  |  | with lib; | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | let | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   cfg = config.networking.nat; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-10 14:23:38 +02:00
										 |  |  |   dest = if cfg.externalIP == null then "-j MASQUERADE" else "-j SNAT --to-source ${cfg.externalIP}"; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |   flushNat = ''
 | 
					
						
							| 
									
										
										
										
											2014-09-16 16:56:08 -07:00
										 |  |  |     iptables -w -t nat -D PREROUTING -j nixos-nat-pre 2>/dev/null|| true | 
					
						
							|  |  |  |     iptables -w -t nat -F nixos-nat-pre 2>/dev/null || true | 
					
						
							|  |  |  |     iptables -w -t nat -X nixos-nat-pre 2>/dev/null || true | 
					
						
							|  |  |  |     iptables -w -t nat -D POSTROUTING -j nixos-nat-post 2>/dev/null || true | 
					
						
							|  |  |  |     iptables -w -t nat -F nixos-nat-post 2>/dev/null || true | 
					
						
							|  |  |  |     iptables -w -t nat -X nixos-nat-post 2>/dev/null || true | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |   '';
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   setupNat = ''
 | 
					
						
							| 
									
										
										
										
											2014-09-16 16:56:08 -07:00
										 |  |  |     # Create subchain where we store rules | 
					
						
							|  |  |  |     iptables -w -t nat -N nixos-nat-pre | 
					
						
							|  |  |  |     iptables -w -t nat -N nixos-nat-post | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |     # We can't match on incoming interface in POSTROUTING, so | 
					
						
							|  |  |  |     # mark packets coming from the external interfaces. | 
					
						
							|  |  |  |     ${concatMapStrings (iface: ''
 | 
					
						
							| 
									
										
										
										
											2014-09-16 16:56:08 -07:00
										 |  |  |       iptables -w -t nat -A nixos-nat-pre \ | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |         -i '${iface}' -j MARK --set-mark 1 | 
					
						
							|  |  |  |     '') cfg.internalInterfaces}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # NAT the marked packets. | 
					
						
							|  |  |  |     ${optionalString (cfg.internalInterfaces != []) ''
 | 
					
						
							| 
									
										
										
										
											2014-09-16 16:56:08 -07:00
										 |  |  |       iptables -w -t nat -A nixos-nat-post -m mark --mark 1 \ | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |         -o ${cfg.externalInterface} ${dest} | 
					
						
							|  |  |  |     ''}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # NAT packets coming from the internal IPs. | 
					
						
							|  |  |  |     ${concatMapStrings (range: ''
 | 
					
						
							| 
									
										
										
										
											2014-09-16 16:56:08 -07:00
										 |  |  |       iptables -w -t nat -A nixos-nat-post \ | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |         -s '${range}' -o ${cfg.externalInterface} ${dest} | 
					
						
							|  |  |  |     '') cfg.internalIPs}
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # NAT from external ports to internal ports. | 
					
						
							|  |  |  |     ${concatMapStrings (fwd: ''
 | 
					
						
							| 
									
										
										
										
											2014-09-16 16:56:08 -07:00
										 |  |  |       iptables -w -t nat -A nixos-nat-pre \ | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |         -i ${cfg.externalInterface} -p tcp \ | 
					
						
							|  |  |  |         --dport ${builtins.toString fwd.sourcePort} \ | 
					
						
							|  |  |  |         -j DNAT --to-destination ${fwd.destination} | 
					
						
							|  |  |  |     '') cfg.forwardPorts}
 | 
					
						
							| 
									
										
										
										
											2014-09-16 16:56:08 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  |     # Append our chains to the nat tables | 
					
						
							|  |  |  |     iptables -w -t nat -A PREROUTING -j nixos-nat-pre | 
					
						
							|  |  |  |     iptables -w -t nat -A POSTROUTING -j nixos-nat-post | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |   '';
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  | in | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ###### interface | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   options = { | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |     networking.nat.enable = mkOption { | 
					
						
							| 
									
										
										
										
											2013-10-30 17:37:45 +01:00
										 |  |  |       type = types.bool; | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |       default = false; | 
					
						
							|  |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							|  |  |  |           Whether to enable Network Address Translation (NAT). | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-04-10 14:23:38 +02:00
										 |  |  |     networking.nat.internalInterfaces = mkOption { | 
					
						
							|  |  |  |       type = types.listOf types.str; | 
					
						
							|  |  |  |       default = []; | 
					
						
							|  |  |  |       example = [ "eth0" ]; | 
					
						
							|  |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							|  |  |  |           The interfaces for which to perform NAT. Packets coming from | 
					
						
							|  |  |  |           these interface and destined for the external interface will | 
					
						
							|  |  |  |           be rewritten. | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |     networking.nat.internalIPs = mkOption { | 
					
						
							| 
									
										
										
										
											2013-10-30 17:37:45 +01:00
										 |  |  |       type = types.listOf types.str; | 
					
						
							| 
									
										
										
										
											2014-04-10 14:23:38 +02:00
										 |  |  |       default = []; | 
					
						
							|  |  |  |       example = [ "192.168.1.0/24" ]; | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							| 
									
										
										
										
											2012-10-05 22:11:57 -07:00
										 |  |  |           The IP address ranges for which to perform NAT.  Packets | 
					
						
							| 
									
										
										
										
											2014-04-10 14:23:38 +02:00
										 |  |  |           coming from these addresses (on any interface) and destined | 
					
						
							|  |  |  |           for the external interface will be rewritten. | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |     networking.nat.externalInterface = mkOption { | 
					
						
							| 
									
										
										
										
											2013-10-30 17:37:45 +01:00
										 |  |  |       type = types.str; | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |       example = "eth1"; | 
					
						
							|  |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							|  |  |  |           The name of the external network interface. | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |     networking.nat.externalIP = mkOption { | 
					
						
							| 
									
										
										
										
											2013-10-30 17:37:45 +01:00
										 |  |  |       type = types.nullOr types.str; | 
					
						
							|  |  |  |       default = null; | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |       example = "203.0.113.123"; | 
					
						
							|  |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							|  |  |  |           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. | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2011-09-14 18:20:50 +00:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-01 22:20:59 +02:00
										 |  |  |     networking.nat.forwardPorts = mkOption { | 
					
						
							| 
									
										
										
										
											2014-09-04 10:25:56 +02:00
										 |  |  |       type = types.listOf types.optionSet; | 
					
						
							| 
									
										
										
										
											2014-09-01 22:20:59 +02:00
										 |  |  |       default = []; | 
					
						
							|  |  |  |       example = [ { sourcePort = 8080; destination = "10.0.0.1:80"; } ]; | 
					
						
							| 
									
										
										
										
											2014-09-04 10:25:56 +02:00
										 |  |  |       options = { | 
					
						
							|  |  |  |         sourcePort = mkOption { | 
					
						
							|  |  |  |           type = types.int; | 
					
						
							| 
									
										
										
										
											2014-09-04 11:32:40 +02:00
										 |  |  |           example = 8080; | 
					
						
							|  |  |  |           description = "Source port of the external interface"; | 
					
						
							| 
									
										
										
										
											2014-09-04 10:25:56 +02:00
										 |  |  |         }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         destination = mkOption { | 
					
						
							|  |  |  |           type = types.str; | 
					
						
							| 
									
										
										
										
											2014-09-04 11:32:40 +02:00
										 |  |  |           example = "10.0.0.1:80"; | 
					
						
							|  |  |  |           description = "Forward tcp connection to destination ip:port"; | 
					
						
							| 
									
										
										
										
											2014-09-04 10:25:56 +02:00
										 |  |  |         }; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-01 22:20:59 +02:00
										 |  |  |       description = | 
					
						
							|  |  |  |         ''
 | 
					
						
							|  |  |  |           List of forwarded ports from the external interface to | 
					
						
							|  |  |  |           internal destinations by using DNAT. | 
					
						
							|  |  |  |         '';
 | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |   }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   ###### implementation | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   config = mkIf config.networking.nat.enable { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     environment.systemPackages = [ pkgs.iptables ]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |     boot = { | 
					
						
							|  |  |  |       kernelModules = [ "nf_nat_ftp" ]; | 
					
						
							| 
									
										
										
										
											2014-10-31 16:49:32 -07:00
										 |  |  |       kernel.sysctl = { | 
					
						
							|  |  |  |         "net.ipv4.conf.all.forwarding" = mkOverride 99 true; | 
					
						
							|  |  |  |         "net.ipv4.conf.default.forwarding" = mkOverride 99 true; | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |       }; | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     networking.firewall = mkIf config.networking.firewall.enable { | 
					
						
							|  |  |  |       extraCommands = mkMerge [ (mkBefore flushNat) setupNat ]; | 
					
						
							|  |  |  |       extraStopCommands = flushNat; | 
					
						
							|  |  |  |     }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-09-16 16:56:08 -07:00
										 |  |  |     systemd.services = mkIf (!config.networking.firewall.enable) { nat = { | 
					
						
							| 
									
										
										
										
											2014-09-15 19:03:47 -07:00
										 |  |  |       description = "Network Address Translation"; | 
					
						
							|  |  |  |       wantedBy = [ "network.target" ]; | 
					
						
							|  |  |  |       after = [ "network-interfaces.target" "systemd-modules-load.service" ]; | 
					
						
							|  |  |  |       path = [ pkgs.iptables ]; | 
					
						
							|  |  |  |       unitConfig.ConditionCapability = "CAP_NET_ADMIN"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       serviceConfig = { | 
					
						
							|  |  |  |         Type = "oneshot"; | 
					
						
							|  |  |  |         RemainAfterExit = true; | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       script = flushNat + setupNat; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       postStop = flushNat; | 
					
						
							|  |  |  |     }; }; | 
					
						
							| 
									
										
										
										
											2011-03-10 12:08:39 +00:00
										 |  |  |   }; | 
					
						
							|  |  |  | } |