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