From 7308eb8dc71ecba67044da591a52a3d8e4bf3b18 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Wed, 22 Jan 2025 12:44:11 +0100 Subject: [PATCH] clanModules/mycelium: init `mycelium` This adds a clanModule for `mycelium`. `Mycelium` is an IPv6 overlay network written in Rust. Each node that joins the overlay network will receive an overlay network IP in the 400::/7 range. An example configuration might look like this in the inventory: ```nix mycelium.default = { roles.peer.machines = [ "berlin" "munich" ]; config = { topLevelDomain = "m"; openFirewall = true; addHostedPublicNodes = true; }; }; ``` This will add the machines named `berlin` and `munich` to the `mycelium` vpn. And will also set the toplevel domain of the mycelium vpn to `m`, meaning the machines are now reachable via `berlin.m` and `munich.m`. --- clanModules/flake-module.nix | 1 + clanModules/mycelium/README.md | 37 ++++++++++++ clanModules/mycelium/roles/peer.nix | 91 +++++++++++++++++++++++++++++ docs/mkdocs.yml | 1 + 4 files changed, 130 insertions(+) create mode 100644 clanModules/mycelium/README.md create mode 100644 clanModules/mycelium/roles/peer.nix diff --git a/clanModules/flake-module.nix b/clanModules/flake-module.nix index b9e1b1d2d..706e3515f 100644 --- a/clanModules/flake-module.nix +++ b/clanModules/flake-module.nix @@ -26,6 +26,7 @@ in matrix-synapse = ./matrix-synapse; moonlight = ./moonlight; mumble = ./mumble; + mycelium = ./mycelium; nginx = ./nginx; packages = ./packages; postgresql = ./postgresql; diff --git a/clanModules/mycelium/README.md b/clanModules/mycelium/README.md new file mode 100644 index 000000000..c8039892a --- /dev/null +++ b/clanModules/mycelium/README.md @@ -0,0 +1,37 @@ +--- +description = "End-2-end encrypted IPv6 overlay network" +categories = ["System", "Network"] +features = [ "inventory" ] +--- +Mycelium is an IPv6 overlay network written in Rust. Each node that joins the overlay network will receive an overlay network IP in the 400::/7 range. + +Features: +- Mycelium, is locality aware, it will look for the shortest path between nodes +- All traffic between the nodes is end-2-end encrypted +- Traffic can be routed over nodes of friends, location aware +- If a physical link goes down Mycelium will automatically reroute your traffic +- The IP address is IPV6 and linked to private key +- A simple reliable messagebus is implemented on top of Mycelium +- Mycelium has multiple ways how to communicate quic, tcp, ... and we are working on holepunching for Quick which means P2P traffic without middlemen for NATted networks e.g. most homes +- Scalability is very important for us, we tried many overlay networks before and got stuck on all of them, we are trying to design a network which scales to a planetary level +- You can run mycelium without TUN and only use it as reliable message bus. + + +An example configuration might look like this in the inventory: +```nix +mycelium.default = { + roles.peer.machines = [ + "berlin" + "munich" + ]; + config = { + topLevelDomain = "m"; + openFirewall = true; + addHostedPublicNodes = true; + }; +}; +``` + +This will add the machines named `berlin` and `munich` to the `mycelium` vpn. +And will also set the toplevel domain of the mycelium vpn to `m`, meaning the +machines are now reachable via `berlin.m` and `munich.m`. diff --git a/clanModules/mycelium/roles/peer.nix b/clanModules/mycelium/roles/peer.nix new file mode 100644 index 000000000..3e5de5b25 --- /dev/null +++ b/clanModules/mycelium/roles/peer.nix @@ -0,0 +1,91 @@ +{ + pkgs, + config, + lib, + ... +}: +let + flake = config.clan.core.settings.directory; + machineName = config.clan.core.settings.machine.name; + + # Instances might be empty, if the module is not used via the inventory + # + # Type: { ${instanceName} :: { roles :: Roles } } + # Roles :: { ${role_name} :: { machines :: [string] } } + instances = config.clan.inventory.services.mycelium or { }; + + allPeers = lib.foldlAttrs ( + acc: _instanceName: instanceConfig: + acc + ++ ( + if (builtins.elem machineName instanceConfig.roles.peer.machines) then + instanceConfig.roles.peer.machines + else + [ ] + ) + ) [ ] instances; + allPeerConfigurations = lib.filterAttrs (n: _: builtins.elem n allPeers) flake.nixosConfigurations; + allPeersWithIp = + builtins.mapAttrs + (_: x: lib.removeSuffix "\n" x.config.clan.core.vars.generators.mycelium.files.ip.value) + ( + lib.filterAttrs ( + _: x: (builtins.tryEval x.config.clan.core.vars.generators.mycelium.files.ip.value).success + ) allPeerConfigurations + ); + + ips = lib.attrValues allPeersWithIp; + peers = lib.concatMap (ip: [ + "tcp://[${ip}]:9651" + "quic://[${ip}]:9651" + ]) ips; +in +{ + options = { + clan.mycelium.topLevelDomain = lib.mkOption { + type = lib.types.str; + default = ""; + description = "Top level domain to reach hosts"; + }; + clan.mycelium.openFirewall = lib.mkEnableOption "Open the firewall for mycelium"; + clan.mycelium.addHostedPublicNodes = lib.mkEnableOption "Add hosted Public nodes"; + clan.mycelium.addHosts = lib.mkOption { + default = true; + description = "Add mycelium ip's to the host file"; + }; + }; + + config.services.mycelium = { + enable = true; + addHostedPublicNodes = lib.mkDefault config.clan.mycelium.addHostedPublicNodes; + openFirewall = lib.mkDefault config.clan.mycelium.openFirewall; + keyFile = config.clan.core.vars.generators.mycelium.files.key.path; + inherit peers; + }; + + config.networking.hosts = lib.mkIf (config.clan.mycelium.addHosts) ( + lib.mapAttrs' ( + host: ip: + lib.nameValuePair ip ( + if (config.clan.mycelium.topLevelDomain == "") then [ host ] else [ "${host}.m" ] + ) + ) allPeersWithIp + ); + + config.clan.core.vars.generators.mycelium = { + files."key" = { }; + files."ip".secret = false; + files."pubkey".secret = false; + runtimeInputs = [ + pkgs.mycelium + pkgs.coreutils + pkgs.jq + ]; + script = '' + timeout 5 mycelium --key-file "$out"/key || : + mycelium inspect --key-file "$out"/key --json | jq -r .publicKey > "$out"/pubkey + mycelium inspect --key-file "$out"/key --json | jq -r .address > "$out"/ip + ''; + }; + +} diff --git a/docs/mkdocs.yml b/docs/mkdocs.yml index 9131a8fdd..0f3d3db90 100644 --- a/docs/mkdocs.yml +++ b/docs/mkdocs.yml @@ -92,6 +92,7 @@ nav: - reference/clanModules/matrix-synapse.md - reference/clanModules/moonlight.md - reference/clanModules/mumble.md + - reference/clanModules/mycelium.md - reference/clanModules/nginx.md - reference/clanModules/packages.md - reference/clanModules/postgresql.md