Bug #340899 - Validate getaddrinfo() results.
authorZac Medico <zmedico@gentoo.org>
Thu, 14 Oct 2010 02:30:40 +0000 (19:30 -0700)
committerZac Medico <zmedico@gentoo.org>
Thu, 14 Oct 2010 03:39:29 +0000 (20:39 -0700)
pym/_emerge/actions.py
pym/_emerge/sync/getaddrinfo_validate.py [new file with mode: 0644]

index 83b7bb9f50951ca615f6dcee073c8520e62840f3..0ac7e3de5d485dbe1d7ee5c15f429b0879383e7e 100644 (file)
@@ -59,6 +59,7 @@ from _emerge.Scheduler import Scheduler
 from _emerge.search import search
 from _emerge.SetArg import SetArg
 from _emerge.show_invalid_depstring_notice import show_invalid_depstring_notice
+from _emerge.sync.getaddrinfo_validate import getaddrinfo_validate
 from _emerge.sync.old_tree_timestamp import old_tree_timestamp_warn
 from _emerge.unmerge import unmerge
 from _emerge.UnmergeDepPriority import UnmergeDepPriority
@@ -2086,34 +2087,46 @@ def action_sync(settings, trees, mtimedb, myopts, myaction):
                        ("-6" in all_rsync_opts or "--ipv6" in all_rsync_opts):
                        family = socket.AF_INET6
 
+               addrinfos = None
                uris = []
 
                try:
-                       addrinfos = socket.getaddrinfo(hostname, None,
-                               family, socket.SOCK_STREAM)
+                       addrinfos = getaddrinfo_validate(
+                               socket.getaddrinfo(hostname, None,
+                               family, socket.SOCK_STREAM))
                except socket.error as e:
-                       writemsg("!!! getaddrinfo failed for '%s': %s\n" % (hostname, e), noiselevel=-1)
+                       writemsg_level(
+                               "!!! getaddrinfo failed for '%s': %s\n" % (hostname, e),
+                               noiselevel=-1, level=logging.ERROR)
+
+               if not addrinfos:
                        # With some configurations we need to use the plain hostname
                        # rather than try to resolve the ip addresses (bug #340817).
                        uris.append(syncuri)
                else:
+
+                       AF_INET = socket.AF_INET
+                       AF_INET6 = None
+                       if socket.has_ipv6:
+                               AF_INET6 = socket.AF_INET6
+
                        ips_v4 = []
                        ips_v6 = []
 
                        for addrinfo in addrinfos:
-                               if socket.has_ipv6 and addrinfo[0] == socket.AF_INET6:
+                               if addrinfo[0] == AF_INET:
+                                       ips_v4.append("%s" % addrinfo[4][0])
+                               elif AF_INET6 is not None and addrinfo[0] == AF_INET6:
                                        # IPv6 addresses need to be enclosed in square brackets
                                        ips_v6.append("[%s]" % addrinfo[4][0])
-                               else:
-                                       ips_v4.append(addrinfo[4][0])
 
                        random.shuffle(ips_v4)
                        random.shuffle(ips_v6)
 
                        # Give priority to the address family that
                        # getaddrinfo() returned first.
-                       if socket.has_ipv6 and addrinfos and \
-                               addrinfos[0][0] == socket.AF_INET6:
+                       if AF_INET6 is not None and addrinfos and \
+                               addrinfos[0][0] == AF_INET6:
                                ips = ips_v6 + ips_v4
                        else:
                                ips = ips_v4 + ips_v6
diff --git a/pym/_emerge/sync/getaddrinfo_validate.py b/pym/_emerge/sync/getaddrinfo_validate.py
new file mode 100644 (file)
index 0000000..5e6009c
--- /dev/null
@@ -0,0 +1,29 @@
+# Copyright 2010 Gentoo Foundation
+# Distributed under the terms of the GNU General Public License v2
+
+import sys
+
+if sys.hexversion >= 0x3000000:
+       basestring = str
+
+def getaddrinfo_validate(addrinfos):
+       """
+       Validate structures returned from getaddrinfo(),
+       since they may be corrupt, especially when python
+       has IPv6 support disabled (bug #340899).
+       """
+       valid_addrinfos = []
+       for addrinfo in addrinfos:
+               try:
+                       if len(addrinfo) != 5:
+                               continue
+                       if len(addrinfo[4]) < 2:
+                               continue
+                       if not isinstance(addrinfo[4][0], basestring):
+                               continue
+               except TypeError:
+                       continue
+
+               valid_addrinfos.append(addrinfo)
+
+       return valid_addrinfos