You have a socket and want to identify the machine at the other end.
If you're only interested in the IP address of the remote machine, use:
use Socket; $other_end = getpeername(SOCKET) or die "Couldn't identify other end: $!\n"; ($port, $iaddr) = unpack_sockaddr_in($other_end); $ip_address = inet_ntoa($iaddr);
If you want its actual host name, use:
use Socket; $other_end = getpeername(SOCKET) or die "Couldn't identify other end: $!\n"; ($port, $iaddr) = unpack_sockaddr_in($other_end); $actual_ip = inet_ntoa($iaddr); $claimed_hostname = gethostbyaddr($iaddr, AF_INET); @name_lookup = gethostbyname($claimed_hostname) or die "Could not look up $claimed_hostname : $!\n"; @resolved_ips = map { inet_ntoa($_) } @name_lookup[ 4 .. $#ips_for_hostname ];
For a long time, figuring out who connected to you was considered more straightforward than it really is. The
getpeername
function returns the IP address of the remote machine in a packed binary structure (or
undef
if an error occurred). To unpack it, use
inet_ntoa
. If you want the name of the remote end, call
gethostbyaddr
to look up the name of the machine in the DNS tables, right?
Not really. That's only half the solution. Because a name lookup goes to the name's owner's DNS server and a lookup of an IP addresses goes to the address's owner's DNS server, you have to contend with the possibility that the machine that connected to you is giving incorrect names. For instance, the machine
evil.crackers.org
could belong to malevolent cyberpirates who tell their DNS server that its IP address (
1.2.3.4
) should be identified as
trusted.dod.gov
. If your program trusts
trusted.dod.gov
, a connection from
evil.crackers.org
will cause
getpeername
to return the right IP address (
1.2.3.4
), but
gethostbyaddr
will return the duplicitous name.
To avoid this problem, we take the (possibly deceitful) name returned by
get-hostbyaddr
and look it up again with
gethostbyname
. In the case of
evil.crackers.org
, the lookup of
trusted.dod.gov
will be done through
dod.gov
's DNS servers, and will return the real IP address(es) for
trusted.dod.gov
. Because many machines have more than one IP address (multihomed web servers are the obvious example), we can't use the simplified form of
gethostbyname
:
$packed_ip = gethostbyname($name) or die "Couldn't look up $name : $!\n"; $ip_address = inet_ntoa($packed_ip);
So far we've assumed we're dealing with an Internet domain application. You can also call
getpeername
on a Unix domain socket. If the other end called
bind
, you'll get the filename they bound to. If the other end
didn't
call
bind
, however,
getpeername
may return an empty string (unpacked), a packed string with oddball garbage in it, or
undef
to indicate an error, or your computer may reboot. (These possibilities are listed in descending order of probability and desirability.) This is what we in the computer business call "undefined behavior."
Even this level of paranoia and mistrust isn't enough. It's still possible for people to fake out DNS servers they don't directly control, so don't use hostnames for identification or authentication. True paranoiacs and misanthropes use cryptographically-secure methods.
The
gethostbyaddr
,
gethostbyname
, and
getpeername
in
Chapter 3
of
Programming Perl
and in
perlfunc
(1); the
inet_ntoa
in the standard Socket module; the documentation for the standard IO::Socket and Net::hostnet modules
Copyright © 2001 O'Reilly & Associates. All rights reserved.