Small Tools

I regularly cobble together small tools to fit niche tasks. Julia Evans recently wrote a blog post about small utilities she wrote, and I thought it was a nice idea, so I’m doing the same. Although unlike Julia I don’t have links to each one (some of them will be in my sourcehut git).

Julia Evans: Tiny Programs

sipping

VoIP needs to deal with NAT a lot. One of these instances is when sending an inbound call to a UAC. UAC’s register to their registrar on a (typically) fixed interval, and in the process open a small hole in their ISP-provided router’s firewall that lets SIP messages come in and go out. This hole, like all holes opened by NAT, has a short lifetime, and will be closed after activity has ceased for a short period.

We want that port to remain open so when a UAC needs to start ringing for an inbound call, we can send an INVITE their way and have them deal with it. If the port were closed, we’d be stuffed. SIP Session Border Controllers deal with this using a few different ways, the most common (I believe) being SIP OPTIONS packets. SIP pings, essentially. At some point I had a need to send these pings to UACs from a host differing to the one they registered against.

sipping is a small tool that reads a mysql table containing the address the UAC registered, the UAC’s address (post-NAT), and the UAC’s port (also post-NAT). It then uses raw sockets to send a periodic SIP OPTIONS packet with a falsified source address to ensure the little hole in their firewall remains open.

This was probably one of the first times I fiddled with C. Chosen because it needed to be fast, and raw sockets aren’t the nicest of things to work with in a lot of languages.

netps

I’ve spoke about this before in my “Stateful Monitoring” post. Icinga does a lot of checks on a lot of systems, and SSH is a natural choice for dealing with subsystems that lack an HTTP API. One common task was checking if a process was running or had restarted. With enough hosts, and enough processes on those hosts, you’re either stuck with too many SSH connections open on the monitoring servers, or with too many SSH connections open on the monitored host. SSH isn’t light. An HTTP API is (comparatively) lighter as it avoids everything that goes into setting up a login environment, a shell, privilege elevation permissions to see the full process table, and so on.

netps wraps around ps-go, to which I made a small modification to provide process start-time. It essentially serves up the current process list as JSON to clients that can provide a suitable client certificate. It was written in Golang, which made the HTTP server and certificate handling trivial, and was a good illustration of the advantages of a broad std library.

icinga-shim

I’ve used a variety of communication tools while working. icinga-shim was a small program written in Golang that implemented an API that could be used by Icinga 2 to push notifications of new alerts into various chat applications.

This was ultimately the last time I touched Golang. A large period of time followed where I didn’t write another tool, and when the next opportunity arose, I wanted something that had proper support on DragonFly BSD targeting other operating systems (MacOS, glibc Linux and ulibc Linux). Which led me to C and Zig.

lmset/lmget/lmsweep

At some point I needed a fast, in-memory database that would fail quickly and handle inserts/deletes “best-effort”. Mutation of the database either had to be instant, or return immediately to avoid blocking the process that attempted them.

LMDB seemed like the best choice, so I knocked up three (relatively poor) utilities to insert/update (lmset), fetch (lmget) and delete old data (lmsweep). Data deletion was done by a secondary key:value pair with a predictable name. On insertion of “mykey1” with lmset, it also inserted “mykey1-${epoch_now}”. lmsweep would then iterate over every key in the store with that sort of name, and bin the ones older than a provided offset (60m, as an example).

A bit crappy, a bit clunky, but they work without issue for the particular use-case they were needed for. There’s obviously issues with people inserting keys that look like that generated timestamp key, but in a controlled environment that isn’t a large concern.

sendqueue

This went through two or three iterations, and was ultimately scrapped. I wanted a HTTP request queuing system to queue up POSTs and re-attempt failed POSTs, so an application could just pass them off and not worry about them happening. This would of course be possible a few different ways - an AMQP-based solution would have probably been the best option. But I wanted something lighter and simpler to use on the submitter’s side.

It was written in C, and then Elixir, and then C again. Eventually settling on C using libcurl for making requests and Mongoose for handling submissions, with the application split into two to avoid messing with threads. Requests would be submitted to the server, with final destination indicated in an HTTP header, and serialized down to disk in a simple but custom text format, as to ease troubleshooting. The “server-client” would then periodically work through those files and relocate them if they’d failed n times.

Ultimately by the time I’d finished playing around, we’d found another solution and completing it became unnecessary. But that’s what playing around is about.

bulkdelete and sumfile

Lots of files are a pain to work with. Scripting stuff around them with bash isn’t too difficult, but is slow. And in some circumstances, you’re very much outside of the Bash comfort-zone (floats, numbers in general).

bulkdelete was originally written in C, then ported to Zig to provide better handling of edge-cases. It reads of a list containing absolute paths and then deletes them, with a final report of how many files were deleted, missing, or where we lacked permission to delete.

sumfile is the same, except instead of deleting the file it records its size and produces a similar report. Written in zig from the start.

monitor-shim

monitor-shim replaces icinga-shim, but does the same thing. Rather than adapt icinga-shim, and try to remember what Golang looks like, I instead wrote monitor-shim in zig. This was interesting for two reasons:

  1. Zig’s std library doesn’t contain a HTTP client, let alone a HTTP server. It may never contain them.
  2. Zig’s C interop is phenomenal.

Frankly, using libcurl with zig is as trivial as if you were writing C. I’ve used libcurl in C previously (a project not listed here), and it largely translated without much thought on my part. I did need to wrap my head around using ArrayList with it, and using the compatibility types (c_long, as an example) - but it was practically seamless. They even (sensibly) provide an example on the Zig site for using libcurl.

For the HTTP server, I made use of Mongoose again, having used it with sendqueue (above). Mongoose is a bit weird in that you’re provided a single C file, and a single C header file. But again, largely trivial. The only issue I ran up against was Zig’s C->Zig compiler making a few structs anyopaque when it would have been really useful for it to not do that. It seems like that particular rough patch will be sorted in Zig 0.10.

k8sicing

A terrible name, but a useful tool. Kubernetes events are generally quite useful, and indicate their own severity in their JSON, making it easy enough to pick out the ones you care about. Icinga doesn’t really operate on the basis of ‘services’ being transient, so most of this project was figuring a pattern that could actually work.

In practice, an event of concern in kubernetes is translated into a passive check result in Icinga for a generated service named for the component that caused the event, with all generated services living under a single host referring to the particular cluster they belong to. In order to make these very much not-ephemeral services look ephemeral, k8sicing instructs the Icinga API to delete all service objects that have existed for a certain period of time, under each cluster host, but only if they have been acknowledged for greater-than n minutes.

Vanadate

I have a something-completely-different post on this, but in quick summary, the online game Final Fantasy XI (released 2002) has its own date system based on our own, but with shorter minutes. It’s very cool, and I wanted the time and date on my desktop, so I knocked up a small program that prints the time and date in Vana’Diel (the world in which the game is set).