[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Xen-devel] [PATCH] add ssl/tls support to relocation



After further investigation, I find that I didn't get relocation using
ssl/tls: the read/write to the pyOpenSSL socket.fileno() will communicate
without data encrypted.

I have add a wrapper to the read/write with the following patch.

This patch also makes pyOpenSSL an optional package.

Note on changing:
    raise XendError("can't connect: %s" % err[1])
to:
    raise XendError("can't connect: %s" % err)
in tools/python/xen/xend/XendDomain.py: 
it will avoid the following error:

[2008-05-08 14:17:28 2678] ERROR (xmlrpclib2:178) Internal error handling
xend.domain.migrate
Traceback (most recent call last):
  File "/usr/lib/python2.4/site-packages/xen/util/xmlrpclib2.py", line 131, in
_marshaled_dispatch
    response = self._dispatch(method, params)
  File "/usr/lib/python2.4/SimpleXMLRPCServer.py", line 406, in _dispatch
    return func(*params)
  File "/usr/lib/python2.4/site-packages/xen/xend/XendDomain.py", line 1335,
in domain_migrate
    raise XendError("can't connect: %s" % err[1])
IndexError: tuple index out of range

Implement reference: 
http://twistedmatrix.com/trac/browser/trunk/twisted/internet/tcp.py

Sorry for the careless.

thanks,

zhigang

Carb, Brian A wrote:
> This works on SLES10SP1 if we download a compatible python openssl rpm
> (python-openssl-0.6-17.x86_64.rpm) from opensuse.
> 
> brian carb
> unisys corporation - malvern, pa
> 
> -----Original Message-----
> From: Zhigang Wang [mailto:zhigang.x.wang@xxxxxxxxxx] 
> Sent: Friday, May 02, 2008 2:11 PM
> To: Carb, Brian A
> Cc: xen-devel
> Subject: Re: [Xen-devel] [PATCH] add ssl/tls support to relocation
> 
> Yes. I add a dependency.
> 
> maybe we can separate SSLTCPListener to a new file like (tcp-ssl.py),
> and import it when needed, just like
> tools/python/xen/xend/server/SSLXMLRPCServer.py did.
> 
> will try it later, or you can help.
> 
> thanks,
> 
> zhigang
> 
> Carb, Brian A wrote:
>> With this patch included, xend start errors: 
>>
>> # xend start
>> Traceback (most recent call last):
>>   File "/usr/sbin/xend", line 44, in ?
>>     from xen.xend.server import SrvDaemon
>>   File
>> "/home/unisys/xen-unstable.hg/dist/install/usr/lib64/python/xen/xend/s
>> er
>> ver/SrvDaemon.py", line 26, in ?
>>     import relocate
>>   File
>> "/home/unisys/xen-unstable.hg/dist/install/usr/lib64/python/xen/xend/s
>> er
>> ver/relocate.py", line 23, in ?
>>     from xen.web import protocol, tcp, unix
>>   File
>>
> "/home/unisys/xen-unstable.hg/dist/install/usr/lib64/python/xen/web/tcp.
>> py", line 25, in ?
>>     from OpenSSL import SSL
>> ImportError: No module named OpenSSL
>>
>> I guess this produces a dependency on python-openssl, but this rpm is 
>> not included in the standard SLES10 distro.
>>
>> brian carb
>> unisys corporation - malvern, pa
>>
>>
>> -----Original Message-----
>> From: xen-devel-bounces@xxxxxxxxxxxxxxxxxxx
>> [mailto:xen-devel-bounces@xxxxxxxxxxxxxxxxxxx] On Behalf Of Zhigang 
>> Wang
>> Sent: Sunday, April 27, 2008 10:50 PM
>> To: xen-devel
>> Subject: [Xen-devel] [PATCH] add ssl/tls support to relocation
>>
>> hi, this patch add ssl/tls support to relocation:
>>
>>  * SSL/TLS support is disabled by default, as other server did.
>>
>>  * If "xend-relocation-server-ssl-key-file" and
>>    "xend-relocation-server-ssl-cert-file" exist, SSL/TLS is enabled
>>    automatically.
>>
>>  * "xend-relocation-tls" is used by relocation client only.
>>
>> Signed-off-by: Zhigang Wang <zhigang.x.wang@xxxxxxxxxx>
>>
>>
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@xxxxxxxxxxxxxxxxxxx
> http://lists.xensource.com/xen-devel
Fix relocation ssl/tls support

 * Make a wrapper of read/write sock.fileno().

 * Makes pyOpenSSL an optional package.

 * Implement reference:
   http://twistedmatrix.com/trac/browser/trunk/twisted/internet/tcp.py

Signed-off-by: Zhigang Wang <zhigang.x.wang@xxxxxxxxxx>

diff -Nura xen-unstable.orig/tools/python/xen/web/connectionssl.py 
xen-unstable/tools/python/xen/web/connectionssl.py
--- xen-unstable.orig/tools/python/xen/web/connectionssl.py     1970-01-01 
08:00:00.000000000 +0800
+++ xen-unstable/tools/python/xen/web/connectionssl.py  2008-05-08 
15:39:44.000000000 +0800
@@ -0,0 +1,188 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or modify
+# it under the terms of the GNU Lesser General Public License as published by
+# the Free Software Foundation; either version 2.1 of the License, or
+# (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2005 Mike Wray <mike.wray@xxxxxx>
+# Copyright (C) 2005 XenSource Ltd.
+# Copyright (C) 2008 Oracle
+#============================================================================
+import os
+import socket
+
+from errno import EAGAIN, EINTR, EWOULDBLOCK
+from OpenSSL import SSL
+
+from connection import SocketServerConnection
+from xen.xend.XendLogging import log
+
+"""General classes to support server and client sockets, without
+specifying what kind of socket they are. There are subclasses
+for TCP and unix-domain sockets (see tcp.py and unix.py).
+
+As pyOpenSSL SSL.Connection fileno() method just retrieve the file descriptor
+number for the underlying socket, direct read/write to the file descriptor
+will result no data encrypted.
+
+recv2fd() and fd2send() are simple wrappers for functions who need direct
+read/write to a file descriptor rather than a socket like object.
+
+To use recv2fd(), you can create a pipe and start a thread to transfer all
+received data to one end of the pipe, then read from the other end:
+
+p2cread, p2cwrite = os.pipe()
+threading.Thread(target=connectionssl.recv2fd, args=(sock, p2cwrite)).start()
+os.read(p2cread, 1024)
+
+To use fd2send():
+
+p2cread, p2cwrite = os.pipe()
+threading.Thread(target=connectionssl.fd2send, args=(sock, p2cread)).start()
+os.write(p2cwrite, "data")
+
+"""
+
+BUFFER_SIZE = 1024
+
+
+class SSLSocketServerConnection(SocketServerConnection):
+    """An SSL aware accepted connection to a server.
+    """
+
+    def __init__(self, sock, protocol_class):
+        SocketServerConnection.__init__(self, sock, protocol_class)
+
+    def main(self):
+        try:
+            while True:
+                try:
+                    data = self.sock.recv(BUFFER_SIZE)
+                    if data == "":
+                        break
+                    if self.protocol.dataReceived(data):
+                        break
+                except socket.error, ex:
+                    if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+                        break
+                except (SSL.WantReadError, SSL.WantWriteError, \
+                        SSL.WantX509LookupError):
+                    # The operation did not complete; the same I/O method
+                    # should be called again.
+                    continue
+                except SSL.ZeroReturnError:
+                    # The SSL Connection has been closed.
+                    break
+                except SSL.SysCallError, (retval, desc):
+                    if ((retval == -1 and desc == "Unexpected EOF")
+                        or retval > 0):
+                        # The SSL Connection is lost.
+                        break
+                    log.debug("SSL SysCallError:%d:%s" % (retval, desc))
+                    break
+                except SSL.Error, e:
+                    # other SSL errors
+                    log.debug("SSL Error:%s" % e)
+                    break
+        finally:
+            try:
+                self.sock.close()
+            except:
+                pass
+
+def recv2fd(sock, fd):
+    try:
+        while True:
+            try:
+                data = sock.recv(BUFFER_SIZE)
+                if data == "":
+                    break
+                count = 0
+                while count < len(data):
+                    try:
+                        nbytes = os.write(fd, data[count:])
+                        count += nbytes
+                    except os.error, ex:
+                        if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+                            raise
+            except socket.error, ex:
+                if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+                    break
+            except (SSL.WantReadError, SSL.WantWriteError, \
+                    SSL.WantX509LookupError):
+                # The operation did not complete; the same I/O method
+                # should be called again.
+                continue
+            except SSL.ZeroReturnError:
+                # The SSL Connection has been closed.
+                break
+            except SSL.SysCallError, (retval, desc):
+                if ((retval == -1 and desc == "Unexpected EOF")
+                    or retval > 0):
+                    # The SSL Connection is lost.
+                    break
+                log.debug("SSL SysCallError:%d:%s" % (retval, desc))
+                break
+            except SSL.Error, e:
+                # other SSL errors
+                log.debug("SSL Error:%s" % e)
+                break
+    finally:
+        try:
+            sock.close()
+            os.close(fd)
+        except:
+            pass
+
+def fd2send(sock, fd):
+    try:
+        while True:
+            try:
+                data = os.read(fd, BUFFER_SIZE)
+                if data == "":
+                    break
+                count = 0
+                while count < len(data):
+                    try:
+                        nbytes = sock.send(data[count:])
+                        count += nbytes
+                    except socket.error, ex:
+                        if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+                            raise
+                    except (SSL.WantReadError, SSL.WantWriteError, \
+                            SSL.WantX509LookupError):
+                        # The operation did not complete; the same I/O method
+                        # should be called again.
+                        continue
+                    except SSL.ZeroReturnError:
+                        # The SSL Connection has been closed.
+                        raise
+                    except SSL.SysCallError, (retval, desc):
+                        if not (e[0] == -1 and data == ""):
+                            # errors when writing empty strings are expected
+                            # and can be ignored
+                            log.debug("SSL SysCallError:%d:%s" % (retval, 
desc))
+                            raise
+                    except SSL.Error, e:
+                        # other SSL errors
+                        log.debug("SSL Error:%s" % e)
+                        raise
+            except os.error, ex:
+                if ex.args[0] not in (EWOULDBLOCK, EAGAIN, EINTR):
+                    break
+    finally:
+        try:
+            sock.close()
+            os.close(fd)
+        except:
+            pass
+
diff -Nura xen-unstable.orig/tools/python/xen/web/tcp.py 
xen-unstable/tools/python/xen/web/tcp.py
--- xen-unstable.orig/tools/python/xen/web/tcp.py       2008-05-05 
14:17:45.000000000 +0800
+++ xen-unstable/tools/python/xen/web/tcp.py    2008-05-05 14:32:16.000000000 
+0800
@@ -22,8 +22,6 @@
 import socket
 import time
 
-from OpenSSL import SSL
-
 import connection
 
 from xen.xend.XendLogging import log
@@ -67,41 +65,3 @@
             except:
                 pass
 
-class SSLTCPListener(TCPListener):
-
-    def __init__(self, protocol_class, port, interface, hosts_allow,
-                 ssl_key_file = None, ssl_cert_file = None):
-        if not ssl_key_file or not ssl_cert_file:
-            raise ValueError("SSLXMLRPCServer requires ssl_key_file "
-                             "and ssl_cert_file to be set.")
-
-        self.ssl_key_file = ssl_key_file
-        self.ssl_cert_file = ssl_cert_file
-
-        TCPListener.__init__(self, protocol_class, port, interface, 
hosts_allow)
-
-
-    def createSocket(self):
-        # make a SSL socket
-        ctx = SSL.Context(SSL.SSLv23_METHOD)
-        ctx.set_options(SSL.OP_NO_SSLv2)
-        ctx.use_privatekey_file (self.ssl_key_file)
-        ctx.use_certificate_file(self.ssl_cert_file)
-        sock = SSL.Connection(ctx,
-                              socket.socket(socket.AF_INET, 
socket.SOCK_STREAM))
-        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
-
-        # SO_REUSEADDR does not always ensure that we do not get an address
-        # in use error when restarted quickly
-        # we implement a timeout to try and avoid failing unnecessarily
-        timeout = time.time() + 30
-        while True:
-            try:
-                sock.bind((self.interface, self.port))
-                return sock
-            except socket.error, (_errno, strerrno):
-                if _errno == errno.EADDRINUSE and time.time() < timeout:
-                    time.sleep(0.5)
-                else:
-                    raise
-
diff -Nura xen-unstable.orig/tools/python/xen/web/tcpssl.py 
xen-unstable/tools/python/xen/web/tcpssl.py
--- xen-unstable.orig/tools/python/xen/web/tcpssl.py    1970-01-01 
08:00:00.000000000 +0800
+++ xen-unstable/tools/python/xen/web/tcpssl.py 2008-05-08 15:38:54.000000000 
+0800
@@ -0,0 +1,82 @@
+#============================================================================
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of version 2.1 of the GNU Lesser General Public
+# License as published by the Free Software Foundation.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+#============================================================================
+# Copyright (C) 2005 Mike Wray <mike.wray@xxxxxx>
+# Copyright (C) 2005 XenSource Ltd.
+# Copyright (C) 2008 Oracle
+#============================================================================
+
+
+import errno
+import socket
+import time
+
+import connection
+import connectionssl
+
+from OpenSSL import SSL
+from tcp import TCPListener
+from xen.xend.XendLogging import log
+
+
+class SSLTCPListener(TCPListener):
+
+    def __init__(self, protocol_class, port, interface, hosts_allow,
+                 ssl_key_file = None, ssl_cert_file = None):
+        if not ssl_key_file or not ssl_cert_file:
+            raise ValueError("SSLXMLRPCServer requires ssl_key_file "
+                             "and ssl_cert_file to be set.")
+
+        self.ssl_key_file = ssl_key_file
+        self.ssl_cert_file = ssl_cert_file
+
+        TCPListener.__init__(self, protocol_class, port, interface, 
hosts_allow)
+
+
+    def createSocket(self):
+        # make a SSL socket
+        ctx = SSL.Context(SSL.SSLv23_METHOD)
+        ctx.set_options(SSL.OP_NO_SSLv2)
+        ctx.use_privatekey_file (self.ssl_key_file)
+        ctx.use_certificate_file(self.ssl_cert_file)
+        sock = SSL.Connection(ctx,
+                              socket.socket(socket.AF_INET, 
socket.SOCK_STREAM))
+        sock.set_accept_state()
+        sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
+
+        # SO_REUSEADDR does not always ensure that we do not get an address
+        # in use error when restarted quickly
+        # we implement a timeout to try and avoid failing unnecessarily
+        timeout = time.time() + 30
+        while True:
+            try:
+                sock.bind((self.interface, self.port))
+                return sock
+            except socket.error, (_errno, strerrno):
+                if _errno == errno.EADDRINUSE and time.time() < timeout:
+                    time.sleep(0.5)
+                else:
+                    raise
+
+
+    def acceptConnection(self, sock, addrport):
+        addr = addrport[0]
+        if connection.hostAllowed(addrport, self.hosts_allow):
+            connectionssl.SSLSocketServerConnection(sock, self.protocol_class)
+        else:
+            try:
+                sock.close()
+            except:
+                pass
+
diff -Nura xen-unstable.orig/tools/python/xen/xend/server/relocate.py 
xen-unstable/tools/python/xen/xend/server/relocate.py
--- xen-unstable.orig/tools/python/xen/xend/server/relocate.py  2008-05-05 
14:17:46.000000000 +0800
+++ xen-unstable/tools/python/xen/xend/server/relocate.py       2008-05-07 
16:39:00.000000000 +0800
@@ -17,10 +17,18 @@
 #============================================================================
 
 import re
+import os
 import sys
 import StringIO
+import threading
 
 from xen.web import protocol, tcp, unix
+try:
+    from xen.web import tcpssl
+    from xen.web import connectionssl
+    ssl_enabled = True
+except ImportError:
+    ssl_enabled = False
 
 from xen.xend import sxp
 from xen.xend import XendDomain
@@ -116,6 +124,27 @@
             log.error(name + ": no transport")
             raise XendError(name + ": no transport")
 
+    def op_sslreceive(self, name, _):
+        if self.transport:
+            self.send_reply(["ready", name])
+            p2cread, p2cwrite = os.pipe()
+            if not ssl_enabled:
+                raise ValueError("pyOpenSSL not installed. "
+                                 "Unable to start relocation with ssl")
+            threading.Thread(target=connectionssl.recv2fd,
+                             args=(self.transport.sock, p2cwrite)).start()
+            try:
+                XendDomain.instance().domain_restore_fd(p2cread,
+                                                        relocating=True)
+            except:
+                os.close(p2cread)
+                os.close(p2cwrite)
+                self.send_error()
+                self.close()
+        else:
+            log.error(name + ": no transport")
+            raise XendError(name + ": no transport")
+
 
 def listenRelocation():
     xoptions = XendOptions.instance()
@@ -136,10 +165,13 @@
         ssl_cert_file = xoptions.get_xend_relocation_server_ssl_cert_file()
 
         if ssl_key_file and ssl_cert_file:
-            tcp.SSLTCPListener(RelocationProtocol, port, interface = interface,
-                               hosts_allow = hosts_allow,
-                               ssl_key_file = ssl_key_file,
-                               ssl_cert_file = ssl_cert_file)
+            if not ssl_enabled:
+                raise ValueError("pyOpenSSL not installed. "
+                                 "Unable to start relocation server with ssl")
+            tcpssl.SSLTCPListener(RelocationProtocol, port, interface = 
interface,
+                                  hosts_allow = hosts_allow,
+                                  ssl_key_file = ssl_key_file,
+                                  ssl_cert_file = ssl_cert_file)
         else:
             tcp.TCPListener(RelocationProtocol, port, interface = interface,
                             hosts_allow = hosts_allow)
diff -Nura xen-unstable.orig/tools/python/xen/xend/XendDomain.py 
xen-unstable/tools/python/xen/xend/XendDomain.py
--- xen-unstable.orig/tools/python/xen/xend/XendDomain.py       2008-05-05 
14:17:45.000000000 +0800
+++ xen-unstable/tools/python/xen/xend/XendDomain.py    2008-05-08 
14:56:54.000000000 +0800
@@ -1297,19 +1297,39 @@
             tls = xoptions.get_xend_relocation_tls()
             if tls:
                 from OpenSSL import SSL
+                from xen.web import connectionssl
                 ctx = SSL.Context(SSL.SSLv23_METHOD)
-                sock = SSL.Connection(ctx, socket.socket(socket.AF_INET, 
socket.SOCK_STREAM))
+                sock = SSL.Connection(ctx,
+                           socket.socket(socket.AF_INET, socket.SOCK_STREAM))
                 sock.set_connect_state()
+                sock.connect((dst, port))
+                sock.send("sslreceive\n")
+                sock.recv(80)
+                p2cread, p2cwrite = os.pipe()
+                threading.Thread(target=connectionssl.fd2send,
+                                 args=(sock, p2cread)).start()
+                XendCheckpoint.save(p2cwrite, dominfo, True, live, dst,
+                                    node=node)
+                os.close(p2cread)
+                os.close(p2cwrite)
+                sock.shutdown()
+                sock.close()
             else:
                 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            sock.connect((dst, port))
+                # When connecting our ssl enabled relocation server using a
+                # plain socket, send will success but recv will block. Add a
+                # 30 seconds timeout to raise a socket.timeout exception to
+                # inform the client.
+                sock.settimeout(30.0)
+                sock.connect((dst, port))
+                sock.send("receive\n")
+                sock.recv(80)
+                sock.settimeout(None)
+                XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst,
+                                    node=node)
+                sock.close()
         except socket.error, err:
-            raise XendError("can't connect: %s" % err[1])
-
-        sock.send("receive\n")
-        sock.recv(80)
-        XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst, node=node)
-        sock.close()
+            raise XendError("can't connect: %s" % err)
 
     def domain_save(self, domid, dst, checkpoint=False):
         """Start saving a domain to file.
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.