diff --git a/doc/build-helpers/fetchers.chapter.md b/doc/build-helpers/fetchers.chapter.md index 8ff1fdf11a19..5ee1d78501ca 100644 --- a/doc/build-helpers/fetchers.chapter.md +++ b/doc/build-helpers/fetchers.chapter.md @@ -163,6 +163,8 @@ Nixpkgs fetchers can make use of a http(s) proxy. Each fetcher will automaticall The environment variable `NIX_SSL_CERT_FILE` is also inherited in fetchers, and can be used to provide a custom certificate bundle to fetchers. This is usually required for a https proxy to work without certificate validation errors. +To use a temporary Tor instance as a proxy for fetching from `.onion` addresses, add `nativeBuildInputs = [ tor.proxyHook ];` to the fetcher parameters. + []{#fetchurl} ## `fetchurl` {#sec-pkgs-fetchers-fetchurl} diff --git a/pkgs/build-support/fetchgit/default.nix b/pkgs/build-support/fetchgit/default.nix index 55b90ec32547..d364c8ebf708 100644 --- a/pkgs/build-support/fetchgit/default.nix +++ b/pkgs/build-support/fetchgit/default.nix @@ -157,6 +157,19 @@ lib.makeOverridable ( "GIT_PROXY_COMMAND" "NIX_GIT_SSL_CAINFO" "SOCKS_SERVER" + + # This is a parameter intended to be set by setup hooks or preFetch + # scripts that want per-URL control over HTTP proxies used by Git + # (if per-URL control isn't needed, `http_proxy` etc. will + # suffice). It must be a whitespace-separated (with backslash as an + # escape character) list of pairs like this: + # + # http://domain1/path1 proxy1 https://domain2/path2 proxy2 + # + # where the URLs are as documented in the `git-config` manual page + # under `http..*`, and the proxies are as documented on the + # same page under `http.proxy`. + "FETCHGIT_HTTP_PROXIES" ]; inherit preferLocalBuild meta allowedRequisites; diff --git a/pkgs/build-support/fetchgit/nix-prefetch-git b/pkgs/build-support/fetchgit/nix-prefetch-git index f8dd93912644..259138641ea9 100755 --- a/pkgs/build-support/fetchgit/nix-prefetch-git +++ b/pkgs/build-support/fetchgit/nix-prefetch-git @@ -126,6 +126,11 @@ init_remote(){ echo "$sparseCheckout" | git sparse-checkout set --stdin ${nonConeMode:+--no-cone} fi ( [ -n "$http_proxy" ] && clean_git config --global http.proxy "$http_proxy" ) || true + local proxy_pairs i + read -a proxy_pairs <<< "${FETCHGIT_HTTP_PROXIES:-}" + for ((i = 1; i < ${#proxy_pairs[@]}; i += 2)); do + clean_git config --global "http.${proxy_pairs[$i - 1]}.proxy" "${proxy_pairs[$i]}" + done } # Return the reference of an hash if it exists on the remote repository. diff --git a/pkgs/by-name/to/tor/package.nix b/pkgs/by-name/to/tor/package.nix index 2d9f0b5b0169..7b044130c5e8 100644 --- a/pkgs/by-name/to/tor/package.nix +++ b/pkgs/by-name/to/tor/package.nix @@ -19,6 +19,7 @@ nixosTests, writeShellScript, versionCheckHook, + makeSetupHook, }: let @@ -111,8 +112,21 @@ stdenv.mkDerivation (finalAttrs: { versionCheckProgramArg = "--version"; passthru = { - tests.tor = nixosTests.tor; + tests = { + inherit (nixosTests) tor; + proxyHook = callPackage ./proxy-hook-tests.nix { + tor = finalAttrs.finalPackage; + }; + }; updateScript = callPackage ./update.nix { }; + proxyHook = makeSetupHook { + name = "tor-proxy-hook"; + substitutions = { + grep = lib.getExe gnugrep; + tee = lib.getExe' coreutils "tee"; + tor = lib.getExe finalAttrs.finalPackage; + }; + } ./proxy-hook.sh; }; meta = { diff --git a/pkgs/by-name/to/tor/proxy-hook-tests.nix b/pkgs/by-name/to/tor/proxy-hook-tests.nix new file mode 100644 index 000000000000..a0544115a85b --- /dev/null +++ b/pkgs/by-name/to/tor/proxy-hook-tests.nix @@ -0,0 +1,45 @@ +{ + testers, + fetchFromGitLab, + fetchgit, + fetchurl, + fetchzip, + linkFarm, + tor, +}: +let + domain = "eweiibe6tdjsdprb4px6rqrzzcsi22m4koia44kc5pcjr7nec2rlxyad.onion"; + rev = "933c5491db00c703d5d8264fdabd5a5b10aff96f"; + hash = "sha256-o6Wpso8GSlQH39GpH3IXZyrVhdP8pEYFxLDq9a7yHX0="; +in +linkFarm "tor-proxy-hook-tests" { + fetchgit = testers.invalidateFetcherByDrvHash fetchgit { + name = "fetchgit-tor-source"; + url = "http://${domain}/tpo/core/tor"; + inherit rev hash; + nativeBuildInputs = [ tor.proxyHook ]; + }; + + fetchzip = testers.invalidateFetcherByDrvHash fetchzip { + name = "fetchzip-tor-source"; + url = "http://${domain}/tpo/core/tor/-/archive/${rev}/tor-${rev}.zip"; + inherit hash; + nativeBuildInputs = [ tor.proxyHook ]; + }; + + fetchurl = testers.invalidateFetcherByDrvHash fetchurl { + name = "fetchurl-tor-source"; + url = "http://${domain}/tpo/core/tor/-/raw/${rev}/Cargo.lock"; + hash = "sha256-oX4WbsscLADgJ5o+czpueyAih7ic0u4lZQs7y1vMA3A="; + nativeBuildInputs = [ tor.proxyHook ]; + }; + + fetchFromGitLab = testers.invalidateFetcherByDrvHash fetchFromGitLab { + name = "gitlab-tor-source"; + protocol = "http"; + owner = "tpo/core"; + repo = "tor"; + inherit domain rev hash; + nativeBuildInputs = [ tor.proxyHook ]; + }; +} diff --git a/pkgs/by-name/to/tor/proxy-hook.sh b/pkgs/by-name/to/tor/proxy-hook.sh new file mode 100644 index 000000000000..ae00a94b181c --- /dev/null +++ b/pkgs/by-name/to/tor/proxy-hook.sh @@ -0,0 +1,19 @@ +_setupTorProxy(){ + local torSocket=$NIX_BUILD_TOP/.tor.sock + local torPort=unix:$torSocket + + exec {tor_fd}< <(@tor@ --DataDirectory "$NIX_BUILD_TOP/.tor" --SocksPort "$torPort") + exitHooks+=("kill '$!'") + + # Wait for Tor to start + read < <(<&$tor_fd- @tee@ /dev/fd/2 | @grep@ -m 1 -F 'Bootstrapped 100% (done): Done') + + export ALL_PROXY="socks5h://localhost$torSocket" + + # A Git repository may have submodules that fetch from clearnet URLs, so + # for better performance, use Tor only for onion addresses. (fetchgit + # doesn't respect ALL_PROXY, so this doesn't conflict.) + export FETCHGIT_HTTP_PROXIES="http://*.onion $ALL_PROXY ${FETCHGIT_HTTP_PROXIES-}" +} + +postHooks+=(_setupTorProxy)