lol

nixos/easytier: init module

L-Trump 725a756d 4206c4cb

+422 -1
+2
nixos/doc/manual/release-notes/rl-2505.section.md
··· 88 88 89 89 - [Readeck](https://readeck.org/), a read-it later web-application. Available as [services.readeck](#opt-services.readeck.enable). 90 90 91 + - [EasyTier](https://github.com/EasyTier/EasyTier), a decentralized VPN solution. Available as [services.easytier](#opt-services.easytier.enable). 92 + 91 93 - [Traccar](https://www.traccar.org/), a modern GPS Tracking Platform. Available as [services.traccar](#opt-services.traccar.enable). 92 94 93 95 - [Schroot](https://codeberg.org/shelter/reschroot), a lightweight virtualisation tool. Securely enter a chroot and run a command or login shell. Available as [programs.schroot](#opt-programs.schroot.enable).
+1
nixos/modules/module-list.nix
··· 1115 1115 ./services/networking/dnsproxy.nix 1116 1116 ./services/networking/doh-proxy-rust.nix 1117 1117 ./services/networking/doh-server.nix 1118 + ./services/networking/easytier.nix 1118 1119 ./services/networking/ejabberd.nix 1119 1120 ./services/networking/envoy.nix 1120 1121 ./services/networking/epmd.nix
+292
nixos/modules/services/networking/easytier.nix
··· 1 + { 2 + config, 3 + lib, 4 + pkgs, 5 + ... 6 + }: 7 + 8 + with lib; 9 + let 10 + cfg = config.services.easytier; 11 + settingsFormat = pkgs.formats.toml { }; 12 + 13 + genFinalSettings = 14 + inst: 15 + attrsets.filterAttrsRecursive (_: v: v != { }) ( 16 + attrsets.filterAttrsRecursive (_: v: v != null) ( 17 + { 18 + inherit (inst.settings) 19 + instance_name 20 + hostname 21 + ipv4 22 + dhcp 23 + listeners 24 + ; 25 + network_identity = { 26 + inherit (inst.settings) network_name network_secret; 27 + }; 28 + peer = map (p: { uri = p; }) inst.settings.peers; 29 + } 30 + // inst.extraSettings 31 + ) 32 + ); 33 + 34 + genConfigFile = 35 + name: inst: 36 + if inst.configFile == null then 37 + settingsFormat.generate "easytier-${name}.toml" (genFinalSettings inst) 38 + else 39 + inst.configFile; 40 + 41 + activeInsts = filterAttrs (_: inst: inst.enable) cfg.instances; 42 + 43 + settingsModule = name: { 44 + options = { 45 + instance_name = mkOption { 46 + type = types.str; 47 + default = name; 48 + description = "Identify different instances on same host"; 49 + }; 50 + 51 + hostname = mkOption { 52 + type = with types; nullOr str; 53 + default = null; 54 + description = "Hostname shown in peer list and web console."; 55 + }; 56 + 57 + network_name = mkOption { 58 + type = with types; nullOr str; 59 + default = null; 60 + description = "EasyTier network name."; 61 + }; 62 + 63 + network_secret = mkOption { 64 + type = with types; nullOr str; 65 + default = null; 66 + description = '' 67 + EasyTier network credential used for verification and 68 + encryption. It can also be set in environmentFile. 69 + ''; 70 + }; 71 + 72 + ipv4 = mkOption { 73 + type = with types; nullOr str; 74 + default = null; 75 + description = '' 76 + IPv4 cidr address of this peer in the virtual network. If 77 + empty, this peer will only forward packets and no TUN device 78 + will be created. 79 + ''; 80 + example = "10.144.144.1/24"; 81 + }; 82 + 83 + dhcp = mkOption { 84 + type = types.bool; 85 + default = false; 86 + description = '' 87 + Automatically determine the IPv4 address of this peer based on 88 + existing peers on network. 89 + ''; 90 + }; 91 + 92 + listeners = mkOption { 93 + type = with types; listOf str; 94 + default = [ 95 + "tcp://0.0.0.0:11010" 96 + "udp://0.0.0.0:11010" 97 + ]; 98 + description = '' 99 + Listener addresses to accept connections from other peers. 100 + Valid format is: `<proto>://<addr>:<port>`, where the protocol 101 + can be `tcp`, `udp`, `ring`, `wg`, `ws`, `wss`. 102 + ''; 103 + }; 104 + 105 + peers = mkOption { 106 + type = with types; listOf str; 107 + default = [ ]; 108 + description = '' 109 + Peers to connect initially. Valid format is: `<proto>://<addr>:<port>`. 110 + ''; 111 + example = [ 112 + "tcp://example.com:11010" 113 + ]; 114 + }; 115 + }; 116 + }; 117 + 118 + instanceModule = 119 + { name, ... }: 120 + { 121 + options = { 122 + enable = mkOption { 123 + type = types.bool; 124 + default = true; 125 + description = "Enable the instance."; 126 + }; 127 + 128 + configServer = mkOption { 129 + type = with types; nullOr str; 130 + default = null; 131 + description = '' 132 + Configure the instance from config server. When this option 133 + set, any other settings for configuring the instance manually 134 + except `hostname` will be ignored. Valid formats are: 135 + 136 + - full uri for custom server: `udp://example.com:22020/<token>` 137 + - username only for official server: `<token>` 138 + ''; 139 + example = "udp://example.com:22020/myusername"; 140 + }; 141 + 142 + configFile = mkOption { 143 + type = with types; nullOr path; 144 + default = null; 145 + description = '' 146 + Path to easytier config file. Setting this option will 147 + override `settings` and `extraSettings` of this instance. 148 + ''; 149 + }; 150 + 151 + environmentFiles = mkOption { 152 + type = with types; listOf path; 153 + default = [ ]; 154 + description = '' 155 + Environment files for this instance. All command-line args 156 + have corresponding environment variables. 157 + ''; 158 + example = literalExpression '' 159 + [ 160 + /path/to/.env 161 + /path/to/.env.secret 162 + ] 163 + ''; 164 + }; 165 + 166 + settings = mkOption { 167 + type = types.submodule (settingsModule name); 168 + default = { }; 169 + description = '' 170 + Settings to generate {file}`easytier-${name}.toml` 171 + ''; 172 + }; 173 + 174 + extraSettings = mkOption { 175 + type = settingsFormat.type; 176 + default = { }; 177 + description = '' 178 + Extra settings to add to {file}`easytier-${name}.toml`. 179 + ''; 180 + }; 181 + 182 + extraArgs = mkOption { 183 + type = with types; listOf str; 184 + default = [ ]; 185 + description = '' 186 + Extra args append to the easytier command-line. 187 + ''; 188 + }; 189 + }; 190 + }; 191 + 192 + in 193 + { 194 + options.services.easytier = { 195 + enable = mkEnableOption "EasyTier daemon"; 196 + 197 + package = mkPackageOption pkgs "easytier" { }; 198 + 199 + allowSystemForward = mkEnableOption '' 200 + Allow the system to forward packets from easytier. Useful when 201 + `proxy_forward_by_system` enabled. 202 + ''; 203 + 204 + instances = mkOption { 205 + description = '' 206 + EasyTier instances. 207 + ''; 208 + type = types.attrsOf (types.submodule instanceModule); 209 + default = { }; 210 + example = { 211 + settings = { 212 + network_name = "easytier"; 213 + network_secret = "easytier"; 214 + ipv4 = "10.144.144.1/24"; 215 + peers = [ 216 + "tcp://public.easytier.cn:11010" 217 + "wss://example.com:443" 218 + ]; 219 + }; 220 + extraSettings = { 221 + flags.dev_name = "tun1"; 222 + }; 223 + }; 224 + }; 225 + }; 226 + 227 + config = mkIf cfg.enable { 228 + environment.systemPackages = [ cfg.package ]; 229 + 230 + systemd.services = mapAttrs' ( 231 + name: inst: 232 + let 233 + configFile = genConfigFile name inst; 234 + in 235 + nameValuePair "easytier-${name}" { 236 + description = "EasyTier Daemon - ${name}"; 237 + wants = [ 238 + "network-online.target" 239 + "nss-lookup.target" 240 + ]; 241 + after = [ 242 + "network-online.target" 243 + "nss-lookup.target" 244 + ]; 245 + wantedBy = [ "multi-user.target" ]; 246 + path = with pkgs; [ 247 + cfg.package 248 + iproute2 249 + bash 250 + ]; 251 + restartTriggers = inst.environmentFiles ++ (optionals (inst.configServer == null) [ configFile ]); 252 + serviceConfig = { 253 + Type = "simple"; 254 + Restart = "on-failure"; 255 + EnvironmentFile = inst.environmentFiles; 256 + StateDirectory = "easytier/easytier-${name}"; 257 + StateDirectoryMode = "0700"; 258 + WorkingDirectory = "/var/lib/easytier/easytier-${name}"; 259 + ExecStart = escapeShellArgs ( 260 + [ 261 + "${cfg.package}/bin/easytier-core" 262 + ] 263 + ++ optionals (inst.configServer != null) ( 264 + [ 265 + "-w" 266 + "${inst.configServer}" 267 + ] 268 + ++ (optionals (inst.settings.hostname != null) [ 269 + "--hostname" 270 + "${inst.settings.hostname}" 271 + ]) 272 + ) 273 + ++ optionals (inst.configServer == null) [ 274 + "-c" 275 + "${configFile}" 276 + ] 277 + ++ inst.extraArgs 278 + ); 279 + }; 280 + } 281 + ) activeInsts; 282 + 283 + boot.kernel.sysctl = mkIf cfg.allowSystemForward { 284 + "net.ipv4.conf.all.forwarding" = mkOverride 97 true; 285 + "net.ipv6.conf.all.forwarding" = mkOverride 97 true; 286 + }; 287 + }; 288 + 289 + meta.maintainers = with maintainers; [ 290 + ltrump 291 + ]; 292 + }
+1
nixos/tests/all-tests.nix
··· 433 433 fscrypt = runTest ./fscrypt.nix; 434 434 fastnetmon-advanced = runTest ./fastnetmon-advanced.nix; 435 435 lauti = runTest ./lauti.nix; 436 + easytier = handleTest ./easytier.nix { }; 436 437 ejabberd = runTest ./xmpp/ejabberd.nix; 437 438 elk = handleTestOn [ "x86_64-linux" ] ./elk.nix { }; 438 439 emacs-daemon = runTest ./emacs-daemon.nix;
+121
nixos/tests/easytier.nix
··· 1 + import ./make-test-python.nix ( 2 + { lib, ... }: 3 + { 4 + name = "easytier"; 5 + meta.maintainers = with lib.maintainers; [ ltrump ]; 6 + 7 + nodes = 8 + let 9 + genPeer = 10 + hostConfig: settings: 11 + lib.mkMerge [ 12 + { 13 + services.easytier = { 14 + enable = true; 15 + instances.default = { 16 + settings = { 17 + network_name = "easytier_test"; 18 + network_secret = "easytier_test_secret"; 19 + } // settings; 20 + }; 21 + }; 22 + 23 + networking.useDHCP = false; 24 + networking.firewall.allowedTCPPorts = [ 25 + 11010 26 + 11011 27 + ]; 28 + networking.firewall.allowedUDPPorts = [ 29 + 11010 30 + 11011 31 + ]; 32 + } 33 + hostConfig 34 + ]; 35 + in 36 + { 37 + relay = 38 + genPeer 39 + { 40 + virtualisation.vlans = [ 41 + 1 42 + 2 43 + ]; 44 + 45 + networking.interfaces.eth1.ipv4.addresses = [ 46 + { 47 + address = "192.168.1.11"; 48 + prefixLength = 24; 49 + } 50 + ]; 51 + 52 + networking.interfaces.eth2.ipv4.addresses = [ 53 + { 54 + address = "192.168.2.11"; 55 + prefixLength = 24; 56 + } 57 + ]; 58 + } 59 + { 60 + ipv4 = "10.144.144.1"; 61 + listeners = [ 62 + "tcp://0.0.0.0:11010" 63 + "wss://0.0.0.0:11011" 64 + ]; 65 + }; 66 + 67 + peer1 = 68 + genPeer 69 + { 70 + virtualisation.vlans = [ 1 ]; 71 + } 72 + { 73 + ipv4 = "10.144.144.2"; 74 + peers = [ "tcp://192.168.1.11:11010" ]; 75 + }; 76 + 77 + peer2 = 78 + genPeer 79 + { 80 + virtualisation.vlans = [ 2 ]; 81 + } 82 + { 83 + ipv4 = "10.144.144.3"; 84 + peers = [ "wss://192.168.2.11:11011" ]; 85 + }; 86 + }; 87 + 88 + testScript = '' 89 + start_all() 90 + 91 + relay.wait_for_unit("easytier-default.service") 92 + peer1.wait_for_unit("easytier-default.service") 93 + peer2.wait_for_unit("easytier-default.service") 94 + 95 + # relay is accessible by the other hosts 96 + peer1.succeed("ping -c5 192.168.1.11") 97 + peer2.succeed("ping -c5 192.168.2.11") 98 + 99 + # The other hosts are in separate vlans 100 + peer1.fail("ping -c5 192.168.2.11") 101 + peer2.fail("ping -c5 192.168.1.11") 102 + 103 + # Each host can ping themselves through EasyTier 104 + relay.succeed("ping -c5 10.144.144.1") 105 + peer1.succeed("ping -c5 10.144.144.2") 106 + peer2.succeed("ping -c5 10.144.144.3") 107 + 108 + # Relay is accessible by the other hosts through EasyTier 109 + peer1.succeed("ping -c5 10.144.144.1") 110 + peer2.succeed("ping -c5 10.144.144.1") 111 + 112 + # Relay can access the other hosts through EasyTier 113 + relay.succeed("ping -c5 10.144.144.2") 114 + relay.succeed("ping -c5 10.144.144.3") 115 + 116 + # The other hosts in separate vlans can access each other through EasyTier 117 + peer1.succeed("ping -c5 10.144.144.3") 118 + peer2.succeed("ping -c5 10.144.144.2") 119 + ''; 120 + } 121 + )
+5 -1
pkgs/by-name/ea/easytier/package.nix
··· 4 4 fetchFromGitHub, 5 5 rustPlatform, 6 6 protobuf, 7 + nixosTests, 7 8 nix-update-script, 8 9 withQuic ? false, # with QUIC protocol support 9 10 }: ··· 33 34 34 35 doCheck = false; # tests failed due to heavy rely on network 35 36 36 - passthru.updateScript = nix-update-script { }; 37 + passthru = { 38 + tests = { inherit (nixosTests) easytier; }; 39 + updateScript = nix-update-script { }; 40 + }; 37 41 38 42 meta = { 39 43 homepage = "https://github.com/EasyTier/EasyTier";