Pushin’ and Popin’ like a pro in Bash

This was blatantly stolen from here.

Ever wish

$ cd -

took you back to the previous directory more than once?

The answer was so obvious once I saw it that I smacked my head and said “D’OH” out loud (causing several people around the office to give me that ‘wth!?’ look.)

Stick this in your .bashrc and be welcomed into the world of directory history:

function cd {
    if (("$#" > 0)); then
        if [ "$1" == "-" ]; then
            popd > /dev/null
        else
            pushd "$@" > /dev/null
        fi
    else
        cd $HOME
    fi
}

I suppose that one could just type ‘pushd’ or ‘popd’ or alias those to shorter commands, but my muscle memory has simply chiseled cd (and ls for that matter) into stone.

Advanced SSH Tunneling with the ProxyCommand Directive

So if you’re anything like me, you have at least 2 or 3 Linux or OS X machines at home with SSH enabled. I frequently find that I need to access some of the data on those machines from remote locations, and scp doesn’t work too well through a NAT / Masquerading router. You can just poke holes through your firewall until it looks like Swiss cheese, or you can Get Serious(tm), setup your own DHCP and Gateway server, then use the ProxyCommand directive in your .ssh/config.

First, pick a gateway machine, one that will be be left online at all times, and install the ISC DHCP server (not the client) using your favorite package manager or tarball.

Next, edit the dhcpd.conf file (usually in /etc somewhere) and configure the subnet section to match the network of your NAT Router. For example, my NAT router is 192.168.2.1, and gives out 192.168.2.0/24 addresses.  Here’s what it would look like:

subnet 192.168.2.0 netmask 255.255.255.0 {
  range 192.168.2.10 192.168.2.254;
  option routers 192.168.2.1;
}

In the same file, add some sane DNS servers in the options (I’m using the public Google DNS servers in this example):

option domain-name-servers 8.8.8.8, 8.8.4.4;

The last change to this file  will involve getting the MAC addresses of the devices you’ll want to SSH into and giving them static IPs OUTSIDE the range you provided above. Mine are all the single digit addresses between 3-9:

host bob  {
  hardware ethernet 11:11:11:11:11:11;
  fixed-address 192.168.2.3;
}
host joe {
  hardware ethernet 22:22:22:22:22:22;
  fixed-address 192.168.2.4;
}
host jim {
  hardware ethernet aa:aa:aa:aa:aa:aa;
  fixed-address 192.168.2.5;
}
host jim-wifi {
  hardware ethernet aa:aa:aa:aa:aa:ab;
  fixed-address 192.168.2.6;
}

Notice I’ve given the wifi and wired adapters their own entries.

Now,  setup a static IP on your DHCP server (192.168.2.2), shut off DHCP on your router and test it out. After renewing DHCP on your devices, you should see the fixed addresses showing up on the devices you configured, and higher numbered 192.168.2.10-255 on unconfigured devices (phones, tablets, your Windows laptop, etc.)  Here’s a map of the configuration so far:

192.168.2.1      - Router / Default Gateway 
192.168.2.2      - SSH Gateway & DHCP server
192.168.2.3-9    - Fixed-address hosts
192.168.2.10-254 - Dynamic hosts
192.168.2.255    - Broadcast address

On the DHCP/Gateway server, setup a simple /etc/hosts file with these IP addresses, host names and a common suffix, such as ‘.home’.

192.168.2.3 bob.home
192.168.2.4 joe.home
192.168.2.5 jim.home
192.168.2.6 jim-wifi.home

Lastly, create or edit a .ssh/config file on the remote device / laptop to handle these names:

Host *.home
  user mysuername
  ProxyCommand ssh -v MY_EXTERNAL_IP -p 22 nc %h %p

Now you should be able to ‘ssh bob.home’ without any more typing, and scp to/from bob.home without using the gateway server as an intermediate step, or poking a hole in your firewall.

I’d recommend setting up public key authentication, and disabling password authentication.  You can also set it up to listen on a high-number port (remember to change the -p option in the ProxyCommand) but that’s only security through obscurity.

If your IP changes frequently, you can also look into Dynamic DNS services to give yourself a hostname rather than use your external IP address directly. DynDNS is no longer free, but there are other services out there if you want to look.