🡅 up Joining HINFO.network

Joining HINFO.network

HINFO.network is a new social network^W^Wwebring of people that manage to make their DNS server send some system information upon a particular obscure request from RFC883, namely HINFO.

As this is totally my thing, I needed to join! Since I just got this new setup here, I thought, eh, let's throw together some Perl to talk to the Porkbun API to set that DNS record and there we go.

I did in fact implement the Porkbun API (which consists of yeeting some JSON over the hedge), before I realized... this API doesn't support setting HINFO records, bleh.

Since I wasn't too much of a fan of using Porkbun's Cloudflare DNS anyway, I did the logical thing and started self-hosting my DNS. My tool of choice is good ole tinydns. Then I realized tinydns got removed from FreeBSD ports earlier this year. But this cannot stop me, so I copied the port from an older checkout and built it myself... At least daemontools is still in tree. Then I moved the zone over. I'll spare you the details, you probably did this before. Since this is just my toy website, having a single DNS server serving its own address is alright, isn't it?

The next, albeit minor, hurdle is that of course tinydns also doesn't support HINFO, but it has an escape hatch: namely, a : record can return arbitrary DNS content. So let's read the RFC above to see what we should answer:

HINFO RDATA format

     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     /                      CPU                      /
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
     /                       OS                      /
     +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+

   where:


   CPU   - A character string which specifies the CPU type.  The
             character string is represented as a single octet
             length followed by that number of characters. 
   OS   - A character string which specifies the operating system
   type.  The character string is represented as a single octet
   length followed by that number of characters.

Okay, this is reasonably easy to generate, so I added this record:

:phala.isatty.net:13:\005AMD64\014FREEBSD/13.2:300

tinydns even supports octal escapes for directly entering bytes, how convenient.

But... imagine I'll update to FreeBSD 14 soon. Do you expect me to edit this file like a peasant? Of course, we need to automate this. So let's write a Perl script:

#!/bin/sh -e
# update-hinfo - update our host's HINFO entry
perl -i- -pe 'BEGIN { chomp ($cpu=uc `uname -m`);
  chomp($os=uc `uname -sr` =~ s/ /\//r =~ s/-.*//r); }
s/^(:phala.isatty.net:13:).*/sprintf("%s\\%03o%s\\%03o%s:300",
  $1,length($cpu),$cpu,length($os),$os)/e' /usr/local/etc/tinydns/root/data
cd /usr/local/etc/tinydns/root && make

That's it! tinydns doesn't need reloading, just compiling the DNS database is enough.

Note the use of s///r (new in Perl 5.14) which returns a copy, so it conveniently chains. Luckily, generating the djbdns zonefile format is trivial with sprintf.

Let's test it:

% dig +nocomments +nostats +nocmd phala.isatty.net hinfo
;phala.isatty.net.              IN      HINFO
phala.isatty.net.       107     IN      HINFO   "AMD64" "FREEBSD/13.2"

Now add this into our crontab(5) for @reboot and there we go!