Deprecated Behaviour

The inane, sometimes insane, ramblings from the mind of Brenton Alker.

Getting the Tools: Haskell Edition

I prefer to reserve the system-level package manager for system-level packages, which my development tools generally are not. As such, my tools are installed in my ~/opt/ directory where possible (then symlinked to ~/bin/).

In this post, I’m looking at how I did this for my Haskell tool-set.

Haskell’s cabal is a great dependency management/build tool with built-in sandbox capabilities. It is also often used to install many Haskell tools, such as hlint, pointfree and doctest.

I was originally installing these tools by creating a subdirectory per tool (e.g. ~/opt/haskell/hlint/) and using cabal sandbox init; cabal install hlint to install the tool (hlint in this case) within the sandbox.

But, I didn’t like having a set of “empty” directories (containing only the hidden .cabal-sandbox and cabal.sandbox.config). With a few extra arguments (thanks to some tips from Ben Kolera at the last BFPG hack night) we can forgo the superfluous subdirectories and reveal the sandboxes.

Here is an example of installing hlint:

# in ~/opt/haskell
cabal --sandbox-config-file=$PKG.sandbox.config sandbox init --sandbox=$PKG
cabal --sandbox-config-file=$PKG.sandbox.config install $PKG

This creates a sandbox config file called hlint.sandbox.config and a visible sandbox in the hlint directory.

You can then symlink the executable onto your path:

ln -s ~/opt/haskell/hlint/bin/hlint ~/bin/hlint

This is how I have installed all of these tools and is my currently preferred method. There are other variations on this that can also be used, for instance, adding the package’s bin directory to your path, or copying the actual executable out of the sandbox (then you could even delete the sandbox if you choose).

This works for all of the packages I mentioned above, and probably any others that you want to install just for the executable binary.

Open and Close SSH Tunnel in Script

I have been using SSH tunnels for a long time. Usually, I just manually open the tunnels I require. But, setting up my new machine (archlinux on a Thinkpad t440s.. shiny!) I’ve been writing a lot of shell scripts to automate much of what I used to do manually.

In that spirit, I wanted a script to create an ssh tunnel and connect my irc client (irssi) to my bouncer (znc), behind my home firewall.

So, this is what I’m using:

ssh -f -o ExitOnForwardFailure=yes -L 6667:localhost:6667 sleep 30

The -f -o ExitOnForwardFailure=yes combination makes ssh wait until the forwarded ports have been established before backgrounding. Effectively, this blocks the script until the ports are ready to use.

The sleep 30 keeps the connection open (in the background) for 30 seconds before ssh terminates. However, if there is an open connection on the tunnel, ssh will wait for it to close before terminating. This means, you have 30 seconds to connect to the forwarded port, then it will stay open as long as you’re using it. So, once I quit irssi, the tunnel closes.

Then, irssi configured to connect to localhost:6667 which is tunneled to localhost:6667 on the target machine, where it finds znc!

Replay Web Hook Requests With Netcat

Netcat (nc) is a really useful little utility, available for most (all?) OSs. It’s often used for low level network tinkering. Recently, I found an everyday (for me) use; Testing HTTP “Web Hooks”.

In my specific case, it was the Facebook “Real-Time” API, which POSTs data back to your registered endpoint when a given event occurs on Facebook. But, navigating to Facebook, performing an action and waiting for them to notify your server is a relatively slow process, and makes debugging painfully slow.

To overcome this, we need to be able to consistently repeat a request from Facebook while fine-tuning the handler to perform the required task.

Firstly, we can set up nc to capture the request. We could manually write a HTTP request, but this will ensure it is authentic and actually represents the request that will be sent by the third party.

nc -l 8000 > request.txt

This will cause nc to listen on port 8000 and write any incoming HTTP requests to “request.txt”. Then, we just need to coerce the target service to send us a request at the correct location (you could use port 80, if you don’t need to keep the web server running). Note: the listening nc process will not reply to the request, so the connection will stay open until the client times out or you manually kill the process. Once the request is received, it will be stored in “request.txt”, where we can view it, edit it and — most importantly — replay it.

We can also use nc to handle sending the request for us by piping the saved file through to the target server.

cat request.txt | nc 80

This will connect to our server and make the exact HTTP request that was captured. The advantage, of course, is that we can replay the request over and over quickly and accurately.