💾 Archived View for thrig.me › blog › 2024 › 06 › 19 › reverse-dns.gmi captured on 2024-06-20 at 11:50:59. Gemini links have been rewritten to link to archived content

View Raw

More Information

-=-=-=-=-=-=-

Reverse DNS

Most folks won't need to know about reverse DNS; it is relevant for SMTP and some other protocols I've forgotten about, and most people aren't running SMTP servers these days (or really ever in the grand scheme of things).

    $ host example.org.
    example.org has address 93.184.215.14
    example.org has IPv6 address 2606:2800:21f:cb07:6820:80da:af6b:8b2c
    example.org mail is handled by 0 .

So a lookup on "example.org" involves forward DNS, and such hostnames are what users may or may no longer put into their browser thing and may or may no longer see if some company has its way and is able to hide the pesky URL bar. The google is father, the google is mother. Anyways reverse DNS concerns taking the "93.184.215.14" and maybe getting a hostname back from that. Lots of addresses will not have reverse DNS setup, or most hosts if you include IPv6 and nobody is doing a wildcard DNS record dragnet. For IPv4 the reverse is pretty simple, and various tools will guess when you supply an address instead of a hostname and do the conversion for you.

    $ perl -E 'say join ".", reverse split /[.]/, shift' 93.184.215.14
    14.215.184.93
    $ host 14.215.184.93.in-addr.arpa
    Host 14.215.184.93.in-addr.arpa not found: 3(NXDOMAIN)
    $ host 93.184.215.14
    Host 14.215.184.93.in-addr.arpa. not found: 3(NXDOMAIN)
    $ host -t A thrig.me.
    thrig.me has address 104.207.156.138
    $ host 104.207.156.138
    138.156.207.104.in-addr.arpa domain name pointer thrig.me.

This is backwards so a DNS server can host a "104.in-addr.arpa." zone, and someone else (your ISP, eventually, which may be you) can be delegated the "207.104.in-addr.arpa." zone, and so forth. DNS is a distributed database. There is support for CIDR but it's weird and I only had to set it up once and eventually I simplified and got rid of the /23 subnet. This apparently was a surprising move as in academia you're not supposed to give up the physical space the subnet was associated with?

If you run SMTP servers you do need to worry about reverse DNS as thanks to spammers spamming spam server administrators got strict about where email would be accepted from. Some janky no-name IP address? How about no! Another place reverse DNS appears is for blacklist (RBL) services, which also grew out of spammers spamming spam. An RBL will host reverse-like records under some zone, so for example if something connects from 192.0.2.42 your mail server (or firewall or intrusion detection system or whatever) might query for

    $ host 42.2.0.192.zen.spamhaus.org.
    42.2.0.192.zen.spamhaus.org has address 127.0.0.10

which here indicates a "non-MTA ip" or host that should not be sending email therefore it's probably spam or someone has misconfigured a system or DNS record. You probably do not want your mail server on any of these blacklists, nor maybe even on the same subnet (say, a /24) with a bunch of blacklisted hosts. However, the IPv4 pool is pretty much used up, and some address ranges are pretty ruined by spammers and other such folks. Good luck, have fun!

What about IPv6, the morbidly curious reader may have been asking? It's more complicated. You need to fiddle around with the contents of the s6_addr field of a "struct in6_addr" object, or to call inet_ntop(3) and then parse a possibly abbreviated form into a fully qualified reverse form, or to use something that hides all these gory details.

    $ host -t AAAA thrig.me.
    thrig.me has IPv6 address 2001:19f0:8001:143b:5400:4ff:fe1a:8ed6
    $ host 2001:19f0:8001:143b:5400:4ff:fe1a:8ed6
    6.d.e.8.a.1.e.f.f.f.4.0.0.0.4.5.b.3.4.1.1.0.0.8.0.f.9.1.1.0.0.2.ip6.arpa domain name pointer thrig.me.
    $ host -t MX google.com.
    google.com mail is handled by 10 smtp.google.com.
    $ host -t AAAA smtp.google.com.
    smtp.google.com has IPv6 address 2607:f8b0:400e:c02::1a
    smtp.google.com has IPv6 address 2607:f8b0:400e:c02::1b
    smtp.google.com has IPv6 address 2607:f8b0:400e:c07::1a
    smtp.google.com has IPv6 address 2607:f8b0:400e:c07::1b
    $ host 2607:f8b0:400e:c02::1a
    a.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.c.0.e.0.0.4.0.b.8.f.7.0.6.2.ip6.arpa domain name pointer ph-in-f26.1e100.net.
    a.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.c.0.e.0.0.4.0.b.8.f.7.0.6.2.ip6.arpa domain name pointer ph-in-x1a.1e100.net.

If you've scrolled off an 80x24 terminal, maybe your thing is too complicated? That's a metric I made up just now. Another metric is how many pages of 80x24 terminals it takes before a website starts showing content, if any. Some of them are real bad.

    #!/usr/bin/env perl
    # reverse-host - calculate reverse DNS for the given hostname or IP
    use 5.36.0;
    use Socket qw(:addrinfo AF_INET AF_INET6 AF_UNSPEC SOCK_RAW
      inet_ntop unpack_sockaddr_in unpack_sockaddr_in6);

    my $host = shift // die "Usage: reverse-host ip-or-hostname\n";

    my ( $err, @results ) =
      getaddrinfo( $host, undef,
        { family => AF_UNSPEC, socktype => SOCK_RAW } );
    die "getaddrinfo: $err\n" if defined $err and length $err;
    say reverse_dns($_) for @results;

    sub reverse_dns {
        my ($sock) = @_;
        if ( $sock->{family} == AF_INET ) {
            goto &reverse4;
        } elsif ( $sock->{family} == AF_INET6 ) {
            goto &reverse6;
        } else {
            warn "unknown family $sock->{family}\n";
        }
    }

    sub reverse4 ( $sock, $tail = 'in-addr.arpa' ) {
        my ( undef, $paddr ) = unpack_sockaddr_in $sock->{addr};
        my @segments = split /[.]/, inet_ntop AF_INET, $paddr;
        return join( '.', reverse @segments ) . $tail;
    }

    sub reverse6 ( $sock, $tail = 'ip6.arpa' ) {
        my ( undef, $paddr ) = unpack_sockaddr_in6 $sock->{addr};
        my $ip = inet_ntop AF_INET6, $paddr;
        # Net::IP::XS has reverse_ip which may be better tested and faster?
        my $s = '';
        my ( $left, $right ) = split /::/, $ip;
        while ( $left =~ m/([A-Fa-f0-9]{1,4})/g ) {
            my $seg = $1;
            my $len = length $seg;
            if ( $len < 4 ) {
                $s .= ('0') x ( 4 - $len ) . $seg;
            } else {
                $s .= $seg;
            }
        }
        if ( length $right ) {
            my $t;
            while ( $right =~ m/([A-Fa-f0-9]{1,4})/g ) {
                my $seg = $1;
                my $len = length($seg);
                if ( $len < 4 ) {
                    $t .= ('0') x ( 4 - $len ) . $seg;
                } else {
                    $t .= $seg;
                }
            }
            $s .= ('0') x ( 32 - length($t) - length($s) ) . $t;
        }
        $s =~ s/(.)/.$1/g;
        return reverse($s) . $tail;
    }

reverse-host.pl

IPv6 support is a bit longer than for v4, no?

    $ perl reverse-host.pl thrig.me
    138.156.207.104in-addr.arpa
    6.d.e.8.a.1.e.f.f.f.4.0.0.0.4.5.b.3.4.1.1.0.0.8.0.f.9.1.1.0.0.2.ip6.arpa
    $ perl reverse-host.pl ::1
    1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa
    $ perl reverse-host.pl 2607:f8b0:400e:c02::1a
    a.1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.2.0.c.0.e.0.0.4.0.b.8.f.7.0.6.2.ip6.arpa
    $ perl reverse-host.pl /
    getaddrinfo: non-recoverable failure in name resolution
    $ perl reverse-host.pl _
    getaddrinfo: no address associated with name

Pretty sure this code is not buggy, but you may want a better tested library, but now you may have dependencies that need to be reviewed for supply chain attacks… also getaddrinfo(3) may not perform well if DNS is down or your system falls off the internet, but checking for return DNS packets or having a timeout if not is a bit more complicated.

P.S. another reason for IPv6 hate (probably especially in systems or languages where IPv6 was bolted on and not designed for or at least better hidden behind a cromulent interface) is that it adds branches to all the network codes, which increases the odds of bugs and increases the need for testing. IPv4 was also established for a while so there's inertia that humans may have trouble changing.

P.P.S. sometimes you can get away with leaving off the "." at the end of a hostname, but it is there, and sometimes leaving off that trailing "." will result in "foo.example.org.example.org" or similar messes if the lack of a trailing "." means "append something else" in that context. This is similar to the rsync problem of the trailing slash or not. Mostly it won't bite you, until it does.