diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 2ccaea466c6a..13e9868eab70 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1034,6 +1034,7 @@ ./services/networking/multipath.nix ./services/networking/murmur.nix ./services/networking/mxisd.nix + ./services/networking/mycelium.nix ./services/networking/namecoind.nix ./services/networking/nar-serve.nix ./services/networking/nat.nix diff --git a/nixos/modules/services/networking/mycelium.nix b/nixos/modules/services/networking/mycelium.nix new file mode 100644 index 000000000000..71ff8d1dd9af --- /dev/null +++ b/nixos/modules/services/networking/mycelium.nix @@ -0,0 +1,126 @@ +{ config, pkgs, lib, ... }: + +let + cfg = config.services.mycelium; +in +{ + options.services.mycelium = { + enable = lib.mkEnableOption "mycelium network"; + peers = lib.mkOption { + type = lib.types.listOf lib.types.str; + description = '' + List of peers to connect to in the format quic://1.2.3.4:9651. + If addHostedPublicNodes is set to true, the hosted public nodes will be added to this list. + ''; + default = []; + }; + keyFile = lib.mkOption { + type = lib.types.nullOr lib.types.path; + default = null; + description = '' + optional path to a keyFile, if unset the default location (/var/lib/mycelium/key) will be used + If this key does not exist, it will be generated + ''; + }; + openFirewall = lib.mkOption { + type = lib.types.bool; + default = false; + description = "Open the firewall for mycelium"; + }; + package = lib.mkOption { + type = lib.types.package; + default = pkgs.mycelium; + defaultText = lib.literalExpression ''"''${pkgs.mycelium}"''; + description = "The mycelium package to use"; + }; + addHostedPublicNodes = lib.mkOption { + type = lib.types.bool; + default = true; + description = '' + add the hosted peers from https://github.com/threefoldtech/mycelium#hosted-public-nodes + ''; + }; + }; + config = lib.mkIf cfg.enable { + networking.firewall.allowedTCPPorts = lib.optionals cfg.openFirewall [ 9651 ]; + networking.firewall.allowedUDPPorts = lib.optionals cfg.openFirewall [ 9650 9651 ]; + + systemd.services.mycelium = { + description = "Mycelium network"; + after = [ "network.target" ]; + wantedBy = [ "multi-user.target" ]; + restartTriggers = [ + cfg.keyFile + ]; + + unitConfig.Documentation = "https://github.com/threefoldtech/mycelium"; + + serviceConfig = { + User = "mycelium"; + DynamicUser = true; + StateDirectory = "mycelium"; + ProtectHome = true; + ProtectSystem = true; + LoadCredential = lib.mkIf (cfg.keyFile != null) "keyfile:${cfg.keyFile}"; + SyslogIdentifier = "mycelium"; + AmbientCapabilities = [ "CAP_NET_ADMIN" ]; + MemoryDenyWriteExecute = true; + ProtectControlGroups = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6 AF_NETLINK"; + RestrictNamespaces = true; + RestrictRealtime = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ "@system-service" "~@privileged @keyring" ]; + ExecStart = lib.concatStringsSep " " ([ + (lib.getExe cfg.package) + (if (cfg.keyFile != null) then + "--key-file \${CREDENTIALS_DIRECTORY}/keyfile" else + "--key-file %S/mycelium/key.bin" + ) + "--tun-name" "mycelium" + ] ++ + (lib.optional (cfg.addHostedPublicNodes || cfg.peers != []) "--peers") + ++ cfg.peers ++ (lib.optionals cfg.addHostedPublicNodes [ + "tcp://188.40.132.242:9651" # DE 01 + "tcp://[2a01:4f8:221:1e0b::2]:9651" + "quic://188.40.132.242:9651" + "quic://[2a01:4f8:221:1e0b::2]:9651" + + "tcp://136.243.47.186:9651" # DE 02 + "tcp://[2a01:4f8:212:fa6::2]:9651" + "quic://136.243.47.186:9651" + "quic://[2a01:4f8:212:fa6::2]:9651" + + "tcp://185.69.166.7:9651" # BE 03 + "tcp://[2a02:1802:5e:0:8478:51ff:fee2:3331]:9651" + "quic://185.69.166.7:9651" + "quic://[2a02:1802:5e:0:8478:51ff:fee2:3331]:9651" + + "tcp://185.69.166.8:9651" # BE 04 + "tcp://[2a02:1802:5e:0:8c9e:7dff:fec9:f0d2]:9651" + "quic://185.69.166.8:9651" + "quic://[2a02:1802:5e:0:8c9e:7dff:fec9:f0d2]:9651" + + "tcp://65.21.231.58:9651" # FI 05 + "tcp://[2a01:4f9:6a:1dc5::2]:9651" + "quic://65.21.231.58:9651" + "quic://[2a01:4f9:6a:1dc5::2]:9651" + + "tcp://65.109.18.113:9651" # FI 06 + "tcp://[2a01:4f9:5a:1042::2]:9651" + "quic://65.109.18.113:9651" + "quic://[2a01:4f9:5a:1042::2]:9651" + ])); + Restart = "always"; + RestartSec = 5; + TimeoutStopSec = 5; + }; + }; + }; + meta = { + maintainers = with lib.maintainers; [ flokli lassulus ]; + }; +} + diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index dd6c744a79ce..faff759f76c0 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -561,6 +561,7 @@ in { munin = handleTest ./munin.nix {}; mutableUsers = handleTest ./mutable-users.nix {}; mxisd = handleTest ./mxisd.nix {}; + mycelium = handleTest ./mycelium {}; mympd = handleTest ./mympd.nix {}; mysql = handleTest ./mysql/mysql.nix {}; mysql-autobackup = handleTest ./mysql/mysql-autobackup.nix {}; diff --git a/nixos/tests/mycelium/default.nix b/nixos/tests/mycelium/default.nix new file mode 100644 index 000000000000..f0d72436843c --- /dev/null +++ b/nixos/tests/mycelium/default.nix @@ -0,0 +1,57 @@ +import ../make-test-python.nix ({ lib, ... }: let + peer1-ip = "531:c350:28c1:dfde:ea6d:77d1:a60b:7209"; + peer2-ip = "49f:3942:3a55:d100:4c78:c558:c4f:695b"; +in + { + name = "mycelium"; + meta.maintainers = with lib.maintainers; [ lassulus ]; + + nodes = { + + peer1 = { config, pkgs, ... }: { + virtualisation.vlans = [ 1 ]; + networking.interfaces.eth1.ipv4.addresses = [{ + address = "192.168.1.11"; + prefixLength = 24; + }]; + + services.mycelium = { + enable = true; + addHostedPublicNodes = false; + openFirewall = true; + keyFile = ./peer1.key; + peers = [ + "quic://192.168.1.12:9651" + "tcp://192.168.1.12:9651" + ]; + }; + }; + + peer2 = { config, pkgs, ... }: { + virtualisation.vlans = [ 1 ]; + networking.interfaces.eth1.ipv4.addresses = [{ + address = "192.168.1.12"; + prefixLength = 24; + }]; + + services.mycelium = { + enable = true; + addHostedPublicNodes = false; + openFirewall = true; + keyFile = ./peer2.key; + }; + }; + }; + + testScript = '' + start_all() + + peer1.wait_for_unit("network-online.target") + peer2.wait_for_unit("network-online.target") + peer1.wait_for_unit("mycelium.service") + peer2.wait_for_unit("mycelium.service") + + peer1.succeed("ping -c5 ${peer2-ip}") + peer2.succeed("ping -c5 ${peer1-ip}") + ''; + }) diff --git a/nixos/tests/mycelium/peer1.key b/nixos/tests/mycelium/peer1.key new file mode 100644 index 000000000000..db1cf9e72fe4 --- /dev/null +++ b/nixos/tests/mycelium/peer1.key @@ -0,0 +1 @@ +s B0dRH5u?^ \ No newline at end of file diff --git a/nixos/tests/mycelium/peer2.key b/nixos/tests/mycelium/peer2.key new file mode 100644 index 000000000000..7e757de48efb --- /dev/null +++ b/nixos/tests/mycelium/peer2.key @@ -0,0 +1 @@ +X1yGՅSAMe 7] \ No newline at end of file