Network info

gethostent#

Fetch the next entry from the host database.

gethostent walks the host database — on traditional Unix systems the /etc/hosts file, on modern systems whatever NSS source is configured — returning one record per call until the database is exhausted. Use it when you want to enumerate every known host, not when you want to resolve a single name: gethostbyname is the right tool for a targeted lookup.

The iteration cursor is shared with sethostent (which rewinds it) and endhostent (which closes it). Between those two calls gethostent yields each record in order, then returns the empty list (or undef in scalar context) once the end of the database is reached.

Synopsis#

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

What you get back#

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

  • $name — the canonical hostname for this entry.

  • $aliases — a space-separated string of alternate names.

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

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

  • @addrs — every address recorded for this host, each a packed binary string of $length bytes.

At end-of-database the return is the empty list. A distinction worth keeping in mind: the upstream perlfunc note that a missing entry may return “a single meaningless true value” applies to the by-name and by-address lookups, not to gethostent — iteration past the end is a clean empty list.

Scalar context — the canonical $name only, or undef at end-of-database. Use list context whenever you need anything beyond the name; reconstructing the other fields is not possible after the fact.

Convert a packed address from @addrs with Socket::inet_ntoa for IPv4 or unpack directly:

use Socket;
print inet_ntoa($addrs[0]), "\n";

Global state it touches#

  • The host database cursor, shared with sethostent, endhostent, gethostbyname, and gethostbyaddr. A by-name or by-address lookup may reset or invalidate a cursor left mid-iteration by gethostent; don’t interleave the two styles without a fresh sethostent between them.

  • $? — set to the C h_errno value on failure, where the platform exposes it. A plain end-of-database is not a failure and leaves $? alone.

  • $!gethostent is a database iterator, not a syscall wrapper in the open/read sense. DNS and NSS errors surface through h_errno (via $?), not through $!.

Examples#

Enumerate every host in the database:

use Socket;
sethostent(1);
while (my ($name, $aliases, $type, $len, @addrs) = gethostent) {
    my @dotted = map { inet_ntoa($_) } @addrs;
    print "$name  @dotted\n";
}
endhostent;

Scalar context — list just the canonical names:

sethostent(0);
while (defined(my $name = gethostent)) {
    print "$name\n";
}
endhostent;

Build a name-to-address hash in one pass, then look up entries locally without further DNS calls:

use Socket;
my %ip_of;
sethostent(1);
while (my ($name, $aliases, undef, undef, @addrs) = gethostent) {
    next unless @addrs;
    $ip_of{$name} = inet_ntoa($addrs[0]);
    $ip_of{$_}    = inet_ntoa($addrs[0]) for split ' ', $aliases;
}
endhostent;

print $ip_of{"localhost"} // "not in hosts DB", "\n";

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

use Net::hostent;
while (my $h = gethostent) {
    printf "%-30s %s\n", $h->name, join(",", @{$h->aliases});
}

Edge cases#

  • No implicit rewind. gethostent does not open or rewind the database on its own. First call after program start works because the C library lazily opens the database, but once the end is reached further calls keep returning end-of-database until a sethostent rewinds the cursor. Always pair enumeration with an explicit sethostent / endhostent.

  • STAYOPEN argument to sethostent. Passing a true value asks the library to keep the database file open across lookups, which matters for NSS sources that otherwise reconnect on every call. Passing 0 permits the library to close and reopen between calls.

  • End-of-database is the empty list, not undef. In list context the loop condition while (my @r = gethostent) works because the empty list is false. In scalar context use while (defined(my $name = gethostent)) — a hostname of "0" is theoretically valid and would falsely terminate a truthiness-based loop.

  • @addrs may be empty even for a returned record on some NSS backends. Guard the address-unpacking step:

    next unless @addrs;
    
  • Aliases are one scalar, not a list. $aliases is a single space-separated string. Split on whitespace if you want a list.

  • NSS source mix. On glibc-based systems the hosts database may draw from /etc/hosts, DNS, mDNS, and other NSS modules depending on nsswitch.conf. DNS-backed NSS modules typically do not enumerate — gethostent against a DNS-only hosts database returns the empty list immediately. On most real deployments only the files source contributes entries to iteration.

  • Interleaving with by-name / by-address lookups. A call to gethostbyname or gethostbyaddr can reset the shared cursor. Finish the iteration first, or restart it with sethostent after the lookup.

  • Thread safety. The underlying C routine keeps per-process static state for the iteration cursor. Concurrent calls from multiple threads interleave results unpredictably. Confine enumeration to a single thread.

Differences from upstream#

Fully compatible with upstream Perl 5.42.

See also#

  • sethostent — rewind the iterator and control whether the database stays open across calls

  • endhostent — close the iterator and release the database handle

  • gethostbyname — targeted lookup by name instead of full enumeration

  • gethostbyaddr — targeted reverse lookup by packed address

  • getnetent — same iteration pattern for the networks database

  • Socket::inet_ntoa — turn a packed address from @addrs into a dotted-quad string