Network info

gethostbyaddr#

Look up a host record by its packed IP address.

gethostbyaddr performs a reverse DNS lookup: given a packed binary address (four bytes for IPv4, sixteen for IPv6) and the matching address family, it calls the system’s C gethostbyaddr(3) routine and returns the host record. The typical use case — “whose machine is this packet from?” — wants the scalar-context form: a single hostname. The list-context form exposes the full struct hostent: canonical name, aliases, address family, address length, and every address the resolver knows for that host.

Synopsis#

my $name = gethostbyaddr $packed_addr, $addrtype;
my ($name, $aliases, $addrtype, $length, @addrs) = gethostbyaddr $packed_addr, $addrtype;

What you get back#

Scalar context — the canonical hostname as a plain string, or undef if the reverse lookup fails.

List context — a five-element list mirroring the C struct hostent:

  • $name — the canonical hostname the resolver mapped the address to.

  • $aliases — a space-separated string of alternate names. Single scalar, not a list.

  • $addrtype — the address family of the returned addresses, typically AF_INET (2) or AF_INET6 (10).

  • $length — the length of each address in bytes (4 for IPv4, 16 for IPv6).

  • @addrs — every address returned for the host, each a packed binary string of $length bytes. Often just one, but multi-homed hosts can yield several.

On lookup failure in list context, the return is the empty list.

Global state it touches#

  • $? — set to the C h_errno value on failure, when the platform exposes it. Test with $? != 0 to distinguish HOST_NOT_FOUND from TRY_AGAIN and similar transient errors.

  • $! — not meaningfully set by DNS failures. Reverse lookups fail via h_errno, not errno; do not check $! after a failed call.

  • The host database iteration cursor shared with gethostent, sethostent, and endhostent. A call to gethostbyaddr may reset a cursor left open by gethostent.

Examples#

Scalar form — map a dotted-quad to a hostname:

use Socket;
my $packed = inet_aton("127.0.0.1");
my $name   = gethostbyaddr($packed, AF_INET);
print defined $name ? "$name\n" : "no PTR record\n";

Round-trip — forward lookup, then reverse the first address:

use Socket;
my $packed = gethostbyname("www.perl.org");
my $name   = gethostbyaddr($packed, AF_INET);
print "$name\n";

Identify the peer on an accepted socket connection:

use Socket;
my $peer = getpeername($sock);
my ($port, $iaddr) = sockaddr_in($peer);
my $host = gethostbyaddr($iaddr, AF_INET);
printf "connection from %s:%d\n", $host // inet_ntoa($iaddr), $port;

List form — every name and address the resolver knows for the host:

use Socket;
my $packed = inet_aton("8.8.8.8");
my ($name, $aliases, $type, $len, @addrs) = gethostbyaddr($packed, AF_INET);
print "canonical: $name\n";
print "aliases:   $_\n" for split ' ', $aliases;
print "address:   ", inet_ntoa($_), "\n" for @addrs;

By-name interface via the Net::hostent override — accessor methods instead of positional unpacking:

use Net::hostent;
use Socket;
my $h = gethostbyaddr(inet_aton("127.0.0.1"), AF_INET);
print $h->name, "\n" if $h;

Edge cases#

  • ADDR is a packed binary string, not a dotted-quad. Passing "127.0.0.1" directly does not work — Perl will call the resolver with nine raw bytes and get nothing useful back. Always go through Socket::inet_aton, Socket::inet_pton, or an equivalent packer first.

  • ADDRTYPE must match the address width. AF_INET wants a four-byte ADDR; AF_INET6 wants sixteen. A mismatch either returns undef or, on some platforms, reads past the buffer. Use the constant from Socket, not a hand-typed integer.

  • Check for undef on the scalar form. A missing PTR record returns undef, not an empty string. Many addresses on the public internet have no reverse mapping at all.

  • @addrs may not include the address you queried. The resolver returns the full record for the canonical host, which may contain additional addresses that happen to share the hostname.

  • Scalar context runs the full resolver call anyway. The C routine always populates the whole hostent; Perl just discards the list. There is no performance advantage to the scalar form beyond clearer code.

  • Reverse of a forward lookup is not guaranteed to round-trip. gethostbyaddr(gethostbyname($h), AF_INET) may return a different name from $h — reverse DNS maps to the canonical hostname, which often differs from the alias the forward query used.

  • IPv6 support is platform-dependent. Not every libc’s gethostbyaddr(3) handles AF_INET6 cleanly. For portable dual-stack reverse resolution use Socket::getnameinfo.

  • Thread safety. The underlying C routine keeps per-process static state for the host cursor. Concurrent calls from multiple threads may interleave results. Scripts that need thread-safe reverse resolution should use Socket::getnameinfo.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • gethostbyname — the forward lookup: hostname → packed address

  • gethostent — iterate every entry in the host database instead of looking up one address

  • sethostent — rewind the host iterator and control whether the file stays open across lookups

  • Socket::inet_aton — build the packed ADDR argument from a dotted-quad string

  • Socket::inet_ntoa — render a packed address from @addrs back to dotted-quad form

  • Socket::getnameinfo — modern, protocol-agnostic reverse resolver that handles IPv6 and is thread-safe