Re: m2crypto blocking all other threads
Rune Froysa <[email protected]>
| Newsgroups | gmane.comp.python.cryptography |
|---|---|
| Message-ID | <[email protected]> |
Heikki Toivonen <[email protected]> writes: > Rune Froysa wrote: > > I'm using m2crypto for a SSL-based xmlrpc service. This service is > > frequently DOSed by what appears to be a bug in m2crypto: it blocks > > It seems like this is user error. In a multithreaded application you > need to initialize M2Crypto for threading. With those changes your > sample works for me. See below: Sorry about that. Is this documented some place? For some reason, demo/ssl/https_srv.py works without it (two "openssl s_client -connect localhost:19443" can connect simultaneously without problems). However, a "telnet localhost 19443"+<do nothing> first will prevent any later s_clients from reaching past the "CONNECTED(00000003)" state. The threading.init() trick seems to work for my previous example, but if I add a threading.init() to line 135 (first in __main__) of demo/ssl/https_srv.py, i get a segfault when a client connects (python 2.3.4) (It works if I actually have created a separate thread): Starting program: /usr/bin/python https_srv.py [Thread debugging using libthread_db enabled] [New Thread -1208785216 (LWP 12122)] Program received signal SIGSEGV, Segmentation fault. [Switching to Thread -1208785216 (LWP 12122)] 0x00dbdb4a in sem_post@GLIBC_2.0 () from /lib/tls/libpthread.so.0 (gdb) where #0 0x00dbdb4a in sem_post@GLIBC_2.0 () from /lib/tls/libpthread.so.0 #1 0x080cf636 in PyThread_release_lock (lock=0x0) at Python/thread_pthread.h:431 #2 0x080ca519 in PyGILState_Release (oldstate=3080343864) at Python/pystate.c:473 #3 0xb7ad39e8 in ssl_info_callback (s=0x81ef058, where=16, ret=1) at SWIG/_m2crypto.c:1058 #4 0x00b251e2 in ssl23_accept () from /lib/libssl.so.4 #5 0x00b2a093 in SSL_accept () from /lib/libssl.so.4 #6 0xb7ad73b3 in ssl_accept (ssl=0x81ef058) at SWIG/_m2crypto.c:3492 #7 0xb7ae2d23 in _wrap_ssl_accept (self=0x0, args=0xb79b310c) at SWIG/_m2crypto.c:11191 #8 0x080ed9b0 in PyCFunction_Call (func=0xb7b2218c, arg=0xb79b310c, kw=0x1) at Objects/methodobject.c:108 #9 0x080a4f67 in call_function (pp_stack=0xbfffee9c, oparg=135426480) at Python/ceval.c:3439 ... > > BTW: under 0.15, the https_srv.py complains from line 126 -> SSL/Context.py: 118: > > TypeError: ssl_ctx_load_verify_locations() argument 3 must be string, not None > > This does not happen for me. Strange. Latest version from svn: /tmp/m2/demo/ssl@dresden >PYTHONPATH=/tmp/m2/build/lib.linux-i686-2.3 python https_srv.py Traceback (most recent call last): File "https_srv.py", line 141, in ? SSL.verify_none) File "https_srv.py", line 126, in init_context ctx.load_verify_info(cafile) File "/tmp/m2/build/lib.linux-i686-2.3/M2Crypto/SSL/Context.py", line 121, in load_verify_locations return m2.ssl_ctx_load_verify_locations(self.ctx, cafile, capath) TypeError: ssl_ctx_load_verify_locations() argument 3 must be string, not None It would be great if there was some way to set a timeout value on connected clients. With the below patch, https_srv.py could instantiate the HTTPS_Server with a default_timeout=SSL.timeout(sec=4) keyword argument to kill misbehaving clients (like the telnet above). Could something like this be considered for future inclusion? (I don't believe there is a standard pythonic way of setting timeout on client sockets): Index: M2Crypto/SSL/SSLServer.py =================================================================== --- M2Crypto/SSL/SSLServer.py (revision 319) +++ M2Crypto/SSL/SSLServer.py (working copy) @@ -12,7 +12,7 @@ class SSLServer(SocketServer.TCPServer): - def __init__(self, server_address, RequestHandlerClass, ssl_context): + def __init__(self, server_address, RequestHandlerClass, ssl_context, default_timeout=None): """ Superclass says: Constructor. May be extended, do not override. This class says: Ho-hum. @@ -21,6 +21,8 @@ self.RequestHandlerClass=RequestHandlerClass self.ssl_ctx=ssl_context self.socket=Connection(self.ssl_ctx) + if default_timeout is not None: + self.socket.set_default_client_timeout(default_timeout) self.server_bind() self.server_activate() Index: M2Crypto/SSL/Connection.py =================================================================== --- M2Crypto/SSL/Connection.py (revision 319) +++ M2Crypto/SSL/Connection.py (working copy) @@ -38,6 +38,7 @@ self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._fileno = self.socket.fileno() + self._default_client_timeout = None def __del__(self): if getattr(self, 'sslbio', None): @@ -102,16 +103,27 @@ def accept_ssl(self): return m2.ssl_accept(self.ssl) + def set_default_client_timeout(self, timeout): + self._default_client_timeout = timeout + def accept(self): """Accept an SSL connection. The return value is a pair (ssl, addr) where ssl is a new SSL connection object and addr is the address bound to the the other end of the SSL connection.""" sock, addr = self.socket.accept() + if self._default_client_timeout is not None: + sock.setsockopt(socket.SOL_SOCKET, socket.SO_RCVTIMEO, + self._default_client_timeout.pack()) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_SNDTIMEO, + self._default_client_timeout.pack()) + ssl = Connection(self.ctx, sock) ssl.addr = addr ssl.setup_ssl() ssl.set_accept_state() - ssl.accept_ssl() + if ssl.accept_ssl() != 1: + raise SSLError(m2.err_reason_error_string(m2.err_get_error())) + check = getattr(self, 'postConnectionCheck', self.serverPostConnectionCheck) if check is not None: if not check(self.get_peer_cert(), ssl.addr[0]): Regards, Rune Frøysa