at 16.09-beta 6.3 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.services.tinc; 8 9in 10 11{ 12 13 ###### interface 14 15 options = { 16 17 services.tinc = { 18 19 networks = mkOption { 20 default = { }; 21 type = types.loaOf types.optionSet; 22 description = '' 23 Defines the tinc networks which will be started. 24 Each network invokes a different daemon. 25 ''; 26 options = { 27 28 extraConfig = mkOption { 29 default = ""; 30 type = types.lines; 31 description = '' 32 Extra lines to add to the tinc service configuration file. 33 ''; 34 }; 35 36 name = mkOption { 37 default = null; 38 type = types.nullOr types.str; 39 description = '' 40 The name of the node which is used as an identifier when communicating 41 with the remote nodes in the mesh. If null then the hostname of the system 42 is used. 43 ''; 44 }; 45 46 ed25519PrivateKeyFile = mkOption { 47 default = null; 48 type = types.nullOr types.path; 49 description = '' 50 Path of the private ed25519 keyfile. 51 ''; 52 }; 53 54 debugLevel = mkOption { 55 default = 0; 56 type = types.addCheck types.int (l: l >= 0 && l <= 5); 57 description = '' 58 The amount of debugging information to add to the log. 0 means little 59 logging while 5 is the most logging. <command>man tincd</command> for 60 more details. 61 ''; 62 }; 63 64 hosts = mkOption { 65 default = { }; 66 type = types.loaOf types.lines; 67 description = '' 68 The name of the host in the network as well as the configuration for that host. 69 This name should only contain alphanumerics and underscores. 70 ''; 71 }; 72 73 interfaceType = mkOption { 74 default = "tun"; 75 type = types.addCheck types.str (n: n == "tun" || n == "tap"); 76 description = '' 77 The type of virtual interface used for the network connection 78 ''; 79 }; 80 81 listenAddress = mkOption { 82 default = null; 83 type = types.nullOr types.str; 84 description = '' 85 The ip adress to bind to. 86 ''; 87 }; 88 89 package = mkOption { 90 type = types.package; 91 default = pkgs.tinc_pre; 92 defaultText = "pkgs.tinc_pre"; 93 description = '' 94 The package to use for the tinc daemon's binary. 95 ''; 96 }; 97 98 chroot = mkOption { 99 default = true; 100 type = types.bool; 101 description = '' 102 Change process root directory to the directory where the config file is located (/etc/tinc/netname/), for added security. 103 The chroot is performed after all the initialization is done, after writing pid files and opening network sockets. 104 105 Note that tinc can't run scripts anymore (such as tinc-down or host-up), unless it is setup to be runnable inside chroot environment. 106 ''; 107 }; 108 }; 109 }; 110 }; 111 112 }; 113 114 115 ###### implementation 116 117 config = mkIf (cfg.networks != { }) { 118 119 environment.etc = fold (a: b: a // b) { } 120 (flip mapAttrsToList cfg.networks (network: data: 121 flip mapAttrs' data.hosts (host: text: nameValuePair 122 ("tinc/${network}/hosts/${host}") 123 ({ mode = "0444"; inherit text; }) 124 ) // { 125 "tinc/${network}/tinc.conf" = { 126 mode = "0444"; 127 text = '' 128 Name = ${if data.name == null then "$HOST" else data.name} 129 DeviceType = ${data.interfaceType} 130 ${optionalString (data.ed25519PrivateKeyFile != null) "Ed25519PrivateKeyFile = ${data.ed25519PrivateKeyFile}"} 131 ${optionalString (data.listenAddress != null) "BindToAddress = ${data.listenAddress}"} 132 Device = /dev/net/tun 133 Interface = tinc.${network} 134 ${data.extraConfig} 135 ''; 136 }; 137 } 138 )); 139 140 networking.interfaces = flip mapAttrs' cfg.networks (network: data: nameValuePair 141 ("tinc.${network}") 142 ({ 143 virtual = true; 144 virtualType = "${data.interfaceType}"; 145 }) 146 ); 147 148 systemd.services = flip mapAttrs' cfg.networks (network: data: nameValuePair 149 ("tinc.${network}") 150 ({ 151 description = "Tinc Daemon - ${network}"; 152 wantedBy = [ "network.target" ]; 153 after = [ "network-interfaces.target" ]; 154 path = [ data.package ]; 155 restartTriggers = [ config.environment.etc."tinc/${network}/tinc.conf".source ] 156 ++ mapAttrsToList (host: _ : config.environment.etc."tinc/${network}/hosts/${host}".source) data.hosts; 157 serviceConfig = { 158 Type = "simple"; 159 PIDFile = "/run/tinc.${network}.pid"; 160 Restart = "on-failure"; 161 }; 162 preStart = '' 163 mkdir -p /etc/tinc/${network}/hosts 164 165 # Determine how we should generate our keys 166 if type tinc >/dev/null 2>&1; then 167 # Tinc 1.1+ uses the tinc helper application for key generation 168 ${if data.ed25519PrivateKeyFile != null then " # Keyfile managed by nix" else '' 169 # Prefer ED25519 keys (only in 1.1+) 170 [ -f "/etc/tinc/${network}/ed25519_key.priv" ] || tinc -n ${network} generate-ed25519-keys 171 ''} 172 # Otherwise use RSA keys 173 [ -f "/etc/tinc/${network}/rsa_key.priv" ] || tinc -n ${network} generate-rsa-keys 4096 174 else 175 # Tinc 1.0 uses the tincd application 176 [ -f "/etc/tinc/${network}/rsa_key.priv" ] || tincd -n ${network} -K 4096 177 fi 178 ''; 179 script = '' 180 tincd -D -U tinc.${network} -n ${network} ${optionalString (data.chroot) "-R"} --pidfile /run/tinc.${network}.pid -d ${toString data.debugLevel} 181 ''; 182 }) 183 ); 184 185 users.extraUsers = flip mapAttrs' cfg.networks (network: _: 186 nameValuePair ("tinc.${network}") ({ 187 description = "Tinc daemon user for ${network}"; 188 isSystemUser = true; 189 }) 190 ); 191 192 }; 193 194}