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 © 2002 O'Reilly & Associates. All rights reserved.