💾 Archived View for thrig.me › blog › 2024 › 06 › 19 › reverse-host.pl captured on 2024-06-20 at 11:51:02.

View Raw

More Information

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

#!/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;
}