Unverified Commit f3b9f478 authored by misuzu's avatar misuzu Committed by GitHub
Browse files

nixos/umurmur: init (#387580)

parents 74680bc6 095da00b
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -1289,6 +1289,12 @@
  "module-services-foundationdb-full-docs": [
    "index.html#module-services-foundationdb-full-docs"
  ],
  "module-service-umurmur": [
    "index.html#module-service-umurmur"
  ],
  "module-service-umurmur-quick-start": [
    "index.html#module-service-umurmur-quick-start"
  ],
  "module-borgbase": [
    "index.html#module-borgbase"
  ],
+2 −0
Original line number Diff line number Diff line
@@ -77,6 +77,8 @@

- [Yggdrasil-Jumper](https://github.com/one-d-wide/yggdrasil-jumper) is an independent project that aims to transparently reduce latency of a connection over Yggdrasil network, utilizing NAT traversal to automatically bypass intermediary nodes.

- [uMurmur](https://umurmur.net), minimalistic Mumble server primarily targeted to run on embedded computers. Available as [services.umurmur](options.html#opt-services.umurmur).

- [Zenoh](https://zenoh.io/), a pub/sub/query protocol with low overhead. The Zenoh router daemon is available as [services.zenohd](options.html#opt-services.zenohd.enable)

- [ytdl-sub](https://github.com/jmbannon/ytdl-sub), a tool that downloads media via yt-dlp and prepares it for your favorite media player, including Kodi, Jellyfin, Plex, Emby, and modern music players. Available as [services.ytdl-sub](options.html#opt-services.ytdl-sub.instances).
+1 −0
Original line number Diff line number Diff line
@@ -1315,6 +1315,7 @@
  ./services/networking/trickster.nix
  ./services/networking/twingate.nix
  ./services/networking/ucarp.nix
  ./services/networking/umurmur.nix
  ./services/networking/unbound.nix
  ./services/networking/unifi.nix
  ./services/networking/uptermd.nix
+33 −0
Original line number Diff line number Diff line
# uMurmur {#module-service-umurmur}

[uMurmur](http://umurmur.net/) is a minimalistic Mumble server primarily targeted to run on embedded computers. This module enables it (`umurmurd`).

## Quick Start {#module-service-umurmur-quick-start}

```nix
{
  services.umurmur = {
    enable = true;
    openFirewall = true;
    settings = {
      port = 7365;
      channels = [
        {
          name = "root";
          parent = "";
          description = "Root channel. No entry.";
          noenter = true;
        }
        {
          name = "lobby";
          parent = "root";
          description = "Lobby channel";
        }
      ];
      default_channel = "lobby";
    };
  };
}
```

See a full configuration in [umurmur.conf.example](https://github.com/umurmur/umurmur/blob/master/umurmur.conf.example)
+244 −0
Original line number Diff line number Diff line
{
  config,
  lib,
  pkgs,
  ...
}:

let
  cfg = config.services.umurmur;
  dumpAttrset =
    x: top_level:
    (lib.optionalString (!top_level) "{")
    + (lib.concatLines (lib.mapAttrsToList (name: value: "${name} = ${toConfigValue value false};") x))
    + (lib.optionalString (!top_level) "}");
  dumpList = x: top_level: "(${lib.concatStringsSep ",\n" (map (y: "${toConfigValue y false}") x)})";

  toConfigValue =
    x: top_level:
    if builtins.isList x then
      dumpList x top_level
    else if builtins.isAttrs x then
      dumpAttrset x top_level
    else
      builtins.toJSON x;
  dumpCfg = x: toConfigValue x true;
  configAttrs = lib.filterAttrsRecursive (name: value: value != null) cfg.settings;
  configFile = pkgs.writeTextFile {
    name = "umurmur.conf";
    checkPhase = ''
      ${lib.getExe cfg.package} -t -c "$target"
    '';
    text = "\n" + (dumpCfg configAttrs) + "\n";
  };
in
{
  options = {
    services.umurmur = {
      enable = lib.mkEnableOption "uMurmur Mumble server";

      package = lib.mkPackageOption pkgs "umurmur" { };

      openFirewall = lib.mkOption {
        type = lib.types.bool;
        default = false;
        description = ''
          Open ports in the firewall for the uMurmur Mumble server.
        '';
      };

      settings = lib.mkOption {
        type = lib.types.submodule {
          freeformType =
            let
              valueType =
                with lib.types;
                oneOf [
                  bool
                  int
                  float
                  str
                  path
                  (listOf (attrsOf valueType))
                ]
                // {
                  description = "uMurmur config value";
                };
            in
            valueType;
          options = {
            welcometext = lib.mkOption {
              type = lib.types.nullOr lib.types.str;
              default = "Welcome to uMurmur!";
              description = "Welcome message for connected clients.";
            };

            bindaddr = lib.mkOption {
              type = lib.types.str;
              default = "0.0.0.0";
              description = "IPv4 address to bind to. Defaults binding on all addresses.";
            };

            bindaddr6 = lib.mkOption {
              type = lib.types.str;
              default = "::";
              description = "IPv6 address to bind to. Defaults binding on all addresses.";
            };

            bindport = lib.mkOption {
              type = lib.types.port;
              default = 64739;
              description = "Port to bind to (UDP and TCP).";
            };

            password = lib.mkOption {
              type = lib.types.nullOr lib.types.str;
              default = null;
              description = "Required password to join server, if specified.";
            };

            max_bandwidth = lib.mkOption {
              type = lib.types.int;
              default = 48000;
              description = ''
                Maximum bandwidth (in bits per second) that clients may send
                speech at.
              '';
            };

            max_users = lib.mkOption {
              type = lib.types.int;
              default = 10;
              description = "Maximum number of concurrent clients allowed.";
            };

            certificate = lib.mkOption {
              type = lib.types.str;
              default = "/var/lib/private/umurmur/cert.crt";
              description = "Path to your SSL certificate. Generates self-signed automatically if not exists.";
            };

            private_key = lib.mkOption {
              type = lib.types.str;
              default = "/var/lib/private/umurmur/key.key";
              description = "Path to your SSL key. Generates self-signed automatically if not exists.";
            };

            ca_path = lib.mkOption {
              type = lib.types.nullOr lib.types.str;
              default = null;
              description = "Path to your SSL CA certificate.";
            };

            channels = lib.mkOption {
              type = lib.types.listOf lib.types.attrs;
              default = [
                {
                  name = "root";
                  parent = "";
                  description = "Root channel.";
                  noenter = false;
                }
              ];
              description = "Channel tree definitions.";
            };

            channel_links = lib.mkOption {
              type = lib.types.listOf lib.types.attrs;
              default = [ ];
              example = [
                {
                  source = "Lobby";
                  destination = "Red team";
                }
              ];
              description = "Channel tree definitions.";
            };

            default_channel = lib.mkOption {
              type = lib.types.str;
              default = "root";
              description = "The channel in which users will appear in when connecting.";
            };

          };
        };
        default = { };
        description = "Settings of uMurmur. For reference see https://github.com/umurmur/umurmur/blob/master/umurmur.conf.example";
      };

      configFile = lib.mkOption rec {
        type = lib.types.path;
        default = configFile;
        description = "Configuration file, default is generated from config.service.umurmur.settings";
        defaultText = description;
      };
    };
  };

  config = lib.mkIf cfg.enable {
    networking.firewall = lib.mkIf cfg.openFirewall {
      allowedTCPPorts = [ cfg.settings.bindport ];
      allowedUDPPorts = [ cfg.settings.bindport ];
    };

    systemd.services.umurmur = {
      description = "uMurmur Mumble Server";
      wants = [ "network.target" ];
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        Type = "exec";
        ExecStart = "${lib.getExe cfg.package} -d -c ${cfg.configFile}";
        Restart = "on-failure";
        DynamicUser = true;
        StateDirectory = "umurmur";
        ReadWritePaths = "/dev/shm";

        # hardening
        UMask = 27;
        MemoryDenyWriteExecute = true;
        AmbientCapabilities = [ "" ];
        CapabilityBoundingSet = [ "" ];
        DevicePolicy = "closed";
        LockPersonality = true;
        NoNewPrivileges = true;
        PrivateDevices = true;
        PrivateTmp = true;
        PrivateUsers = true;
        ProtectSystem = "full";
        ProtectClock = true;
        ProtectControlGroups = true;
        ProtectHome = true;
        ProtectHostname = true;
        ProtectKernelLogs = true;
        ProtectKernelModules = true;
        ProtectKernelTunables = true;
        ProcSubset = "pid";
        ProtectProc = "invisible";
        RemoveIPC = true;
        RestrictAddressFamilies = [
          "AF_UNIX"
          "AF_INET"
          "AF_INET6"
        ];
        RestrictNamespaces = true;
        RestrictRealtime = true;
        RestrictSUIDSGID = true;
        SystemCallArchitectures = "native";
        SystemCallFilter = [
          "@system-service"
          "~@cpu-emulation"
          "~@debug"
          "~@mount"
          "~@obsolete"
          "~@privileged"
          "~@resources"
        ];
      };
    };
  };

  meta.maintainers = with lib.maintainers; [ _3JlOy-PYCCKUi ];
  meta.doc = ./umurmur.md;
}
Loading