Beefy Boxes and Bandwidth Generously Provided by pair Networks Bob
The stupid question is the question not asked
 
PerlMonks  

IPv6 Name Resolution

by VinsWorldcom (Priest)
on Nov 15, 2011 at 15:26 UTC ( #938198=perlquestion: print w/ replies, xml ) Need Help??
VinsWorldcom has asked for the wisdom of the Perl Monks concerning the following question:

I've done some research and come to the conclusion that I can't do name lookup for IPv4 *and* IPv6 addresses (address family independent) with the current version of Perl on my platform. This question is basically to confirm or set me straight.

Windows 7 x64, Strawberry Perl 5.12.3

VinsWorldcom@C:\Users\VinsWorldcom> ver Microsoft Windows [Version 6.1.7601] VinsWorldcom@C:\Users\VinsWorldcom> perl -v This is perl 5, version 12, subversion 3 (v5.12.3) built for MSWin32-x +64-multi-thread [...]

Looking at http://www.perl.org/about/whitepapers/perl-ipv6.html, I successfully built a simple Perl web-server that listens on v4 *OR* v6 (not both at the same time) using IO::Socket::INET and IO::Socket::INET6 (also with IO::Socket::IP and some additional logic). All that worked fine using just IPv4/v6 addresses. I want to use names.

I have IPv6 enabled with a Hurricane Electric tunnel and can successfully ping ipv6.google.com (an IPv6 only site). In this case, I'm just looking to do name resolution.

With dig.exe on Windows:

VinsWorldcom@C:\Users\VinsWorldcom> dig -v DiG 9.8.1 VinsWorldcom@C:\Users\VinsWorldcom> dig ipv6.google.com aaaa @8.8.8.8 ; <<>> DiG 9.8.1 <<>> ipv6.google.com aaaa @8.8.8.8 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 7089 ;; flags: qr rd ra; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;ipv6.google.com. IN AAAA ;; ANSWER SECTION: ipv6.google.com. 86399 IN CNAME ipv6.l.google.com. ipv6.l.google.com. 299 IN AAAA 2001:4860:800f::63 ;; Query time: 69 msec ;; SERVER: 8.8.8.8#53(8.8.8.8) ;; WHEN: Tue Nov 15 10:05:14 2011 ;; MSG SIZE rcvd: 82

I put together a simple script to test name lookup the 'old' way (gethostbyname() and inet_ntoa()) and the 'new' way (getaddrinfo() and inet_ntop()). I also successfully installed the Socket6 and Socket::GetAddrInfo modules with Strawberry.

#!/usr/bin/perl use strict; use warnings; use Getopt::Long qw(:config no_ignore_case); use Pod::Usage; use Socket; use Socket6; use Socket::GetAddrInfo qw(getaddrinfo); my %opt; GetOptions( 'new!' => \$opt{new}, 'old!' => \$opt{old} ) or pod2usage(-verbose => 0); if (!@ARGV) { pod2usage(-verbose => 0, -message => "$0: host required\n") } if ((!defined($opt{new})) && (!defined($opt{old}))) { $opt{new} = $opt{old} = 1 } if ($opt{old}) { my $gethost = gethostbyname($ARGV[0]); my $host = inet_ntoa((gethostbyname($ARGV[0]))[4]); # print "OLD: gethostbyname() = $gethost\n"; print "OLD: inet_ntoa() Address = $host\n"; } if ($opt{new}) { my ($err, @getaddr) = getaddrinfo($ARGV[0], 0); if (!@getaddr) { print "$0: $err\n"; exit } my $host = inet_ntop(AF_INET6, (getaddrinfo($ARGV[0], 0))[1]->{add +r}); # printf "NEW: getaddrinfo() = %s\n", $getaddr[1]->{addr}; print "NEW: inet_ntop() Address = $host\n"; } __END__ =head1 SYNOPSIS program [--old|--new] IP[v6]_address | hostname

I believe the coding is correct (albeit not elegent). It just errors on the IPv6 host look ups and incorrectly does the IPv4 lookups the 'new' way.

VinsWorldcom@C:\Users\VinsWorldcom\tmp> v4v6Lookup.pl www.google.com OLD: inet_ntoa() Address = 72.14.204.105 NEW: inet_ntop() Address = 200:0:480e:cc69:: VinsWorldcom@C:\Users\VinsWorldcom\tmp> v4v6Lookup.pl 72.14.204.105 OLD: inet_ntoa() Address = 72.14.204.105 NEW: inet_ntop() Address = 200:0:480e:cc69::

Both addresses should be the v4 address. The inet_ntop function is converting to IPv6 even though it shouldn't - 72 = 48, 14 = 0e, 204 = cc, 105 = 69

With IPv6 name lookups, it doesn't work at all. I expect the runs without the '--new' switch to fail as gethostbyname() and inet_ntoa() don't support IPv6, but the runs with the '--new' switch also fail.

VinsWorldcom@C:\Users\VinsWorldcom\tmp> v4v6Lookup.pl ipv6.google.com Usage: Socket::inet_ntoa(ip_address_sv) at C:\Users\VinsWorldcom\tmp\v +4v6Lookup.pl line 29. VinsWorldcom@C:\Users\VinsWorldcom\tmp> v4v6Lookup.pl --new ipv6.googl +e.com C:\Users\VinsWorldcom\tmp\v4v6Lookup.pl: The requested name is valid, +but no data of the requested type was found. VinsWorldcom@C:\Users\VinsWorldcom\tmp> v4v6Lookup.pl 2001:4860:800f:: +63 Usage: Socket::inet_ntoa(ip_address_sv) at C:\Users\VinsWorldcom\tmp\v +4v6Lookup.pl line 29. VinsWorldcom@C:\Users\VinsWorldcom\tmp> v4v6Lookup.pl --new 2001:4860: +800f::63 Bad arg length for Socket6::inet_ntop, length is 28, should be 16 at C +:\Users\VinsWorldcom\tmp\v4v6Lookup.pl line 40.

As you can see, the gethostbyname() and inet_ntoa() worked well for host or IP resolution to an IP address in the IPv4 address family - and that's how I've always done it. Trying to extend that to let my scripts accommodate IPv4 and IPv6 is proving problematic. According to the above web link, Perl 5.14 will fix this and Strawberry just released 5.14 - I haven't tried that yet.

UPDATE:

Found a way to get it to work - less than ideal though:

#!/usr/bin/perl use strict; use warnings; use Getopt::Long qw(:config no_ignore_case); use Pod::Usage; use Socket; use Socket6; # Windows DOES support getaddrinfo and inet_ntop/pton functions # although it may *seem* like it doesn't from Strawberry's GCC # Don't need Socket6::GetAddrInfo my %opt; GetOptions( 'new!' => \$opt{new}, 'old!' => \$opt{old} ) or pod2usage(-verbose => 0); if (!@ARGV) { pod2usage(-verbose => 0, -message => "$0: host required\n") } if ((!defined($opt{new})) && (!defined($opt{old}))) { $opt{new} = $opt{old} = 1 } if ($opt{old}) { my $gethost = gethostbyname($ARGV[0]); my $host = inet_ntoa((gethostbyname($ARGV[0]))[4]); # print "OLD: gethostbyname() = $gethost\n"; print "OLD: inet_ntoa() Address = $host\n"; } if ($opt{new}) { my @getaddr = getaddrinfo($ARGV[0], 0); # IP[v6] address shows up at different locations in the [3] elemen +t # use substr to 'find' it - awful! my $host = inet_ntop($getaddr[0], substr($getaddr[3], (($getaddr[0 +] == AF_INET) ? 4 : 8), (($getaddr[0] == AF_INET) ? 4 : 16))); # printf "NEW: getaddrinfo() = %s\n", $getaddr[3]; print "NEW: inet_ntop() Address = $host\n"; } __END__ =head1 SYNOPSIS program [--old|--new] IP[v6]_address | hostname

And the output:

VinsWorldcom@C:\Users\VinsWorldcom\tmp> v4v6Lookup.pl --new www.google +.com NEW: inet_ntop() Address = 72.14.204.147 VinsWorldcom@C:\Users\VinsWorldcom\tmp> v4v6Lookup.pl --new ipv6.googl +e.com NEW: inet_ntop() Address = 2001:4860:800f::93

UPDATE

Realized getaddrinfo returns 5 element array, number 3 is the address *STRUCTURE* - not the address itself. Need the following code to massage out the IPv4/v6 address:

if ($opt{new}) { my @getaddr = getaddrinfo($ARGV[0], 0); my $address; # Get the pointer to the address itself, different fields in IPv4 +and IPv6 if ($getaddr[0] == AF_INET) { $address = (unpack_sockaddr_in($getaddr[3]))[1] } else { $address = (unpack_sockaddr_in6($getaddr[3]))[1] } my $host = inet_ntop($getaddr[0], $address); # printf "NEW: getaddrinfo() = %s\n", $getaddr[3]; print "NEW: inet_ntop() Address = $host\n"; }

Comment on IPv6 Name Resolution
Select or Download Code
Re: IPv6 Name Resolution
by Anonymous Monk on Nov 22, 2011 at 16:00 UTC
    You almost certainly don't want to be using Socket6 for this. Core's Socket has had getaddrinfo for quite some time now, and I keep improving it. Also, your uses of inet_ntop are suspect. You shouldn't need to use those. This is what getnameinfo is for.
    use Socket qw( getaddrinfo getnameinfo ); my ( $err, @addrs ) = getaddrinfo( $ARGV[0], 0 ); die $err if $err; my ( $err, $hostname ) = getnameinfo( $addrs[0]->{addr} ); die $err if $err;
    If you dislike that error-in-first-result API style, try Socket::GetAddrInfo::Strict:
    use Socket::GetAddrInfo::Strict qw( getaddrinfo, getnameinfo ); my @addrs = getaddrinfo( $ARGV[0], 0 ); my ( $hostname ) = getnameinfo( $addrs[0]->{addr} );
    You shouldn't ever need to use inet_ntop, inet_pton, gethostby*, or any of those other legacies. Any time you want to turn something human-readable into something binary, use getaddrinfo. Any time you want to turn something binary into something human-readable, use getnameinfo. Simple. :)

      It seemed to good to be true and it was:

      VinsWorldcom@C:\Users\VinsWorldcom\tmp> cat test.pl use Socket qw( getaddrinfo getnameinfo ); my ( $err, @addrs ) = getaddrinfo( $ARGV[0], 0 ); die $err if $err; my ( $err, $hostname ) = getnameinfo( $addrs[0]->{addr} ); die $err if $err; VinsWorldcom@C:\Users\VinsWorldcom\tmp> test.pl "getaddrinfo" is not exported by the Socket module "getnameinfo" is not exported by the Socket module Can't continue after import errors at C:\Users\VinsWorldcom\tmp\test.p +l line 1 BEGIN failed--compilation aborted at C:\Users\VinsWorldcom\tmp\test.pl + line 1. VinsWorldcom@C:\Users\VinsWorldcom\tmp> perldoc Socket | grep getnamei +nfo VinsWorldcom@C:\Users\VinsWorldcom\tmp> perldoc Socket | grep getaddri +nfo VinsWorldcom@C:\Users\VinsWorldcom\tmp> perl -MSocket -e "print $Socke +t::VERSION" 1.87_01

      While the latest version of Perl Socket (5.14.x) seems to support getXXXXinfo functions; remember, my original query asked for Windows 7, Strawberry Perl 5.12.3.

        In that case, simply install Socket::GetAddrInfo; it's backed by the same XS and PP code that was copied into core Perl at 5.14.0.

        Also note that I'm in the process of making Socket dual-life, so you can install the current development version of that

        • http://search.cpan.org/~pevans/Socket-1.94_07/
        This is known to work back at least as far as Perl 5.10.0, and hopefully soon this will reach a real 1.95 release. This will mean your code continues to work unchanged on later Perls too.

        BRILLIANT! Thanks for your work on this. I'm doing quite a lot of IPv6 testing now as I'm seeing it pop up here and there. I'd like to be prepared knowing not just the networking aspect, but also the application development (C and Perl at least) angles to retrofitting IPv6 capabilities into existing applications.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://938198]
Approved by sundialsvc4
Front-paged by toolic
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (8)
As of 2014-04-17 09:42 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    April first is:







    Results (443 votes), past polls