Package: git
Version: 1:2.42.0-1
Tags: patch

Dear Maintainer,

git does not support AF_UNIX proxies, despite the git-config manual page
suggesting it will accept anything supported by curl:
  http.proxy
      Override the HTTP proxy, normally configured using the http_proxy,
      https_proxy, and all_proxy environment variables (see curl(1)). In
      addition to the syntax understood by curl, it is possible to
      specify a proxy string with a user name but no password,

I tried to use "torsocks git fetch" with a .onion remote I'd cloned from
in the past, and got an error:
        fatal: unable to access 'http://[elided].onion/git/': Not resolving 
.onion address (RFC 7686)

It seems to be a known problem, and I tried working around it by setting
an AF_UNIX proxy as documented for --proxy in the curl(1) manual:
        export all_proxy=socks5h://localhost/run/tor/socks

That works for curl, but "git fetch" gives an error:
        fatal: unable to access 'http://[elided].onion/git/': Failed to connect 
to localhost port 1080 after 0 ms: Couldn't connect to server

While debugging, I found that git was reading this environment variable,
parsing it poorly, and overriding it by giving libcurl a proxy string of
just "localhost"; seeing no path or port number, curl tries AF_INET6 and
AF_INET with port 1080.

I'm attaching a patch that fixes this.  I haven't tested thoroughly, but
tried to avoid unnecessary changes to the credential code (which I think
should use libcurl to parse URLs).  The flags for curl_url_set() are the
same as in curl's own parse_proxy() function.

  Permission is hereby granted, irrevocably and free of charge, to any
  person obtaining a copy of this software and associated documentation
  files (the "Software"), to deal in the Software without restriction,
  including without limitation the rights to use, copy, modify, merge,
  publish, distribute, sublicense, and/or sell copies of the Software,
  and to permit persons to whom the Software is furnished to do so.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

- Michael


-- System Information:
Debian Release: trixie/sid
  APT prefers unstable-debug
  APT policy: (500, 'unstable-debug'), (500, 'unstable'), (1, 'experimental')
Architecture: amd64 (x86_64)

Kernel: Linux 6.5.0-1-amd64 (SMP w/32 CPU threads; PREEMPT)
Locale: LANG=en_CA.UTF-8, LC_CTYPE=en_CA.UTF-8 (charmap=UTF-8), 
LANGUAGE=en_CA:en
Shell: /bin/sh linked to /usr/bin/dash
Init: systemd (via /run/systemd/system)
LSM: AppArmor: enabled

Versions of packages git depends on:
ii  git-man          1:2.42.0-1
ii  libc6            2.37-11
ii  libcurl3-gnutls  8.3.0-2
ii  liberror-perl    0.17029-2
ii  libexpat1        2.5.0-2
ii  libpcre2-8-0     10.42-4
ii  perl             5.36.0-9
ii  zlib1g           1:1.2.13.dfsg-3

Versions of packages git recommends:
ii  ca-certificates              20230311
ii  less                         590-2
ii  openssh-client [ssh-client]  1:9.4p1-1
ii  patch                        2.7.6-7

Versions of packages git suggests:
ii  gettext-base                          0.21-13+b1
pn  git-cvs                               <none>
pn  git-daemon-run | git-daemon-sysvinit  <none>
ii  git-doc                               1:2.42.0-1
ii  git-email                             1:2.42.0-1
pn  git-gui                               <none>
pn  git-mediawiki                         <none>
pn  git-svn                               <none>
ii  gitk                                  1:2.42.0-1
pn  gitweb                                <none>

-- no debconf information

diff --git a/http.c b/http.c
index e138b4b96fb9..7ba155a77406 100644
--- a/http.c
+++ b/http.c
@@ -1135,32 +1135,39 @@ static CURL *get_curl_handle(void)
                 */
                curl_easy_setopt(result, CURLOPT_PROXY, "");
        } else if (curl_http_proxy) {
-               if (starts_with(curl_http_proxy, "socks5h"))
-                       curl_easy_setopt(result,
-                               CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME);
-               else if (starts_with(curl_http_proxy, "socks5"))
-                       curl_easy_setopt(result,
-                               CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
-               else if (starts_with(curl_http_proxy, "socks4a"))
-                       curl_easy_setopt(result,
-                               CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4A);
-               else if (starts_with(curl_http_proxy, "socks"))
-                       curl_easy_setopt(result,
-                               CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4);
-#ifdef GIT_CURL_HAVE_CURLOPT_PROXY_KEYPASSWD
-               else if (starts_with(curl_http_proxy, "https")) {
-                       curl_easy_setopt(result, CURLOPT_PROXYTYPE, 
CURLPROXY_HTTPS);
+               CURLU *url = curl_url();
+               CURLUcode urc;
+               char *url_str = NULL;
+
+               url = curl_url();
+               if (!url) {
+                       urc = CURLUE_OUT_OF_MEMORY;
+                       goto proxy_out;
+               }
 
-                       if (http_proxy_ssl_cert)
-                               curl_easy_setopt(result, CURLOPT_PROXY_SSLCERT, 
http_proxy_ssl_cert);
+               urc = curl_url_set(url, CURLUPART_URL, curl_http_proxy,
+                               CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
+               if (urc)
+                       goto proxy_out;
 
-                       if (http_proxy_ssl_key)
-                               curl_easy_setopt(result, CURLOPT_PROXY_SSLKEY, 
http_proxy_ssl_key);
+               if (http_proxy_ssl_cert) {
+                       urc = curl_easy_setopt(result, CURLOPT_PROXY_SSLCERT, 
http_proxy_ssl_cert);
+                       if (urc)
+                               goto proxy_out;
+               }
 
-                       if (has_proxy_cert_password())
-                               curl_easy_setopt(result, 
CURLOPT_PROXY_KEYPASSWD, proxy_cert_auth.password);
+               if (http_proxy_ssl_key) {
+                       urc = curl_easy_setopt(result, CURLOPT_PROXY_SSLKEY, 
http_proxy_ssl_key);
+                       if (urc)
+                               goto proxy_out;
                }
-#endif
+
+               if (has_proxy_cert_password()) {
+                       urc = curl_easy_setopt(result, CURLOPT_PROXY_KEYPASSWD, 
proxy_cert_auth.password);
+                       if (urc)
+                               goto proxy_out;
+               }
+
                if (strstr(curl_http_proxy, "://"))
                        credential_from_url(&proxy_auth, curl_http_proxy);
                else {
@@ -1170,13 +1177,45 @@ static CURL *get_curl_handle(void)
                        strbuf_release(&url);
                }
 
-               if (!proxy_auth.host)
-                       die("Invalid proxy URL '%s'", curl_http_proxy);
+               if (!proxy_auth.host) {
+                       urc = CURLUE_URLDECODE;
+                       goto proxy_out;
+               }
+
+               /* Set a proxy URL without username or password.
+                * init_curl_proxy_auth() will deal with those.
+                */
+               urc = curl_url_set(url, CURLUPART_USER, NULL,
+                               CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
+               if (urc)
+                       goto proxy_out;
+
+               urc = curl_url_set(url, CURLUPART_PASSWORD, NULL,
+                               CURLU_NON_SUPPORT_SCHEME|CURLU_GUESS_SCHEME);
+               if (urc)
+                       goto proxy_out;
+
+               urc = curl_url_get(url, CURLUPART_URL, &url_str, 0);
+               if (urc)
+                       goto proxy_out;
+
+               urc = curl_easy_setopt(result, CURLOPT_PROXY, url_str);
+               if (urc)
+                       goto proxy_out;
 
-               curl_easy_setopt(result, CURLOPT_PROXY, proxy_auth.host);
                var_override(&curl_no_proxy, getenv("NO_PROXY"));
                var_override(&curl_no_proxy, getenv("no_proxy"));
-               curl_easy_setopt(result, CURLOPT_NOPROXY, curl_no_proxy);
+               urc = curl_easy_setopt(result, CURLOPT_NOPROXY, curl_no_proxy);
+               if (urc)
+                       goto proxy_out;
+
+proxy_out:
+               curl_url_cleanup(url);
+               curl_free(url_str);
+               if (urc) {
+                       die("Unable to parse proxy URL '%s': %s",
+                                       curl_http_proxy, 
curl_url_strerror(urc));
+               }
        }
        init_curl_proxy_auth(result);
 

Attachment: signature.asc
Description: PGP signature

Reply via email to