From 850005499bd92c5b9b0027f944fcd33633c8db46 Mon Sep 17 00:00:00 2001
From: Noriko Hosoi <nhosoi@totoro.usersys.redhat.com>
Date: Tue, 27 Mar 2012 16:15:50 -0700
Subject: [PATCH] Trac Ticket #46 - (take 3) setup-ds-admin.pl does not like
 ipv6 only hostnames

https://fedorahosted.org/389/ticket/46

Fix Description:
Perl functions (gethostbyname, gethostbyaddr) do not support IPv6
addresses.  This patch addes the IPv6 support if an IPv6 enabled
socket module is available.  If Socket::addrinfo subsystem is
found, use getaddrinfo and getnameinfo from the module. If not
and if Socket6 module is available, the module is used.  If both
are not found on the system, the existing non-IPv6 methods are
called.
---
 ldap/admin/src/scripts/DSUtil.pm.in |  107 +++++++++++++++++++++++++++--------
 1 files changed, 84 insertions(+), 23 deletions(-)

diff --git a/ldap/admin/src/scripts/DSUtil.pm.in b/ldap/admin/src/scripts/DSUtil.pm.in
index 9e4b322..a3a8abf 100644
--- a/ldap/admin/src/scripts/DSUtil.pm.in
+++ b/ldap/admin/src/scripts/DSUtil.pm.in
@@ -59,7 +59,16 @@ require Exporter;
 use strict;
 
 use Socket;
-use Socket6 qw( getaddrinfo getnameinfo unpack_sockaddr_in6 );
+BEGIN {
+    if (eval {require Socket::addrinfo; 1}) {
+        import Socket qw (:addrinfo inet_ntoa 
+                          unpack_sockaddr_in unpack_sockaddr_in6 
+                          AF_INET INADDR_ANY 
+                          PF_INET SO_REUSEADDR SOCK_STREAM SOL_SOCKET);
+    } elsif (eval {require Socket6; 1}) {
+        import Socket6 qw (getaddrinfo getnameinfo unpack_sockaddr_in6);
+    }
+}
 use NetAddr::IP::Util qw( ipv6_n2x );
 
 use File::Temp qw(tempfile tempdir);
@@ -210,35 +219,87 @@ sub checkHostname {
     }
 
     # see if we can resolve the hostname (IPv6 supported)
-    my @aires = getaddrinfo( $hn, "ldap", AF_UNSPEC, SOCK_STREAM );
-    if (scalar(@aires) < 5) {
-        return $res->getText('warning_no_such_hostname', $hn);
-    }
     my $found = 0;
     my @hostip = ();
-    my $ailen = scalar(@aires);
-    while ( $ailen >= 5 ) {
-        debug(1, "found for hostname $hn\n");
-        my ($family, $socktype, $proto, $saddr, $canonname, @aires) = @aires;
-        $ailen = scalar(@aires);
-        my $ip;
-        if ($family == AF_INET) {
-            my ( $port, $ipaddr ) = unpack_sockaddr_in( $saddr );
-            $ip = inet_ntoa($ipaddr);
-        } else {
-            my ( $port, $ipaddr ) = unpack_sockaddr_in6( $saddr );
-            $ip = ipv6_n2x($ipaddr);
+    if (eval {require Socket::addrinfo; 1}) {
+        my %hints = (socktype => SOCK_STREAM);
+        my ($err, @aires) = getaddrinfo($hn, "ldap", \%hints);
+        if ($err) {
+            return $res->getText('warning_no_such_hostname', $hn);
+        }
+        while (my $ai = shift @aires) {
+            debug(1, "found for hostname $hn\n");
+            my $ip;
+            if ($ai->{family} == AF_INET) {
+                my ( $port, $ipaddr ) = unpack_sockaddr_in( $ai->{addr} );
+                $ip = inet_ntoa($ipaddr);
+            } else {
+                my ( $port, $ipaddr ) = unpack_sockaddr_in6( $ai->{addr} );
+                $ip = ipv6_n2x($ipaddr);
+            }
+            debug(1, "ipaddr=", $ip, "\n");
+            # see if reverse resolution works
+            my ($err, $hn2, $service) = getnameinfo($ai->{addr});
+            if (!$err) {
+                push @hostip, [$hn2, $ip];
+                if (lc($hn) eq lc($hn2)) {
+                    $found = 1;
+                    last;
+                }
+            }
+        }
+    } elsif (eval {require Socket6; 1}) {
+        my @aires = getaddrinfo($hn, "ldap", AF_UNSPEC, SOCK_STREAM);
+        if (scalar(@aires) < 5) {
+            return $res->getText('warning_no_such_hostname', $hn);
+        }
+        my $ailen = scalar(@aires);
+        while ($ailen >= 5) {
+            debug(1, "found for hostname $hn\n");
+            my ($family, $socktype, $proto, $saddr, $canonname, @aires) = @aires;
+            $ailen = scalar(@aires);
+            my $ip;
+            if ($family == AF_INET) {
+                my ($port, $ipaddr) = unpack_sockaddr_in($saddr);
+                $ip = inet_ntoa($ipaddr);
+            } else {
+                my ($port, $ipaddr) = unpack_sockaddr_in6($saddr);
+                $ip = ipv6_n2x($ipaddr);
+            }
+            debug(1, "ipaddr=", $ip, "\n");
+            # see if reverse resolution works
+            my ($hn2, $service) = getnameinfo($saddr);
+            if (!$hn2) {
+                push @hostip, [$hn2, $ip];
+                if (lc($hn) eq lc($hn2)) {
+                    $found = 1;
+                }
+            }
         }
-        debug(1, "ipaddr=", $ip, "\n");
-        # see if reverse resolution works
-        my ( $hn2, $service ) = getnameinfo( $saddr );
-        if (!$hn2) {
+    } else {
+        # see if we can resolve the hostname
+        my ($name, $aliases, $addrtype, $length, @addrs) = gethostbyname($hn);
+        if (!$name) {
+            if ($res) {
+                return $res->getText('warning_no_such_hostname', $hn);
+            } else {
+                return "Warning: could not resolve hostname $hn\n";
+            }
+        }
+        debug(1, "found for hostname $hn: name=$name\n");
+        debug(1, "aliases=$aliases\n");
+        debug(1, "addrtype=$addrtype\n");
+         # see if reverse resolution works
+        foreach my $ii (@addrs) {
+            my $hn2 = gethostbyaddr($ii, $addrtype);
+            my $ip = join('.', unpack('C4', $ii));
+            debug(1, "\thost=$hn2 ip=$ip\n");
             push @hostip, [$hn2, $ip];
             if (lc($hn) eq lc($hn2)) {
                 $found = 1;
                 last;
-            }
-        }
+            } 
+        } 
     }
 
     if (!$found) {
-- 
1.7.7.6

