On Thu, Feb 17, 2011 at 08:25:37PM +0100, Jakub Hrozek wrote: > On Wed, Feb 09, 2011 at 10:23:27AM +0100, Jan Zelený wrote: > > Jakub Hrozek <jhro...@redhat.com> wrote: > > > On Thu, Feb 03, 2011 at 02:23:11PM +0100, Jan Zelený wrote: > > > > Jakub Hrozek <jhro...@redhat.com> wrote: > > > > > Hi, > > > > > > > > > > attached is a patch to nsslib.py that changes its semantics so > > > > > it is able to work with different address families. It is the last > > > > > piece of IPv6 support. > > > > > > > > > > Aside from the hunks in the patch, I still need to set Requires: in > > > > > the > > > > > patch (don't know the exact version yet). Also, the attached patch > > > > > always tries IPv4 first and only falls back to IPv6. I think there > > > > > should be a config option that tells IPA to prefer one of the address > > > > > families or use it exclusively for performance reasons. > > > > > > > > > > Please note that the patch requires the latest changes to python-nss > > > > > in order to work correctly. Since John is still working on python-nss > > > > > packages, this patch should be treated as a preview and not pushed > > > > > even > > > > > if it is deemed OK. At this stage, I'd like to get at least the > > > > > general > > > > > approach and code reviewed so I can fix it tomorrow. > > > > > > > > > > Thank you, > > > > > > > > > > Jakub > > > > > > > > The patch looks ok, all my questions answered off-list. Also tested with > > > > IPv4 (latest python-nss installed) and IPv6, both work fine. > > > > > > > > ACK > > > > > > > > Jan > > > > > > Thanks for the review. But attached is a new version of the patch that > > > changes the semantics a little based on what's recommended by the new > > > version of python-nss: don't construct the NetworkAddress object > > > manually, but rather resolve the hostname using the AddrInfo object and > > > then try connecting to the list of of NetworkAddress object manually. > > > > Changes consulted off-list, the patch looks good. Will do some more testing > > on > > RHEL6. Unless I find some issues, this patch is ACKed. > > > > Jan > > > > One more change - bumped the minimum required version of python-nss to > 0.11 which is in the nightly devel repo now. >
and now with the patch attached.
>From fd089113524c250c502eb2e4028affd29754dd77 Mon Sep 17 00:00:00 2001 From: Jakub Hrozek <jhro...@redhat.com> Date: Wed, 2 Feb 2011 13:57:16 +0100 Subject: [PATCH] Make nsslib IPv6 aware --- freeipa.spec.in | 5 ++- ipapython/nsslib.py | 108 +++++++++++++++++++++++++++++++++++++++++++-------- 2 files changed, 96 insertions(+), 17 deletions(-) diff --git a/freeipa.spec.in b/freeipa.spec.in index f301aa2..0e54caf 100644 --- a/freeipa.spec.in +++ b/freeipa.spec.in @@ -177,7 +177,7 @@ Requires: python-kerberos >= 1.1-3 Requires: authconfig Requires: gnupg Requires: pyOpenSSL -Requires: python-nss >= 0.9-8 +Requires: python-nss >= 0.11 Requires: python-lxml Requires: python-netaddr @@ -476,6 +476,9 @@ fi %ghost %attr(0644,root,apache) %config(noreplace) %{_sysconfdir}/ipa/default.conf %changelog +* Thu Feb 17 2011 Jakub Hrozek <jhro...@redhat.com> - 1.99-45 +- Set minimum version of python-nss to 0.11 to make sure IPv6 support is in + * Wed Feb 9 2011 Rob Crittenden <rcrit...@redhat.com> - 1.99-44 - Set minimum version of sssd to 1.5.1 diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py index fad65a3..8d77863 100644 --- a/ipapython/nsslib.py +++ b/ipapython/nsslib.py @@ -21,12 +21,14 @@ import sys import httplib import getpass +import socket import logging from nss.error import NSPRError import nss.io as io import nss.nss as nss import nss.ssl as ssl +import nss.error as error def auth_certificate_callback(sock, check_sig, is_server, certdb): cert_is_valid = False @@ -113,11 +115,84 @@ def client_auth_data_callback(ca_names, chosen_nickname, password, certdb): return False return False -class NSSConnection(httplib.HTTPConnection): +class NSSAddressFamilyFallback(object): + def __init__(self, family): + self.sock_family = family + self.family = self._get_nss_family(self.sock_family) + + def _get_nss_family(self, sock_family): + """ + Translate a family from python socket module to nss family. + """ + if sock_family in [ socket.AF_INET, socket.AF_UNSPEC ]: + return io.PR_AF_INET + elif sock_family == socket.AF_INET6: + return io.PR_AF_INET6 + else: + raise ValueError('Uknown socket family %d\n', sock_family) + + def _get_next_family(self): + if self.sock_family == socket.AF_UNSPEC and \ + self.family == io.PR_AF_INET: + return io.PR_AF_INET6 + + return None + + def _create_socket(self): + self.sock = io.Socket(family=self.family) + + def _connect_socket_family(self, host, port, family): + logging.debug("connect_socket_family: host=%s port=%s family=%s", + host, port, io.addr_family_name(family)) + try: + addr_info = [ ai for ai in io.AddrInfo(host) if ai.family == family ] + # No suitable families + if len(addr_info) == 0: + raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR, + "Cannot resolve %s using family %s" % (host, io.addr_family_name(family))) + + # Try connecting to the NetworkAddresses + for net_addr in addr_info: + net_addr.port = port + logging.debug("connecting: %s", net_addr) + try: + self.sock.connect(net_addr, family) + except Exception, e: + logging.debug("Could not connect socket to %s, error: %s, retrying..", + net_addr, str(e)) + continue + else: + return + + # Could not connect with any of NetworkAddresses + raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR, + "Could not connect to %s using any address" % host) + except ValueError, e: + raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR, e.message) + + def connect_socket(self, host, port): + try: + self._connect_socket_family(host, port, self.family) + except NSPRError, e: + if e.errno == error.PR_ADDRESS_NOT_SUPPORTED_ERROR: + next_family = self._get_next_family() + if next_family: + self.family = next_family + self._create_socket() + self._connect_socket_family(host, port, self.family) + else: + logging.debug('No next family to try..') + raise e + else: + raise e + +class NSSConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): default_port = httplib.HTTPSConnection.default_port - def __init__(self, host, port=None, strict=None, dbdir=None): + def __init__(self, host, port=None, strict=None, + dbdir=None, family=socket.AF_UNSPEC): httplib.HTTPConnection.__init__(self, host, port, strict) + NSSAddressFamilyFallback.__init__(self, family) if not dbdir: raise RuntimeError("dbdir is required") @@ -134,10 +209,12 @@ class NSSConnection(httplib.HTTPConnection): nss.nss_init(dbdir) ssl.set_domestic_policy() nss.set_password_callback(self.password_callback) + self._create_socket() + def _create_socket(self): # Create the socket here so we can do things like let the caller # override the NSS callbacks - self.sock = ssl.SSLSocket() + self.sock = ssl.SSLSocket(family=self.family) self.sock.set_ssl_option(ssl.SSL_SECURITY, True) self.sock.set_ssl_option(ssl.SSL_HANDSHAKE_AS_CLIENT, True) @@ -146,7 +223,8 @@ class NSSConnection(httplib.HTTPConnection): # Provide a callback to verify the servers certificate self.sock.set_auth_certificate_callback(auth_certificate_callback, - nss.get_default_certdb()) + nss.get_default_certdb()) + self.sock.set_hostname(self.host) def password_callback(self, slot, retry, password): if not retry and password: return password @@ -160,11 +238,7 @@ class NSSConnection(httplib.HTTPConnection): pass def connect(self): - logging.debug("connect: host=%s port=%s", self.host, self.port) - self.sock.set_hostname(self.host) - net_addr = io.NetworkAddress(self.host, self.port) - logging.debug("connect: %s", net_addr) - self.sock.connect(net_addr) + self.connect_socket(self.host, self.port) def endheaders(self, message=None): """ @@ -210,20 +284,22 @@ class NSSHTTPS(httplib.HTTP): port = None self._setup(self._connection_class(host, port, strict, dbdir=dbdir)) -class NSPRConnection(httplib.HTTPConnection): +class NSPRConnection(httplib.HTTPConnection, NSSAddressFamilyFallback): default_port = httplib.HTTPConnection.default_port - def __init__(self, host, port=None, strict=None): + def __init__(self, host, port=None, strict=None, family=socket.AF_UNSPEC): httplib.HTTPConnection.__init__(self, host, port, strict) + NSSAddressFamilyFallback.__init__(self, family) logging.debug('%s init %s', self.__class__.__name__, host) + self._create_socket() + + def _create_socket(self): + super(NSPRConnection, self)._create_socket() + self.sock.set_hostname(self.host) - self.sock = io.Socket() def connect(self): - logging.debug("connect: host=%s port=%s", self.host, self.port) - net_addr = io.NetworkAddress(self.host, self.port) - logging.debug("connect: %s", net_addr) - self.sock.connect(net_addr) + self.connect_socket(self.host, self.port) class NSPRHTTP(httplib.HTTP): _http_vsn = 11 -- 1.7.4
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel