Loopback Workaround

Promenade across the floor,
Sashay right on out the door,
Out the door and into the glade,
And everybody promenade.

– Bugs Bunny, cited on IMDb

I run a small server at home. I’ve got Plex on there alongside a wee Dokuwiki where I chronicle my impressions of various single-malts and high-end chewing gums. I wanted a domain name for that server, but my ISP does not offer static IP addresses. Or perhaps it would be more accurate to say that I felt disinclined to pay for one. Either way, it was a problem.

To get around not having a static address I turned to Duck DNS where I was able to get a subdomain. (Let’s pretend that it’s mylightningrods.duckdns.org.) A cron job on my server regularly lets Duck DNS know where to send the traffic. It’s free. I have used it for a long time, and it works well. They accept donations, and I have made one.

Now into the creek and fish for the trout,
Dive right in and flap about;
Trout, trout, pretty little trout;
One more splash and come right out.

– ibid.

But there was another problem: The modem/router provided by my ISP will not handle a loopback. I could have bought a better router, but again I felt disinclined to throw money at the problem. So let’s imagine that my server’s IP address is 123.123.123.123. When I am at home I cannot reach the server at that address. Instead, I need to use the local address specific to my LAN. It might be something like 10.0.0.123. And of course that address is useful only from home.

So I needed a way to have one URL point to two different IP addresses depending on whether or not I was at home. Below is a solution I cobbled together for my MacBook Pro (running Sierra). The basic strategy is to run a daemon that checks my SSID once per minute and sometimes modifies my /etc/hosts file. When I am at home it should add a line to the file for my server’s local IP address. From anywhere else I can just rely on the Internet to do its thing.

Grab a fencepost hold it tight,
Whomp your partner with all your might;
Hit him in the shin, hit him in the head;
Hit him again, that critter ain’t dead.

– ibid.

Command to find SSID

First off we need a terminal command that will return our current SSID. I found the following suggestion at Stack Overflow:

1
/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk '/ SSID/ {print substr($0, index($0, $2))}'

bash script

Now we incorporate that command into the following bash script. I’m using these example values:

name value
Duck DNS address mylightningrods.duckdns.org
Server’s local IP address 10.0.0.123
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
#!/bin/bash
 
# Get the SSID
ssid=`/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I | awk '/ SSID/ {print substr($0, index($0, $2))}'`

# Test whether our domain name is already mentioned in the hosts file.
mydomain=`grep 'mylightningrods.duckdns.org' /etc/hosts`

# If we are connected to our home SSID:
if [[ $ssid == 'OUR-SSID' ]]
then
    # If we haven't yet added the domain name to the hosts file:
    if [[ -z $mydomain ]]
    then
        echo "10.0.0.123    mylightningrods.duckdns.org" >> /etc/hosts
    fi
# Otherwise take our domain name out of the hosts file:
else
    sed -e '/^.*mylightningrods.duckdns.org.*/d' -i '' /etc/hosts
fi

We’ll save the script at:

1
/Users/me/scripts/host.sh

And make it executable:

1
chmod a+x /Users/me/scripts/host.sh

daemon

Now we’ll create a file at:

1
/Library/LaunchDaemons/org.duckdns.mylightningrods.host.plist

And we’ll use the following values for our context:

name value
Duck DNS subdomain mylightningrods
Path to bash script /Users/me/scripts/host.sh
Path to .plist file /Library/LaunchDaemons/org.duckdns.mylightningrods.host.plist
Frequency in seconds 60
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>org.duckdns.mylightningrods.host</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/Users/me/scripts/host.sh</string>
    </array>
    <key>StartInterval</key>
    <integer>60</integer>
</dict>
</plist>

The <string> element on line 6 should correspond to the name of your .plist file (without the extension), and the <integer> corresponds to the desired frequency in seconds.

Finally we’ll need to load the daemon:

1
sudo launchctl load -w /Library/LaunchDaemons/org.duckdns.mylightningrods.host.plist

Bow to your partner
Now bow to your corner
Loopback workaround allemande left

– me