From 1a272fd276fd5ab16506b205fcc75ba581873bc6 Mon Sep 17 00:00:00 2001 From: Lance Stout Date: Thu, 9 Feb 2012 21:28:28 -0800 Subject: Add support for querying and connecting to IPv6 addresses. Tested using servers provided by Florian Jensen (flosoft.biz) during the 2012 FOSDEM XMPP Summit. Fixes issue #94. --- sleekxmpp/clientxmpp.py | 4 ++- sleekxmpp/xmlstream/xmlstream.py | 54 +++++++++++++++++++++++++++++++++++----- 2 files changed, 51 insertions(+), 7 deletions(-) (limited to 'sleekxmpp') diff --git a/sleekxmpp/clientxmpp.py b/sleekxmpp/clientxmpp.py index a836cbd9..d2a6bfee 100644 --- a/sleekxmpp/clientxmpp.py +++ b/sleekxmpp/clientxmpp.py @@ -166,8 +166,10 @@ class ClientXMPP(BaseXMPP): try: record = "_xmpp-client._tcp.%s" % domain answers = [] + log.debug("Querying SRV records for %s" % domain) for answer in dns.resolver.query(record, dns.rdatatype.SRV): address = (answer.target.to_text()[:-1], answer.port) + log.debug("Found SRV record: %s", address) answers.append((address, answer.priority, answer.weight)) except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): log.warning("No SRV records for %s", domain) @@ -179,7 +181,7 @@ class ClientXMPP(BaseXMPP): return answers else: log.warning("dnspython is not installed -- " + \ - "relying on OS A record resolution") + "relying on OS A/AAAA record resolution") return [((domain, port), 0, 0)] def register_feature(self, name, handler, restart=False, order=5000): diff --git a/sleekxmpp/xmlstream/xmlstream.py b/sleekxmpp/xmlstream/xmlstream.py index 3a2cafc4..fe8f1bf3 100644 --- a/sleekxmpp/xmlstream/xmlstream.py +++ b/sleekxmpp/xmlstream/xmlstream.py @@ -397,7 +397,25 @@ class XMLStream(object): if self.default_domain: self.address = self.pick_dns_answer(self.default_domain, self.address[1]) - self.socket = self.socket_class(Socket.AF_INET, Socket.SOCK_STREAM) + + try: + # Look for IPv6 addresses, in addition to IPv4 + for res in Socket.getaddrinfo(self.address[0], + int(self.address[1]), + 0, + Socket.SOCK_STREAM): + log.debug("Trying: %s", res[-1]) + af, sock_type, proto, canonical, sock_addr = res + try: + self.socket = self.socket_class(af, sock_type, proto) + break + except Socket.error: + log.debug("Could not open IPv%s socket." % proto) + except Socket.gaierror: + log.warning("Socket could not be opened, wrong IP versions.") + self.stop.set() + return False + self.configure_socket() if self.reconnect_delay is None: @@ -839,20 +857,44 @@ class XMLStream(object): resolver = dns.resolver.get_default_resolver() self.configure_dns(resolver, domain=domain, port=port) + v4_answers = [] + v6_answers = [] + answers = [] + + try: + log.debug("Querying A records for %s" % domain) + v4_answers = resolver.query(domain, dns.rdatatype.A) + except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): + log.warning("No A records for %s", domain) + v4_answers = [((domain, port), 0, 0)] + except dns.exception.Timeout: + log.warning("DNS resolution timed out " + \ + "for A record of %s", domain) + v4_answers = [((domain, port), 0, 0)] + else: + for ans in v4_answers: + log.debug("Found A record: %s", ans[0]) + answers.append(((ans.address, port), 0, 0)) + try: - answers = resolver.query(domain, dns.rdatatype.A) + log.debug("Querying AAAA records for %s" % domain) + v6_answers = resolver.query(domain, dns.rdatatype.AAAA) except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer): log.warning("No A records for %s", domain) - return [((domain, port), 0, 0)] + v6_answers = [((domain, port), 0, 0)] except dns.exception.Timeout: log.warning("DNS resolution timed out " + \ "for A record of %s", domain) - return [((domain, port), 0, 0)] + v6_answers = [((domain, port), 0, 0)] else: - return [((ans.address, port), 0, 0) for ans in answers] + for ans in v6_answers: + log.debug("Found AAAA record: %s", ans[0]) + answers.append(((ans.address, port), 0, 0)) + + return answers else: log.warning("dnspython is not installed -- " + \ - "relying on OS A record resolution") + "relying on OS A/AAAA record resolution") self.configure_dns(None, domain=domain, port=port) return [((domain, port), 0, 0)] -- cgit v1.2.3