Wednesday, April 8, 2020

Putty and double bastion host tunneling

I've always found complex ssh tunneling to be a pain in Windows.  Unfortunately, I'm stuck with it due to company mandate.  This post is as much about sharing the info as it is about documenting it so that I can come back and refer to it when I forget everything here.

So, the use case is this.  You have a host that you have to hop through in order to get to other hosts, but there may be more hosts that you can't get to unless you hop through yet another host.

For example, if I want to access my Linux workstation at the office, I have to hop through two hosts, my ssh bastion host and from there to another host that also has an IP on the office network, and from there to my desktop.

Even to experienced tunnelers, that's daunting, especially from Windows.

So, here goes.  Here's what the values in my example mean:

My workstation:
The public facing bastion host:
The internal server:
My username on my workstation: myusername
My username when accessing company servers: companyusername
My WSL username: myWSLusername

Putty Configuration

  1. Create a new session in Putty.
  2. Hostname:
  3. Port: 22
  4. Category → Connection → Data
    • Auto-login username: myusername
  5. Category → Connection → Proxy
    • Proxy type: Local
    • Telnet command, or local proxy command:
      c:\progra~1\putty\plink.exe -ssh -agent -A -l companyusername -nc %host:%port -proxycmd "c:\progra~1\putty\plink.exe -l companyusername -agent -A -nc"
  6. Category → Connection → SSH
    • Enable compression
    • Notice that I didn't use the compression option -C in my plink commands in the previous step.  When tunneling ssh traffic, you should only enable compression in one place so that you're not compressing traffic only to have other segments attempting to compress the already compressed data.
  7. Category → Connection → SSH → Auth
    • Attempt authentication using Pageant
    • Allow agent forwarding
  8. Category → Connection → SSH → X11
    • With WSL and VcXsrv X Server installed, you can run gui apps
    • X11 Forwarding: Enable X11 forwarding
    • X display location: (Look in VcXsrv server's log to confirm this value.)
    • Remote X11 authentication protocol: MIT-Magic-Cookie-1
    • X authority file for local display:
    • (You might to run from WSL bash shell xauth generate $DISPLAY initially to get the x authority file seeded.)
  9. Save new Putty session
  10. Launch new Putty session
There are certainly other ways of doing this that can be a little bit simpler.  One of the reasons I used this method is because my bastion host strips X11 traffic.  It's not configured for it and doesn't have any of the required x related dependencies needed (xorg-x11-server-utils et. al.).  Doing it the way I have creates a tunnel that simply passes all traffic through to the next host keeping me well below the application layer from the perspective of the bastion host.

Workstation File Access

The other advantage to this method is that I can use this same Putty session to make additional ssh tunnels that go right to my workstation.  So, in my Putty config detailed above, I also have a local tunnel 20202: that gives me direct ssh access to my workstation by ssh'ing to here on my laptop.

So, software like WinSCP can now access my workstation over this tunnel and behaves as if it were direct access.  I use Mountain Duck, which is not free software. The end result is that it allows me to map a drive right to my Linux workstation at the office from my Windows 10 laptop at home.

(Additionally, I use the RDP tunneling method described in my previous post to make it so that RDP sessions end up originating from my workstation.)


While drive/file access works quite well, this is not fast enough to do X11 well at all.  So as much as I'd like to run gvim directly from my workstation over the tunnel, it's just not fast enough.  

But, having the option to do it was helpful for me.  There were a couple apps that I really just needed some of the settings out of so that I could set up the Windows versions of those apps to work the same way.


I haven't actually explored the capabilities of the OpenSSH that's now included with Windows 10, but regardless, for non-Windows users, note that there is a newer ProxyJump directive.  This let's you chain together any number of bastion hosts.  So, following my earlier example, you can do something like in an .ssh/config file entry:

Host workstation-tunnel
User myusername
ForwardAgent yes
ForwardX11 yes
ForwardX11Trusted yes
Compress yes
PubkeyAuthentication yes

Then you just ssh workstation-tunnel and you're good!

Tuesday, April 7, 2020

SSH SOCKS Proxying with Putty

I'm writing this during the COVID-19 lockdown.  My company's VPN is getting hit really hard since everyone is working from home.  Anything we can do to stay off of it is helpful.

We also keep a host available with SSH exposed publicly (public key auth only).  So, I use that host as an SSH SOCKS proxy and it works great for keeping me off the VPN.

So, if you're in a similar position or simply would like to use SSH as a sort of pseudo-VPN, these instructions might be helpful.

Non-Windows users can do the same thing, you just need to use the ssh command to connect to the remote host and use the -D parameter.  Something like: ssh -D 1337 yourhost

Putty Configuration

  1. Create a new session in Putty
  2. Hostname: yourhost
  3. Port: 22
  4. Go under Category → Connection → Data
    • Auto-login username: <your username>
  5. Category → Connection → Proxy
    • Leave this off
  6. Category → Connection → SSH
    • Enable compression
  7. Category → Connection → SSH → Auth
    • Attempt to authenticate using Pageant
    • Allow agent forwarding
  8. Category → Connection → SSH → Tunnels
    • Source port: 1337
    • Destination: yourhost
    • Radio button: Dynamic
    • Click Add
    • (Just shows D1337, this ok)
  9. Save the new Putty session
  10. Launch the new Putty session

Proxy Configuration

Now, to actually use the proxy, you can go a couple ways.  Originally, I was doing it the manual way, but I found the Chrome extension SOCKS proxy which works great.  It's hassle free and even make it so that DNS requests go over the proxy.  The source code is very small and easily reviewed so you can see it's not doing anything nefarious.

If you can't or won't install an extension, here's the manual method.
  1. Run the inetcpl.cpl control panel. (NOT the new Windows 10 Proxy Settings page.)
  2. Go under the Connections tab
  3. LAN settings button
  4. Uncheck automatic detection
  5. Check Use a proxy server for your LAN
  6. Advanced button.
  7. Fill in ONLY the SOCKS information (not http, secure, or ftp. Uncheck Use the same proxy for all protocols)
    • Socks:
    • Port: 1337

DNS Considerations

Now, if you don't have to worry about resolving any private DNS records, you're good to go.  My company has whole zones that aren't resolvable from the public internet.  For these, DNS queries have to originate from the company network.  Chrome, by default, will not send DNS requests over the SOCKS proxy, so there's an additional step required.

I suggest copying your existing Chrome icon and giving it a different name.  Edit this icon and append to the end of the Target: field, after the final quote (not inside the quotes) the following:

--proxy-server="socks5://" --host-resolver-rules="MAP * ~NOTFOUND , EXCLUDE"

I haven't test it myself, but I've heard that Firefox automatically pushes DNS requests over the proxy.


So one of the big limitations of this is that it doesn't really help in a heavy Active Directory environment where your PC has to communicate with things over a domain, such as shared drives.


However, you can tunnel RDP through your SSH host as well.  Configure additional tunnels, one per RDP destination. Back in your new Putty session:

  • Category → Connection → SSH → Tunnels
  • Source port: 38001
    • (This is a made up value of no significance. You'll have to make one up for each RDP destination.)
  • Destination: rdphost:3389
  • Relaunch your Putty session
  • Open RDP
  • Use the destination address:
  • Repeat the port forwards with different port numbers for each RDP host you to access.