From 8c39f54eee79713a3fdd1860b6c964bb82ae0036 Mon Sep 17 00:00:00 2001 From: jz8132543 Date: Fri, 8 Mar 2024 13:54:40 +0800 Subject: [PATCH] add: fw-proxy --- flake.lock | 90 +++ flake.nix | 15 + home-manager/modules/desktop/dconf-proxy.nix | 20 + nixos/hosts/isk/_steam/dst/default.nix | 4 + nixos/hosts/surface/default.nix | 1 + .../modules/base/module/fw-proxy/default.nix | 688 ++++++++++++++++++ nixos/modules/base/module/misc/ports.nix | 2 +- nixos/modules/base/nixpkgs.nix | 1 + nixos/modules/desktop/apps.nix | 10 +- nixos/modules/services/fw-proxy.nix | 76 ++ nixos/modules/services/hydra.nix | 1 + secrets/common.yaml | 170 ++--- 12 files changed, 988 insertions(+), 90 deletions(-) create mode 100644 home-manager/modules/desktop/dconf-proxy.nix create mode 100644 nixos/modules/base/module/fw-proxy/default.nix create mode 100644 nixos/modules/services/fw-proxy.nix diff --git a/flake.lock b/flake.lock index 8f296fbc..c4de61b7 100644 --- a/flake.lock +++ b/flake.lock @@ -15,6 +15,35 @@ "type": "github" } }, + "clash2sing-box": { + "inputs": { + "fenix": [ + "fenix" + ], + "flake-utils": [ + "flake-utils" + ], + "naersk": [ + "naersk" + ], + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1705993101, + "narHash": "sha256-V1F/nH7qUlZ6vjXwrhc8yMUv/tYALwjbC1aXrcoBfWs=", + "owner": "oluceps", + "repo": "clash2sing-box", + "rev": "2fbf7be3336c0e48d6a60674e566fbeaca29f7ef", + "type": "github" + }, + "original": { + "owner": "oluceps", + "repo": "clash2sing-box", + "type": "github" + } + }, "colmena": { "inputs": { "flake-compat": "flake-compat", @@ -173,6 +202,27 @@ "type": "github" } }, + "fenix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ], + "rust-analyzer-src": "rust-analyzer-src" + }, + "locked": { + "lastModified": 1709792596, + "narHash": "sha256-DQL1KJ9AaoQjwMkZkSBrW9/az2dwbbBnhNIbIzgeDIE=", + "owner": "nix-community", + "repo": "fenix", + "rev": "221fedb628b1e86e88d8fbfbd20b699448e58fa9", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "fenix", + "type": "github" + } + }, "flake-compat": { "flake": false, "locked": { @@ -633,6 +683,26 @@ "type": "github" } }, + "naersk": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1698420672, + "narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=", + "owner": "nix-community", + "repo": "naersk", + "rev": "aeb58d5e8faead8980a807c840232697982d47b9", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "naersk", + "type": "github" + } + }, "neovim-flake": { "inputs": { "flake-utils": "flake-utils_4", @@ -1006,11 +1076,13 @@ "root": { "inputs": { "blank": "blank", + "clash2sing-box": "clash2sing-box", "colmena": "colmena", "deploy-rs": "deploy-rs", "devenv": "devenv", "devshell": "devshell", "disko": "disko", + "fenix": "fenix", "flake-compat": "flake-compat_2", "flake-parts": "flake-parts", "flake-utils": "flake-utils_3", @@ -1023,6 +1095,7 @@ "impermanence": "impermanence", "latest": "latest", "linyinfeng": "linyinfeng", + "naersk": "naersk", "neovim-nightly-overlay": "neovim-nightly-overlay", "nix-index-database": "nix-index-database", "nixago": "nixago", @@ -1040,6 +1113,23 @@ "xremap-flake": "xremap-flake" } }, + "rust-analyzer-src": { + "flake": false, + "locked": { + "lastModified": 1709749600, + "narHash": "sha256-jLGAyPPi4PVo/9y6ayWgdAtzPotFWvNTCxrDzxO+Uj0=", + "owner": "rust-lang", + "repo": "rust-analyzer", + "rev": "ce15e73a8ece3cf9e7958bbad3aedb03daa10135", + "type": "github" + }, + "original": { + "owner": "rust-lang", + "ref": "nightly", + "repo": "rust-analyzer", + "type": "github" + } + }, "sops-nix": { "inputs": { "nixpkgs": [ diff --git a/flake.nix b/flake.nix index 5a0c0fd9..767012a3 100644 --- a/flake.nix +++ b/flake.nix @@ -32,6 +32,14 @@ url = "github:nix-community/haumea"; inputs.nixpkgs.follows = "nixpkgs"; }; + naersk = { + url = "github:nix-community/naersk"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; colmena = { url = "github:zhaofengli/colmena"; inputs.nixpkgs.follows = "nixpkgs"; @@ -145,6 +153,13 @@ inputs.flake-utils.follows = "flake-utils"; inputs.flake-compat.follows = "flake-compat"; }; + clash2sing-box = { + url = "github:oluceps/clash2sing-box"; + inputs.flake-utils.follows = "flake-utils"; + inputs.naersk.follows = "naersk"; + inputs.nixpkgs.follows = "nixpkgs"; + inputs.fenix.follows = "fenix"; + }; # Themes grub2-themes = { url = "github:vinceliuice/grub2-themes"; diff --git a/home-manager/modules/desktop/dconf-proxy.nix b/home-manager/modules/desktop/dconf-proxy.nix new file mode 100644 index 00000000..d4a2e29f --- /dev/null +++ b/home-manager/modules/desktop/dconf-proxy.nix @@ -0,0 +1,20 @@ +{ + lib, + osConfig, + ... +}: let + proxy = { + host = "localhost"; + port = osConfig.networking.fw-proxy.ports.mixed; + }; +in { + dconf.settings = lib.mkIf (osConfig.networking.fw-proxy.enable && osConfig.programs.dconf.enable) { + "system/proxy" = { + mode = "manual"; + use-same-proxy = true; + }; + "system/proxy/http" = proxy; + "system/proxy/https" = proxy; + "system/proxy/socks" = proxy; + }; +} diff --git a/nixos/hosts/isk/_steam/dst/default.nix b/nixos/hosts/isk/_steam/dst/default.nix index ab7fb5de..fd6bdd2e 100644 --- a/nixos/hosts/isk/_steam/dst/default.nix +++ b/nixos/hosts/isk/_steam/dst/default.nix @@ -1,6 +1,7 @@ { config, pkgs, + lib, ... }: let gameHome = config.users.users.steam.home; @@ -73,6 +74,9 @@ in { ExecStop = stopScript; CPUQuota = "300%"; # at most 1.5 core (2 cores in total) }; + environment = + lib.mkIf (config.networking.fw-proxy.enable) + config.networking.fw-proxy.environment; wantedBy = ["multi-user.target"]; }; networking.firewall.allowedUDPPorts = [ diff --git a/nixos/hosts/surface/default.nix b/nixos/hosts/surface/default.nix index 4484673b..85d438cb 100644 --- a/nixos/hosts/surface/default.nix +++ b/nixos/hosts/surface/default.nix @@ -9,6 +9,7 @@ ++ nixosModules.desktop.all ++ [ ./hardware-configuration.nix + nixosModules.services.fw-proxy ]; microsoft-surface = { diff --git a/nixos/modules/base/module/fw-proxy/default.nix b/nixos/modules/base/module/fw-proxy/default.nix new file mode 100644 index 00000000..936c4ac1 --- /dev/null +++ b/nixos/modules/base/module/fw-proxy/default.nix @@ -0,0 +1,688 @@ +{ + config, + lib, + pkgs, + ... +}: let + cfg = config.networking.fw-proxy; + + mixedPort = cfg.ports.mixed; + tproxyPort = cfg.ports.tproxy; + + enableProxy = pkgs.writeShellApplication { + name = "enable-proxy"; + text = '' + ${lib.concatMapStringsSep "\n" (env: ''export ${env.name}="${env.value}"'') (lib.attrsToList cfg.environment)} + ''; + }; + disableProxy = pkgs.writeShellApplication { + name = "disable-proxy"; + text = '' + ${lib.concatMapStringsSep "\n" (name: ''export ${name}=""'') (lib.attrNames cfg.environment)} + ''; + }; + updateSingBoxUrl = pkgs.writeShellApplication { + name = "update-sing-box-url"; + runtimeInputs = with pkgs; [ + curl + jq + yq + moreutils + systemd + clash2sing-box + ]; + text = '' + dir="/etc/sing-box" + + url="" + # downloaded_config_type="sing-box" + downloaded_config_type="clash" + keep_temporary_directory="NO" + profile_name="" + + positional_args=() + while [[ $# -gt 0 ]]; do + case $1 in + --clash) + downloaded_config_type="clash" + shift + ;; + --keep-temporary-directory) + keep_temporary_directory="YES" + shift + ;; + --profile-name) + profile_name="$2" + shift + shift + ;; + -* ) + echo "unknown option $1" >&2 + exit 1 + ;; + *) + positional_args+=("$1") + shift + ;; + esac + done + if [ "''${#positional_args[@]}" = "1" ]; then + url="''${positional_args[0]}" + else + echo "invalid arguments ''${positional_args[*]}" >&2 + exit 1 + fi + + mkdir -p $dir + + echo 'Making temporary directory...' + tmp_dir=$(mktemp -t --directory update-sing-box-config.XXXXXXXXXX) + echo "Temporary directory is: $tmp_dir" + if [ -f "$dir/config.json" ]; then + echo 'Backup old config.json...' + cp "$dir/config.json" "$dir/config.json.old" + fi + function cleanup { + if [ "$keep_temporary_directory" != "YES" ]; then + echo 'Remove temporary directory...' + rm -rf "$tmp_dir" + fi + if [ -f "$dir/config.json.old" ]; then + echo 'Restore old config.json...' + cp "$dir/config.json.old" "$dir/config.json" + rm "$dir/config.json.old" + fi + } + trap cleanup EXIT + + echo 'Downloading original configuration...' + downloaded_config="$tmp_dir/downloaded-config" + curl -L "$url" \ + --fail-with-body \ + --show-error \ + --output "$downloaded_config" + profile_info_file="$tmp_dir/profile-info" + jq --null-input \ + --arg u "$url" \ + --arg p "$profile_name" \ + '{"url": $u, "profile_name": $p}' \ + >"$profile_info_file" + + echo 'Preprocessing original configuration...' + ${cfg.downloadedConfigPreprocessing} + + echo 'Converting downloaded configuration file to raw config.json...' + raw_config="$tmp_dir/raw-config.json" + if [ "$downloaded_config_type" = "sing-box" ]; then + cp "$downloaded_config" "$raw_config" + elif [ "$downloaded_config_type" = "clash" ]; then + ${pkgs.clash2sing-box}/bin/ctos-${pkgs.stdenv.hostPlatform.system} --source="$downloaded_config" gen >"$raw_config" + else + echo "unknown config type: ''${downloaded_config_type}" >&2 + exit 1 + fi + + echo 'Preprocessing raw config.json...' + ${cfg.configPreprocessing} + + echo 'Build config.json...' + jq --slurp '.[0] * .[1]' "$raw_config" - <"$dir/config.json" + ${builtins.toJSON cfg.mixinConfig} + EOF + + external_controller_secrets=$(cat "${cfg.externalController.secretFile}") + jq " + .experimental.clash_api.secret = \"''${external_controller_secrets}\" | + .experimental.clash_api.external_ui = \"${config.nur.repos.linyinfeng.yacd}\" + " "$dir/config.json" | sponge "$dir/config.json" + + echo 'Restarting sing-box...' + systemctl restart sing-box + systemctl status sing-box --no-pager + if [ -f "$dir/config.json.old" ]; then + echo 'Remove old config.json...' + rm "$dir/config.json.old" + fi + ''; + }; + updateSingBox = pkgs.writeShellApplication { + name = "update-sing-box"; + runtimeInputs = [ + updateSingBoxUrl + ]; + text = '' + profile="$1" + shift + case "$profile" in + ${lib.concatMapStringsSep "\n" (p: '' + "${p.name}") + update-sing-box-url "$(cat "${p.urlFile}")" --profile-name "$profile" "$@" + ;; + '') (lib.attrValues cfg.profiles)} + *) + update-sing-box-url "$profile" "$@" + ;; + esac + ''; + }; + tproxyUse = pkgs.writeShellApplication { + name = "fw-tproxy-use"; + runtimeInputs = with pkgs; [ + systemd + ]; + text = '' + exec systemd-run --user --property=NFTSet="${cfg.tproxy.nftSet}" --pipe --pty --wait "$@" + ''; + }; + tproxyCgroup = pkgs.writeShellApplication { + name = "fw-tproxy-cgroup"; + runtimeInputs = with pkgs; [ + nftables + ]; + text = '' + nft_table="${cfg.tproxy.nftTable}" + + function usage { + cat <