diff --git a/flake.lock b/flake.lock index 3582629c..414a7a65 100644 --- a/flake.lock +++ b/flake.lock @@ -44,11 +44,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1765644376, - "narHash": "sha256-yqHBL2wYGwjGL2GUF2w3tofWl8qO9tZEuI4wSqbCrtE=", + "lastModified": 1767364772, + "narHash": "sha256-fFUnEYMla8b7UKjijLnMe+oVFOz6HjijGGNS1l7dYaQ=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "23735a82a828372c4ef92c660864e82fbe2f5fbe", + "rev": "16c7794d0a28b5a37904d55bcca36003b9109aaa", "type": "github" }, "original": { @@ -99,11 +99,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1765766816, - "narHash": "sha256-m2au5a2x9L3ikyBi0g3/NRJSjmHVDvT42mn+O6FlyPs=", + "lastModified": 1767581716, + "narHash": "sha256-FUbiUzdrGkLou37OGfb4vCLPnqdSIvtmJBxjh2iljiE=", "owner": "oxalica", "repo": "rust-overlay", - "rev": "4f53a635709d82652567f51ef7af4365fbc0c88b", + "rev": "1d3f83babdd21e16bf5cfe0f1efcb4f49ee1bc2c", "type": "github" }, "original": { diff --git a/nix/nixos-module.nix b/nix/nixos-module.nix index b21b0b1f..f3833d09 100644 --- a/nix/nixos-module.nix +++ b/nix/nixos-module.nix @@ -31,8 +31,10 @@ in { }; config = mkIf cfg.enable { + # Add client package environment.systemPackages = [cfg.package]; + # Setup systemd service for the intrerface management daemon systemd.services.defguard-service = { description = "Defguard VPN Service"; wantedBy = ["multi-user.target"]; @@ -40,36 +42,20 @@ in { after = ["network-online.target"]; serviceConfig = { ExecStart = "${cfg.package}/bin/defguard-service --log-level ${cfg.logLevel} --stats-period ${toString cfg.statsPeriod}"; - Restart = "on-failure"; - RestartSec = 5; - User = "defguard"; + ExecReload = "/bin/kill -HUP $MAINPID"; Group = "defguard"; - StateDirectory = "defguard"; - LogsDirectory = "defguard"; - # Add capabilities to manage network interfaces - CapabilityBoundingSet = "CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE"; - AmbientCapabilities = "CAP_NET_ADMIN CAP_NET_RAW CAP_SYS_MODULE"; - # Allow access to /dev/net/tun for TUN/TAP devices - DeviceAllow = "/dev/net/tun rw"; - # Access to /sys for network configuration - BindReadOnlyPaths = [ - "/sys" - "/proc" - ]; - # Protect the system while giving necessary access - ProtectSystem = "strict"; - ProtectHome = true; - NoNewPrivileges = true; - # Allow the service to manage network namespaces - PrivateNetwork = false; + Restart = "on-failure"; + RestartSec = 2; + KillMode = "process"; + KillSignal = "SIGINT"; + LimitNOFILE = 65536; + LimitNPROC = "infinity"; + TasksMax = "infinity"; + OOMScoreAdjust = -1000; }; }; - users.users.defguard = { - isSystemUser = true; - group = "defguard"; - }; - + # Make sure the defguard group exists users.groups.defguard = {}; }; } diff --git a/nix/package.nix b/nix/package.nix index da00eaae..76c31bc8 100644 --- a/nix/package.nix +++ b/nix/package.nix @@ -6,9 +6,12 @@ rustc, cargo, makeDesktopItem, + pnpmConfigHook, + fetchPnpmDeps, }: let pname = "defguard-client"; - version = "1.6.2"; # TODO: Get this from Cargo.toml or git + # Automatically read version from Cargo.toml + version = (fromTOML (builtins.readFile ../src-tauri/Cargo.toml)).workspace.package.version; desktopItem = makeDesktopItem { name = pname; @@ -29,7 +32,7 @@ gdk-pixbuf glib glib-networking - gtk4 + gtk3 harfbuzz librsvg libsoup_3 @@ -37,7 +40,13 @@ webkitgtk_4_1 openssl libayatana-appindicator + libayatana-indicator + ayatana-ido + libdbusmenu-gtk3 desktop-file-utils + iproute2 + lsb-release + openresolv ]; nativeBuildInputs = [ @@ -50,11 +59,12 @@ pkgs.protobuf pnpm # configures pnpm to use pre-fetched dependencies - pnpm.configHook + pnpmConfigHook # configures cargo to use pre-fetched dependencies rustPlatform.cargoSetupHook - # helper to add dynamic library paths + # helper to add runtime binary & library deps paths pkgs.makeWrapper + pkgs.wrapGAppsHook3 ]; in stdenv.mkDerivation (finalAttrs: rec { @@ -71,7 +81,7 @@ in }; # prefetch pnpm dependencies - pnpmDeps = pkgs.pnpm.fetchDeps { + pnpmDeps = fetchPnpmDeps { inherit (finalAttrs) pname @@ -80,38 +90,74 @@ in ; fetcherVersion = 2; - hash = "sha256-v47yaNnt7vLDPR7WVLSonmZBBOkYWnmTUqMiPZ/WCGo="; + hash = "sha256-Xtn0FIq097sLEl/iodLeVVOYxVLx1ePJ8UjJUmgB2f0="; }; buildPhase = '' - pnpm tauri build + runHook preBuild + + pnpm tauri build --verbose + + runHook postBuild ''; - postInstall = '' + installPhase = '' + runHook preInstall + mkdir -p $out/bin # copy client binary - cp src-tauri/target/release/${pname} $out/bin/ + install -Dm755 src-tauri/target/release/${pname} $out/bin/${pname} # copy background service binary - cp src-tauri/target/release/defguard-service $out/bin/ + install -Dm755 src-tauri/target/release/defguard-service $out/bin/defguard-service # copy CLI binary - cp src-tauri/target/release/dg $out/bin/ + install -Dm755 src-tauri/target/release/dg $out/bin/dg - # add required library to client binary RPATH - wrapProgram $out/bin/${pname} \ - --prefix LD_LIBRARY_PATH : ${lib.makeLibraryPath [pkgs.libayatana-appindicator pkgs.desktop-file-utils]} + # Copy resources directory (for tray icons, etc.) + mkdir -p $out/lib/${pname} + cp -r src-tauri/resources $out/lib/${pname}/ + # install desktop entry mkdir -p $out/share/applications cp ${desktopItem}/share/applications/* $out/share/applications/ + + # install icon files + mkdir -p $out/share/icons/hicolor/{32x32,128x128}/apps + install -Dm644 src-tauri/icons/32x32.png $out/share/icons/hicolor/32x32/apps/${pname}.png + install -Dm644 src-tauri/icons/128x128.png $out/share/icons/hicolor/128x128/apps/${pname}.png + + runHook postInstall + ''; + + # add extra args to wrapGAppsHook3 wrapper + preFixup = '' + gappsWrapperArgs+=( + --prefix PATH : ${ + lib.makeBinPath [ + # `defguard-service` needs `ip` to manage WireGuard + pkgs.iproute2 + # `defguard-service` needs `resolvconf` to manage DNS + pkgs.openresolv + # `defguard-client` needs `update-desktop-database` and `lsb_release` + pkgs.desktop-file-utils + pkgs.lsb-release + ] + } + --prefix LD_LIBRARY_PATH : ${ + lib.makeLibraryPath [ + pkgs.libayatana-appindicator + ] + } + ) ''; meta = with lib; { description = "Defguard VPN Client"; homepage = "https://defguard.net"; # license = licenses.gpl3Only; - maintainers = with maintainers; []; + maintainers = with maintainers; [wojcik91]; platforms = platforms.linux; }; }) diff --git a/src-tauri/src/service/daemon.rs b/src-tauri/src/service/daemon.rs index 6ecf251f..e8d1d097 100644 --- a/src-tauri/src/service/daemon.rs +++ b/src-tauri/src/service/daemon.rs @@ -508,9 +508,11 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { // Remove existing socket if it exists if Path::new(DAEMON_SOCKET_PATH).exists() { + debug!("Removing existing socket file at {DAEMON_SOCKET_PATH}"); fs::remove_file(DAEMON_SOCKET_PATH)?; } + debug!("Binding socket file at {DAEMON_SOCKET_PATH}"); let uds = UnixListener::bind(DAEMON_SOCKET_PATH)?; // change owner group for socket file @@ -521,10 +523,12 @@ pub async fn run_server(config: Config) -> anyhow::Result<()> { })?; // change ownership - keep current user, change group + debug!("Changing owner group of socket file at {DAEMON_SOCKET_PATH} to group {DAEMON_SOCKET_GROUP}"); chown(DAEMON_SOCKET_PATH, None, Some(group.gid))?; // Set socket permissions to allow client access // 0o660 allows read/write for owner and group only + debug!("Setting permissions for socket file at {DAEMON_SOCKET_PATH} to 0x660"); fs::set_permissions(DAEMON_SOCKET_PATH, fs::Permissions::from_mode(0o660))?; let uds_stream = UnixListenerStream::new(uds);