diff --git a/nixos/modules/services/networking/shadowsocks.nix b/nixos/modules/services/networking/shadowsocks.nix index 79d749abb9d5..79a0b66d260c 100644 --- a/nixos/modules/services/networking/shadowsocks.nix +++ b/nixos/modules/services/networking/shadowsocks.nix @@ -29,8 +29,15 @@ let configFile = pkgs.writeText "shadowsocks.json" (builtins.toJSON opts); + executablesMap = { + "${getName pkgs.shadowsocks-libev}" = { + server = "ss-server"; + }; + "${getName pkgs.shadowsocks-rust}" = { + server = "ssserver"; + }; + }; in - { ###### interface @@ -47,14 +54,25 @@ in ''; }; + package = mkPackageOption pkgs "Shadowsocks" { + default = "shadowsocks-libev"; + }; + localAddress = mkOption { - type = types.coercedTo types.str singleton (types.listOf types.str); + type = + with types; + oneOf [ + str + (listOf str) + ]; + # Keeped for compatibility default = [ "[::0]" "0.0.0.0" ]; description = '' Local addresses to which the server binds. + Note: shadowsocks-rust accepts only string parameter. ''; }; @@ -163,14 +181,19 @@ in (noPasswd && !noPasswdFile) || (!noPasswd && noPasswdFile); message = "Option `password` or `passwordFile` must be set and cannot be set simultaneously"; } + { + # Ensure localAddress is a string if package is shadowsocks-rust + assertion = !(getName cfg.package == "shadowsocks-rust" && !lib.strings.isString cfg.localAddress); + message = "Option `localAddress` must be a string when using shadowsocks-rust."; + } ]; - systemd.services.shadowsocks-libev = { - description = "shadowsocks-libev Daemon"; + systemd.services.${getName cfg.package} = { + description = "${getName cfg.package} Daemon"; after = [ "network.target" ]; wantedBy = [ "multi-user.target" ]; path = [ - pkgs.shadowsocks-libev + cfg.package ] ++ optional (cfg.plugin != null) cfg.plugin ++ optional (cfg.passwordFile != null) pkgs.jq; @@ -179,7 +202,9 @@ in ${optionalString (cfg.passwordFile != null) '' cat ${configFile} | jq --arg password "$(cat "${cfg.passwordFile}")" '. + { password: $password }' > /tmp/shadowsocks.json ''} - exec ss-server -c ${if cfg.passwordFile != null then "/tmp/shadowsocks.json" else configFile} + exec ${(executablesMap.${getName cfg.package}).server} -c ${ + if cfg.passwordFile != null then "/tmp/shadowsocks.json" else configFile + } ''; }; }; diff --git a/nixos/tests/shadowsocks/common.nix b/nixos/tests/shadowsocks/common.nix index 298483f36b8f..1ce54101a8be 100644 --- a/nixos/tests/shadowsocks/common.nix +++ b/nixos/tests/shadowsocks/common.nix @@ -1,11 +1,13 @@ { name, + package, plugin ? null, pluginOpts ? "", }: import ../make-test-python.nix ( { pkgs, lib, ... }: + { inherit name; meta = { @@ -27,9 +29,10 @@ import ../make-test-python.nix ( networking.firewall.allowedUDPPorts = [ 8488 ]; services.shadowsocks = { enable = true; + package = package; encryptionMethod = "chacha20-ietf-poly1305"; password = "pa$$w0rd"; - localAddress = [ "0.0.0.0" ]; + localAddress = "0.0.0.0"; port = 8488; fastOpen = false; mode = "tcp_and_udp"; @@ -78,7 +81,7 @@ import ../make-test-python.nix ( testScript = '' start_all() - server.wait_for_unit("shadowsocks-libev.service") + server.wait_for_unit("${lib.getName package}.service") server.wait_for_unit("nginx.service") client.wait_for_unit("shadowsocks-client.service") diff --git a/nixos/tests/shadowsocks/default.nix b/nixos/tests/shadowsocks/default.nix index 3587ffb0edc5..62e67d59afd6 100644 --- a/nixos/tests/shadowsocks/default.nix +++ b/nixos/tests/shadowsocks/default.nix @@ -5,12 +5,26 @@ }: { - "basic" = import ./common.nix { - name = "basic"; + "basic-libev" = import ./common.nix { + name = "basic-libev"; + package = pkgs.shadowsocks-libev; }; - "v2ray-plugin" = import ./common.nix { - name = "v2ray-plugin"; + "basic-rust" = import ./common.nix { + name = "basic-rust"; + package = pkgs.shadowsocks-rust; + }; + + "v2ray-plugin-libev" = import ./common.nix { + name = "v2ray-plugin-libev"; + package = pkgs.shadowsocks-libev; + plugin = "${pkgs.shadowsocks-v2ray-plugin}/bin/v2ray-plugin"; + pluginOpts = "host=nixos.org"; + }; + + "v2ray-plugin-rust" = import ./common.nix { + name = "v2ray-plugin-rust"; + package = pkgs.shadowsocks-rust; plugin = "${pkgs.shadowsocks-v2ray-plugin}/bin/v2ray-plugin"; pluginOpts = "host=nixos.org"; };