[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] [xen-unstable] Fix relocation ssl/tls support
# HG changeset patch # User Keir Fraser <keir.fraser@xxxxxxxxxx> # Date 1210666747 -3600 # Node ID f8ce6e3d86c76a39a2e5098c5cc1c5e5529091f9 # Parent 0a8fc1a6279647ab625377a35413429d52b5d454 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> --- tools/python/xen/web/connection.py | 163 +++++++++++++++++++++++++++++++ tools/python/xen/web/tcp.py | 12 ++ tools/python/xen/xend/XendDomain.py | 63 ++++++++--- tools/python/xen/xend/server/relocate.py | 22 +++- 4 files changed, 243 insertions(+), 17 deletions(-) diff -r 0a8fc1a62796 -r f8ce6e3d86c7 tools/python/xen/web/connection.py --- a/tools/python/xen/web/connection.py Mon May 12 11:19:09 2008 +0100 +++ b/tools/python/xen/web/connection.py Tue May 13 09:19:07 2008 +0100 @@ -18,11 +18,17 @@ #============================================================================ import sys +import os import threading import socket import fcntl from errno import EAGAIN, EINTR, EWOULDBLOCK + +try: + from OpenSSL import SSL +except ImportError: + pass from xen.xend.XendLogging import log @@ -114,6 +120,163 @@ class SocketListener: finally: self.close() + +class SSLSocketServerConnection(SocketServerConnection): + """An SSL aware accepted connection to a server. + + 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=connection.recv2fd, args=(sock, p2cwrite)).start() + os.read(p2cread, 1024) + + To use fd2send(): + + p2cread, p2cwrite = os.pipe() + threading.Thread(target=connection.fd2send, args=(sock, p2cread)).start() + os.write(p2cwrite, "data") + """ + + 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 + + recv2fd = staticmethod(recv2fd) + + 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 (retval == -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 + + fd2send = staticmethod(fd2send) def hostAllowed(addrport, hosts_allowed): if hosts_allowed is None: diff -r 0a8fc1a62796 -r f8ce6e3d86c7 tools/python/xen/web/tcp.py --- a/tools/python/xen/web/tcp.py Mon May 12 11:19:09 2008 +0100 +++ b/tools/python/xen/web/tcp.py Tue May 13 09:19:07 2008 +0100 @@ -88,6 +88,7 @@ class SSLTCPListener(TCPListener): 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 @@ -104,3 +105,14 @@ class SSLTCPListener(TCPListener): else: raise + + def acceptConnection(self, sock, addrport): + addr = addrport[0] + if connection.hostAllowed(addrport, self.hosts_allow): + connection.SSLSocketServerConnection(sock, self.protocol_class) + else: + try: + sock.close() + except: + pass + diff -r 0a8fc1a62796 -r f8ce6e3d86c7 tools/python/xen/xend/XendDomain.py --- a/tools/python/xen/xend/XendDomain.py Mon May 12 11:19:09 2008 +0100 +++ b/tools/python/xen/xend/XendDomain.py Tue May 13 09:19:07 2008 +0100 @@ -1293,25 +1293,56 @@ class XendDomain: if port == 0: port = xoptions.get_xend_relocation_port() - try: - tls = xoptions.get_xend_relocation_tls() - if tls: - from OpenSSL import SSL + tls = xoptions.get_xend_relocation_tls() + if tls: + from OpenSSL import SSL + from xen.web import connection + try: 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() - else: + sock.connect((dst, port)) + sock.send("sslreceive\n") + sock.recv(80) + except SSL.Error, err: + raise XendError("SSL error: %s" % err) + except socket.error, err: + raise XendError("can't connect: %s" % err) + + p2cread, p2cwrite = os.pipe() + threading.Thread(target=connection.SSLSocketServerConnection.fd2send, + args=(sock, p2cread)).start() + + try: + XendCheckpoint.save(p2cwrite, dominfo, True, live, dst, + node=node) + finally: + sock.shutdown() + sock.close() + + os.close(p2cread) + os.close(p2cwrite) + else: + try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((dst, port)) - except socket.error, err: - raise XendError("can't connect: %s" % err[1]) - - sock.send("receive\n") - sock.recv(80) - try: - XendCheckpoint.save(sock.fileno(), dominfo, True, live, dst, node=node) - finally: - sock.close() + # When connecting to 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) + except socket.error, err: + raise XendError("can't connect: %s" % err) + + try: + XendCheckpoint.save(sock.fileno(), dominfo, True, live, + dst, node=node) + finally: + sock.close() def domain_save(self, domid, dst, checkpoint=False): """Start saving a domain to file. diff -r 0a8fc1a62796 -r f8ce6e3d86c7 tools/python/xen/xend/server/relocate.py --- a/tools/python/xen/xend/server/relocate.py Mon May 12 11:19:09 2008 +0100 +++ b/tools/python/xen/xend/server/relocate.py Tue May 13 09:19:07 2008 +0100 @@ -17,10 +17,12 @@ #============================================================================ import re +import os import sys import StringIO +import threading -from xen.web import protocol, tcp, unix +from xen.web import protocol, tcp, unix, connection from xen.xend import sxp from xen.xend import XendDomain @@ -116,6 +118,24 @@ class RelocationProtocol(protocol.Protoc 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() + threading.Thread(target=connection.SSLSocketServerConnection.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() _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |