How to force Git to use socks proxy over its ssh connection?

Viewed 7320

There are tons of identical solutions over the internet for defining proxy tunnel for git's downloads like this one, which all is by setting git's https.proxy & http.proxy config. but those answers are not working when you try to clone/push/pull etc. over the ssh protocol!

For example, by setting git config --global https.proxy socks5://127.0.0.1:9999 when you try to clone git clone git@github.org:user/repo.git it does not go through the defined sock5 tunnel!

I've tried various thing but none was working!

Question:

How to set git to use a local socks5 proxy (e.g. 127.0.0.1:9999) when it uses ssh connections?

5 Answers

There are 2 types to clone git: HTTP, and ssh. There are 2 common types of proxy: HTTP, and socks.

Here's the method dealing with 2 * 2 conditions:

# Method 1. git http + proxy http
git config --global http.proxy "http://127.0.0.1:1080"
git config --global https.proxy "http://127.0.0.1:1080"

# Method 2. git http + proxy shocks
git config --global http.proxy "socks5://127.0.0.1:1080"
git config --global https.proxy "socks5://127.0.0.1:1080"

# to unset
git config --global --unset http.proxy
git config --global --unset https.proxy

# Method 3. git ssh + proxy http
vim ~/.ssh/config
Host github.com
HostName github.com
User git
ProxyCommand socat - PROXY:127.0.0.1:%h:%p,proxyport=1087

# Method 4. git ssh + proxy socks
vim ~/.ssh/config
Host github.com
HostName github.com
User git
ProxyCommand nc -v -x 127.0.0.1:1080 %h %p

The previous answers may work but I find them overly complex.

The most common case should be to access a corporate git server over a SOCKS5 proxy. In this example:

  • Git server: git.evilcorp.com
  • SOCKS5 proxy: localhost:11080

The easiest way to configure git in this case is to have a nice SSH config for the git server (~/.ssh/config):

Host git.evilcorp.com
  # Identity file specifies wich SSH key used to access the git server.
  Identityfile ~/.ssh/id_rsa
  # ProxyCommand does the magic to access the proxy server.
  ProxyCommand /bin/nc -X 5 -x 127.0.0.1:11080 %h %p

Cool detail: The DNS resolution is done by the proxy, so your machine doesn't need to know about the corp DNS servers.

After some visiting so many pages, I finally find the solution to my question:

# [step 1] create a ssh-proxy
  ssh -D 9999 -qCN user@server.net

# [step 2] make git connect through the ssh-proxy
  # [current script only]
  export GIT_SSH_COMMAND='ssh -o ProxyCommand="connect -S 127.0.0.1:9999 %h %p"'
  # OR [git global setting] 
  git config --global core.sshCommand 'ssh -o ProxyCommand="connect -S 127.0.0.1:9999 %h %p"'
  # OR [one-time only use]
  git clone -c=core.sshCommand 'ssh -o ProxyCommand="connect -S 127.0.0.1:9999 %h %p"' git@github.com:user/repo.git
  # OR [current repository use only]
  git config core.sshCommand 'ssh -o ProxyCommand="connect -S 127.0.0.1:9999 %h %p"'

To install connect on Ubuntu:

sudo apt install connect-proxy

git's own git --config 'http.proxy=socks5://127.0.0.1:4444' or ssh_config's proxycommand using socat and nc techniques successfully reroute git commands over the SOCKS proxy.

The problem could be, however, that the DNS lookup fails due to the lookup being done locally rather than remotely over over the SOCKS proxy. For example, in the case of an intranet, the servers may not have domain names on the internet (only known to intranet DNS).

There are two ways to solve this. The first one I've seen recommended several times, but it makes the ambitious assumption that you control the remote server.

  1. Reroute local 53 traffic (DNS) to port X, forward that to the server at port Y, forward port Y to 53 on the server. Usually X=Y for simplicity.

  2. Intercept local system calls that retrieve ip addresses for names.

I would argue that 2. is better, because it catches the problem at the source and only assumes that you control your local machine, which is a more likely case than controlling the remote server.

proxychains-ng intecepts the getaddrinfo system call before it accesses your local nss.

Steps

Open a SOCKS5 port

ssh -v -NT -D 127.0.0.1:4444 intranethost

Setup proxychains to use that port.

~/.proxychains/proxychains.conf

strict_chain
proxy_dns
tcp_read_time_out 150000
tcp_connect_time_out 80000

[ProxyList]
socks5 127.0.0.1 4444

Use proxychains to encapsulate git.

alias gitproxy='proxychains git'
gitproxy clone intranethost:path/to/repo.git

The beauty of taking this route is that this is all transparent to git and its remotes.

You need to define the GIT_SSH_COMMAND environment variable first

In it, you can redefine the ssh command, in order to use your socks proxy setting

ssh -D $port_number $hostname
# or
ssh -D $port_number $username@$hostname

Or using a proxycommand nc (or ncat on Windows)

The point is: once ssh is working with your socks5 proxy, you can define the same syntax in GIT_SSH_COMMAND, and Git will use the right ssh command.

You can also test it with a local configuration:

git -c core.sshCommand='ssh -D 9998 user@host.com' git pull
git -c core.sshCommand='ssh -D 9999 127.0.0.1' git pull
Related