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
>From 4b85251c303e8519939b702254ee0def932f8ed6 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 --- ipapython/nsslib.py | 89 +++++++++++++++++++++++++++++++++++++++++--------- 1 files changed, 73 insertions(+), 16 deletions(-) diff --git a/ipapython/nsslib.py b/ipapython/nsslib.py index 129f1a0..7abbcf0 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,65 @@ 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 _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: + net_addr = io.NetworkAddress(host, port, family) + except ValueError, e: + raise NSPRError(error.PR_ADDRESS_NOT_SUPPORTED_ERROR, e.message) + logging.debug("connect: %s", net_addr) + self.sock.connect(net_addr, family) + + def _create_socket(self): + self.sock = io.Socket(family=self.family) + + 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") @@ -130,10 +186,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) @@ -142,7 +200,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 @@ -156,11 +215,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): """ @@ -206,20 +261,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.3.5
_______________________________________________ Freeipa-devel mailing list Freeipa-devel@redhat.com https://www.redhat.com/mailman/listinfo/freeipa-devel