diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix index 43fcc68ded42..6e8f062c1694 100644 --- a/nixos/modules/module-list.nix +++ b/nixos/modules/module-list.nix @@ -1013,6 +1013,7 @@ ./services/networking/shorewall.nix ./services/networking/shorewall6.nix ./services/networking/shout.nix + ./services/networking/sing-box.nix ./services/networking/sitespeed-io.nix ./services/networking/skydns.nix ./services/networking/smartdns.nix diff --git a/nixos/modules/services/networking/sing-box.nix b/nixos/modules/services/networking/sing-box.nix new file mode 100644 index 000000000000..d32725f77147 --- /dev/null +++ b/nixos/modules/services/networking/sing-box.nix @@ -0,0 +1,66 @@ +{ config, lib, pkgs, utils, ... }: +let + cfg = config.services.sing-box; + settingsFormat = pkgs.formats.json { }; +in +{ + + meta = { + maintainers = with lib.maintainers; [ nickcao ]; + }; + + options = { + services.sing-box = { + enable = lib.mkEnableOption (lib.mdDoc "sing-box universal proxy platform"); + + package = lib.mkPackageOptionMD pkgs "sing-box" { }; + + settings = lib.mkOption { + type = lib.types.submodule { + freeformType = settingsFormat.type; + options = { + route = { + geoip.path = lib.mkOption { + type = lib.types.path; + default = "${pkgs.sing-geoip}/share/sing-box/geoip.db"; + defaultText = lib.literalExpression "\${pkgs.sing-geoip}/share/sing-box/geoip.db"; + description = lib.mdDoc '' + The path to the sing-geoip database. + ''; + }; + geosite.path = lib.mkOption { + type = lib.types.path; + default = "${pkgs.sing-geosite}/share/sing-box/geosite.db"; + defaultText = lib.literalExpression "\${pkgs.sing-geosite}/share/sing-box/geosite.db"; + description = lib.mdDoc '' + The path to the sing-geosite database. + ''; + }; + }; + }; + }; + default = { }; + description = lib.mdDoc '' + The sing-box configuration, see https://sing-box.sagernet.org/configuration/ for documentation. + + Options containing secret data should be set to an attribute set + containing the attribute `_secret` - a string pointing to a file + containing the value the option should be set to. + ''; + }; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.packages = [ cfg.package ]; + + systemd.services.sing-box = { + preStart = '' + mkdir -p /etc/sing-box + ${utils.genJqSecretsReplacementSnippet cfg.settings "/etc/sing-box/config.json"} + ''; + wantedBy = [ "multi-user.target" ]; + }; + }; + +} diff --git a/nixos/tests/all-tests.nix b/nixos/tests/all-tests.nix index 6e9c893c809e..e1ecda9af42c 100644 --- a/nixos/tests/all-tests.nix +++ b/nixos/tests/all-tests.nix @@ -686,6 +686,7 @@ in { shiori = handleTest ./shiori.nix {}; signal-desktop = handleTest ./signal-desktop.nix {}; simple = handleTest ./simple.nix {}; + sing-box = handleTest ./sing-box.nix {}; slurm = handleTest ./slurm.nix {}; smokeping = handleTest ./smokeping.nix {}; snapcast = handleTest ./snapcast.nix {}; diff --git a/nixos/tests/sing-box.nix b/nixos/tests/sing-box.nix new file mode 100644 index 000000000000..43be89317642 --- /dev/null +++ b/nixos/tests/sing-box.nix @@ -0,0 +1,45 @@ +import ./make-test-python.nix ({ lib, pkgs, ... }: { + + name = "sing-box"; + + meta = { + maintainers = with lib.maintainers; [ nickcao ]; + }; + + nodes.machine = { pkgs, ... }: { + environment.systemPackages = [ pkgs.curl ]; + services.nginx.enable = true; + services.sing-box = { + enable = true; + settings = { + inbounds = [{ + type = "mixed"; + tag = "inbound"; + listen = "127.0.0.1"; + listen_port = 1080; + users = [{ + username = "user"; + password = { _secret = pkgs.writeText "password" "supersecret"; }; + }]; + }]; + outbounds = [{ + type = "direct"; + tag = "outbound"; + }]; + }; + }; + }; + + testScript = '' + machine.wait_for_unit("nginx.service") + machine.wait_for_unit("sing-box.service") + + machine.wait_for_open_port(80) + machine.wait_for_open_port(1080) + + machine.succeed("curl --fail --max-time 10 --proxy http://user:supersecret@localhost:1080 http://localhost") + machine.fail("curl --fail --max-time 10 --proxy http://user:supervillain@localhost:1080 http://localhost") + machine.succeed("curl --fail --max-time 10 --proxy socks5://user:supersecret@localhost:1080 http://localhost") + ''; + +}) diff --git a/pkgs/tools/networking/sing-box/default.nix b/pkgs/tools/networking/sing-box/default.nix index a93a973e4b39..1e15eaf9a192 100644 --- a/pkgs/tools/networking/sing-box/default.nix +++ b/pkgs/tools/networking/sing-box/default.nix @@ -4,21 +4,23 @@ , fetchFromGitHub , installShellFiles , buildPackages +, coreutils , nix-update-script +, nixosTests }: buildGoModule rec { pname = "sing-box"; - version = "1.2.7"; + version = "1.3.0"; src = fetchFromGitHub { owner = "SagerNet"; repo = pname; rev = "v${version}"; - hash = "sha256-+pRG5nq0Be58at61qqu5QciHC2DMvw+wj7u8tZx8+eY="; + hash = "sha256-+zEjuoGFAZhajUCFPZXNr1SoAprjOsHf12nVCbDKOeY="; }; - vendorHash = "sha256-gHPMJ4/W2ZisG/jAtHSLH/NlHgBitg7Bwe95wGJAsOY="; + vendorHash = "sha256-KJEjqcwtsNEByTQjp+TU9Yct/CJD8F9fnGuq9eeGtpQ="; tags = [ "with_quic" @@ -50,9 +52,17 @@ buildGoModule rec { --bash <(${emulator} $out/bin/sing-box completion bash) \ --fish <(${emulator} $out/bin/sing-box completion fish) \ --zsh <(${emulator} $out/bin/sing-box completion zsh ) + + substituteInPlace release/config/sing-box{,@}.service \ + --replace "/usr/bin/sing-box" "$out/bin/sing-box" \ + --replace "/bin/kill" "${coreutils}/bin/kill" + install -Dm444 -t "$out/lib/systemd/system/" release/config/sing-box{,@}.service ''; - passthru.updateScript = nix-update-script { }; + passthru = { + updateScript = nix-update-script { }; + tests = { inherit (nixosTests) sing-box; }; + }; meta = with lib;{ homepage = "https://sing-box.sagernet.org";