2014-08-16 13:53:07 +00:00
|
|
|
from __future__ import (absolute_import, print_function, division)
|
2015-02-27 15:59:29 +00:00
|
|
|
import os
|
2014-09-08 22:08:56 +00:00
|
|
|
import select
|
|
|
|
import socket
|
|
|
|
import sys
|
|
|
|
import threading
|
|
|
|
import time
|
|
|
|
import traceback
|
2012-06-18 21:42:32 +00:00
|
|
|
from OpenSSL import SSL
|
2015-03-07 00:31:31 +00:00
|
|
|
import OpenSSL
|
2014-09-08 22:08:56 +00:00
|
|
|
|
2014-08-16 13:53:07 +00:00
|
|
|
from . import certutils
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2014-03-02 08:37:28 +00:00
|
|
|
|
2014-03-02 03:47:10 +00:00
|
|
|
EINTR = 4
|
|
|
|
|
2012-07-04 09:30:07 +00:00
|
|
|
SSLv2_METHOD = SSL.SSLv2_METHOD
|
|
|
|
SSLv3_METHOD = SSL.SSLv3_METHOD
|
|
|
|
SSLv23_METHOD = SSL.SSLv23_METHOD
|
|
|
|
TLSv1_METHOD = SSL.TLSv1_METHOD
|
2014-12-15 11:32:36 +00:00
|
|
|
OP_NO_SSLv2 = SSL.OP_NO_SSLv2
|
|
|
|
OP_NO_SSLv3 = SSL.OP_NO_SSLv3
|
2012-07-04 09:30:07 +00:00
|
|
|
|
2012-06-18 21:42:32 +00:00
|
|
|
|
|
|
|
class NetLibError(Exception): pass
|
2013-05-05 01:49:20 +00:00
|
|
|
class NetLibDisconnect(NetLibError): pass
|
2015-05-04 22:47:02 +00:00
|
|
|
class NetLibIncomplete(NetLibError): pass
|
2013-05-05 01:49:20 +00:00
|
|
|
class NetLibTimeout(NetLibError): pass
|
2013-08-10 11:07:09 +00:00
|
|
|
class NetLibSSLError(NetLibError): pass
|
2012-07-08 11:50:38 +00:00
|
|
|
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2015-02-27 15:59:29 +00:00
|
|
|
class SSLKeyLogger(object):
|
|
|
|
def __init__(self, filename):
|
|
|
|
self.filename = filename
|
|
|
|
self.f = None
|
|
|
|
self.lock = threading.Lock()
|
|
|
|
|
|
|
|
__name__ = "SSLKeyLogger" # required for functools.wraps, which pyOpenSSL uses.
|
|
|
|
|
|
|
|
def __call__(self, connection, where, ret):
|
|
|
|
if where == SSL.SSL_CB_HANDSHAKE_DONE and ret == 1:
|
|
|
|
with self.lock:
|
|
|
|
if not self.f:
|
2015-02-27 21:02:52 +00:00
|
|
|
d = os.path.dirname(self.filename)
|
|
|
|
if not os.path.isdir(d):
|
|
|
|
os.makedirs(d)
|
2015-02-27 15:59:29 +00:00
|
|
|
self.f = open(self.filename, "ab")
|
|
|
|
self.f.write("\r\n")
|
|
|
|
client_random = connection.client_random().encode("hex")
|
|
|
|
masterkey = connection.master_key().encode("hex")
|
|
|
|
self.f.write("CLIENT_RANDOM {} {}\r\n".format(client_random, masterkey))
|
|
|
|
self.f.flush()
|
|
|
|
|
|
|
|
def close(self):
|
|
|
|
with self.lock:
|
|
|
|
if self.f:
|
|
|
|
self.f.close()
|
|
|
|
|
2015-02-27 21:02:52 +00:00
|
|
|
@staticmethod
|
|
|
|
def create_logfun(filename):
|
|
|
|
if filename:
|
|
|
|
return SSLKeyLogger(filename)
|
|
|
|
return False
|
|
|
|
|
|
|
|
log_ssl_key = SSLKeyLogger.create_logfun(os.getenv("MITMPROXY_SSLKEYLOGFILE") or os.getenv("SSLKEYLOGFILE"))
|
2015-02-27 15:59:29 +00:00
|
|
|
|
|
|
|
|
2015-04-09 00:09:33 +00:00
|
|
|
class _FileLike(object):
|
2012-07-23 23:39:49 +00:00
|
|
|
BLOCKSIZE = 1024 * 32
|
2012-06-18 21:42:32 +00:00
|
|
|
def __init__(self, o):
|
|
|
|
self.o = o
|
2012-09-23 23:10:21 +00:00
|
|
|
self._log = None
|
2013-01-16 20:30:19 +00:00
|
|
|
self.first_byte_timestamp = None
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2012-09-23 22:47:41 +00:00
|
|
|
def set_descriptor(self, o):
|
|
|
|
self.o = o
|
|
|
|
|
2012-06-18 21:42:32 +00:00
|
|
|
def __getattr__(self, attr):
|
|
|
|
return getattr(self.o, attr)
|
|
|
|
|
2012-09-23 23:10:21 +00:00
|
|
|
def start_log(self):
|
|
|
|
"""
|
|
|
|
Starts or resets the log.
|
|
|
|
|
|
|
|
This will store all bytes read or written.
|
|
|
|
"""
|
|
|
|
self._log = []
|
|
|
|
|
|
|
|
def stop_log(self):
|
|
|
|
"""
|
|
|
|
Stops the log.
|
|
|
|
"""
|
|
|
|
self._log = None
|
|
|
|
|
|
|
|
def is_logging(self):
|
|
|
|
return self._log is not None
|
|
|
|
|
|
|
|
def get_log(self):
|
|
|
|
"""
|
|
|
|
Returns the log as a string.
|
|
|
|
"""
|
|
|
|
if not self.is_logging():
|
|
|
|
raise ValueError("Not logging!")
|
|
|
|
return "".join(self._log)
|
|
|
|
|
|
|
|
def add_log(self, v):
|
|
|
|
if self.is_logging():
|
|
|
|
self._log.append(v)
|
|
|
|
|
2013-01-16 20:30:19 +00:00
|
|
|
def reset_timestamps(self):
|
|
|
|
self.first_byte_timestamp = None
|
2012-09-23 23:10:21 +00:00
|
|
|
|
2013-01-25 02:54:41 +00:00
|
|
|
|
2012-09-23 23:10:21 +00:00
|
|
|
class Writer(_FileLike):
|
2012-06-18 21:42:32 +00:00
|
|
|
def flush(self):
|
2013-01-26 08:19:35 +00:00
|
|
|
"""
|
|
|
|
May raise NetLibDisconnect
|
|
|
|
"""
|
2013-01-25 02:54:41 +00:00
|
|
|
if hasattr(self.o, "flush"):
|
|
|
|
try:
|
2012-07-29 23:30:31 +00:00
|
|
|
self.o.flush()
|
2013-07-29 21:42:13 +00:00
|
|
|
except (socket.error, IOError), v:
|
2013-01-25 02:54:41 +00:00
|
|
|
raise NetLibDisconnect(str(v))
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2012-09-23 23:10:21 +00:00
|
|
|
def write(self, v):
|
2013-01-26 08:19:35 +00:00
|
|
|
"""
|
|
|
|
May raise NetLibDisconnect
|
|
|
|
"""
|
2012-09-23 23:10:21 +00:00
|
|
|
if v:
|
|
|
|
try:
|
|
|
|
if hasattr(self.o, "sendall"):
|
|
|
|
self.add_log(v)
|
|
|
|
return self.o.sendall(v)
|
|
|
|
else:
|
|
|
|
r = self.o.write(v)
|
|
|
|
self.add_log(v[:r])
|
|
|
|
return r
|
2015-04-09 00:09:33 +00:00
|
|
|
except (SSL.Error, socket.error) as e:
|
|
|
|
raise NetLibDisconnect(str(e))
|
2012-09-23 23:10:21 +00:00
|
|
|
|
|
|
|
|
|
|
|
class Reader(_FileLike):
|
2012-06-18 21:42:32 +00:00
|
|
|
def read(self, length):
|
2012-07-23 23:39:49 +00:00
|
|
|
"""
|
2012-10-09 03:25:15 +00:00
|
|
|
If length is -1, we read until connection closes.
|
2012-07-23 23:39:49 +00:00
|
|
|
"""
|
2012-06-18 21:42:32 +00:00
|
|
|
result = ''
|
2012-07-21 04:10:54 +00:00
|
|
|
start = time.time()
|
2012-07-23 23:39:49 +00:00
|
|
|
while length == -1 or length > 0:
|
2012-10-09 03:25:15 +00:00
|
|
|
if length == -1 or length > self.BLOCKSIZE:
|
|
|
|
rlen = self.BLOCKSIZE
|
|
|
|
else:
|
|
|
|
rlen = length
|
2012-06-18 21:42:32 +00:00
|
|
|
try:
|
2012-10-09 03:25:15 +00:00
|
|
|
data = self.o.read(rlen)
|
2012-07-21 08:51:05 +00:00
|
|
|
except SSL.ZeroReturnError:
|
2012-06-18 21:42:32 +00:00
|
|
|
break
|
2012-07-21 04:10:54 +00:00
|
|
|
except SSL.WantReadError:
|
|
|
|
if (time.time() - start) < self.o.gettimeout():
|
|
|
|
time.sleep(0.1)
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
raise NetLibTimeout
|
|
|
|
except socket.timeout:
|
|
|
|
raise NetLibTimeout
|
2014-01-09 04:33:21 +00:00
|
|
|
except socket.error:
|
|
|
|
raise NetLibDisconnect
|
2014-03-10 16:43:39 +00:00
|
|
|
except SSL.SysCallError as e:
|
|
|
|
if e.args == (-1, 'Unexpected EOF'):
|
|
|
|
break
|
2015-02-27 21:02:52 +00:00
|
|
|
raise NetLibSSLError(e.message)
|
|
|
|
except SSL.Error as e:
|
|
|
|
raise NetLibSSLError(e.message)
|
2013-01-16 20:30:19 +00:00
|
|
|
self.first_byte_timestamp = self.first_byte_timestamp or time.time()
|
2012-06-18 21:42:32 +00:00
|
|
|
if not data:
|
|
|
|
break
|
|
|
|
result += data
|
2012-07-23 23:39:49 +00:00
|
|
|
if length != -1:
|
|
|
|
length -= len(data)
|
2012-09-23 23:10:21 +00:00
|
|
|
self.add_log(result)
|
2012-06-18 21:42:32 +00:00
|
|
|
return result
|
|
|
|
|
|
|
|
def readline(self, size = None):
|
|
|
|
result = ''
|
|
|
|
bytes_read = 0
|
|
|
|
while True:
|
|
|
|
if size is not None and bytes_read >= size:
|
|
|
|
break
|
2015-02-27 21:02:52 +00:00
|
|
|
ch = self.read(1)
|
2012-06-18 21:42:32 +00:00
|
|
|
bytes_read += 1
|
|
|
|
if not ch:
|
|
|
|
break
|
|
|
|
else:
|
|
|
|
result += ch
|
|
|
|
if ch == '\n':
|
|
|
|
break
|
|
|
|
return result
|
|
|
|
|
2015-05-04 22:47:02 +00:00
|
|
|
def safe_read(self, length):
|
|
|
|
"""
|
|
|
|
Like .read, but is guaranteed to either return length bytes, or
|
|
|
|
raise an exception.
|
|
|
|
"""
|
|
|
|
result = self.read(length)
|
|
|
|
if length != -1 and len(result) != length:
|
|
|
|
raise NetLibIncomplete(
|
|
|
|
"Expected %s bytes, got %s"%(length, len(result))
|
|
|
|
)
|
|
|
|
return result
|
|
|
|
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2014-01-31 00:06:53 +00:00
|
|
|
class Address(object):
|
2014-01-28 16:26:35 +00:00
|
|
|
"""
|
2015-05-04 22:47:02 +00:00
|
|
|
This class wraps an IPv4/IPv6 tuple to provide named attributes and
|
|
|
|
ipv6 information.
|
2014-01-28 16:26:35 +00:00
|
|
|
"""
|
2014-01-30 19:07:30 +00:00
|
|
|
def __init__(self, address, use_ipv6=False):
|
2014-02-05 20:34:14 +00:00
|
|
|
self.address = tuple(address)
|
2014-01-31 00:06:53 +00:00
|
|
|
self.use_ipv6 = use_ipv6
|
2014-01-28 16:26:35 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def wrap(cls, t):
|
|
|
|
if isinstance(t, cls):
|
|
|
|
return t
|
|
|
|
else:
|
|
|
|
return cls(t)
|
|
|
|
|
2014-01-30 19:07:30 +00:00
|
|
|
def __call__(self):
|
|
|
|
return self.address
|
|
|
|
|
2014-01-28 16:26:35 +00:00
|
|
|
@property
|
|
|
|
def host(self):
|
2014-01-30 19:07:30 +00:00
|
|
|
return self.address[0]
|
2014-01-28 16:26:35 +00:00
|
|
|
|
|
|
|
@property
|
|
|
|
def port(self):
|
2014-01-30 19:07:30 +00:00
|
|
|
return self.address[1]
|
2014-01-28 16:26:35 +00:00
|
|
|
|
|
|
|
@property
|
2014-01-30 19:07:30 +00:00
|
|
|
def use_ipv6(self):
|
2014-01-28 16:26:35 +00:00
|
|
|
return self.family == socket.AF_INET6
|
|
|
|
|
2014-01-31 00:06:53 +00:00
|
|
|
@use_ipv6.setter
|
|
|
|
def use_ipv6(self, b):
|
|
|
|
self.family = socket.AF_INET6 if b else socket.AF_INET
|
2014-01-30 19:07:30 +00:00
|
|
|
|
2014-09-03 23:10:44 +00:00
|
|
|
def __repr__(self):
|
|
|
|
return repr(self.address)
|
|
|
|
|
2014-02-04 03:51:41 +00:00
|
|
|
def __eq__(self, other):
|
|
|
|
other = Address.wrap(other)
|
|
|
|
return (self.address, self.family) == (other.address, other.family)
|
2014-01-28 16:26:35 +00:00
|
|
|
|
2014-09-03 23:10:44 +00:00
|
|
|
def __ne__(self, other):
|
|
|
|
return not self.__eq__(other)
|
|
|
|
|
2014-02-04 03:51:41 +00:00
|
|
|
|
2014-10-22 15:54:20 +00:00
|
|
|
def close_socket(sock):
|
|
|
|
"""
|
|
|
|
Does a hard close of a socket, without emitting a RST.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
# We already indicate that we close our end.
|
2015-05-04 22:47:02 +00:00
|
|
|
# may raise "Transport endpoint is not connected" on Linux
|
|
|
|
sock.shutdown(socket.SHUT_WR)
|
2014-10-22 15:54:20 +00:00
|
|
|
|
2015-05-04 22:47:02 +00:00
|
|
|
# Section 4.2.2.13 of RFC 1122 tells us that a close() with any pending
|
|
|
|
# readable data could lead to an immediate RST being sent (which is the
|
|
|
|
# case on Windows).
|
2014-10-22 15:54:20 +00:00
|
|
|
# http://ia600609.us.archive.org/22/items/TheUltimateSo_lingerPageOrWhyIsMyTcpNotReliable/the-ultimate-so_linger-page-or-why-is-my-tcp-not-reliable.html
|
|
|
|
#
|
2015-05-04 22:47:02 +00:00
|
|
|
# This in turn results in the following issue: If we send an error page
|
|
|
|
# to the client and then close the socket, the RST may be received by
|
|
|
|
# the client before the error page and the users sees a connection
|
|
|
|
# error rather than the error page. Thus, we try to empty the read
|
|
|
|
# buffer on Windows first. (see
|
|
|
|
# https://github.com/mitmproxy/mitmproxy/issues/527#issuecomment-93782988)
|
2015-04-17 14:29:09 +00:00
|
|
|
#
|
2015-05-04 22:47:02 +00:00
|
|
|
|
2015-04-17 14:29:09 +00:00
|
|
|
if os.name == "nt": # pragma: no cover
|
2015-05-04 22:47:02 +00:00
|
|
|
# We cannot rely on the shutdown()-followed-by-read()-eof technique
|
|
|
|
# proposed by the page above: Some remote machines just don't send
|
|
|
|
# a TCP FIN, which would leave us in the unfortunate situation that
|
|
|
|
# recv() would block infinitely. As a workaround, we set a timeout
|
|
|
|
# here even if we are in blocking mode.
|
2015-04-17 14:29:09 +00:00
|
|
|
sock.settimeout(sock.gettimeout() or 20)
|
|
|
|
|
|
|
|
# limit at a megabyte so that we don't read infinitely
|
|
|
|
for _ in xrange(1024 ** 3 // 4096):
|
|
|
|
# may raise a timeout/disconnect exception.
|
|
|
|
if not sock.recv(4096):
|
|
|
|
break
|
|
|
|
|
|
|
|
# Now we can close the other half as well.
|
|
|
|
sock.shutdown(socket.SHUT_RD)
|
2014-10-22 15:54:20 +00:00
|
|
|
|
|
|
|
except socket.error:
|
|
|
|
pass
|
|
|
|
|
|
|
|
sock.close()
|
|
|
|
|
|
|
|
|
2014-03-02 08:37:28 +00:00
|
|
|
class _Connection(object):
|
|
|
|
def get_current_cipher(self):
|
|
|
|
if not self.ssl_established:
|
|
|
|
return None
|
|
|
|
c = SSL._lib.SSL_get_current_cipher(self.connection._ssl)
|
|
|
|
name = SSL._native(SSL._ffi.string(SSL._lib.SSL_CIPHER_get_name(c)))
|
|
|
|
bits = SSL._lib.SSL_CIPHER_get_bits(c, SSL._ffi.NULL)
|
|
|
|
version = SSL._native(SSL._ffi.string(SSL._lib.SSL_CIPHER_get_version(c)))
|
|
|
|
return name, bits, version
|
|
|
|
|
2014-01-09 04:33:21 +00:00
|
|
|
def finish(self):
|
|
|
|
self.finished = True
|
2014-10-22 15:54:20 +00:00
|
|
|
# If we have an SSL connection, wfile.close == connection.close
|
|
|
|
# (We call _FileLike.set_descriptor(conn))
|
2015-05-04 22:47:02 +00:00
|
|
|
# Closing the socket is not our task, therefore we don't call close
|
|
|
|
# then.
|
2014-10-22 15:54:20 +00:00
|
|
|
if type(self.connection) != SSL.Connection:
|
2014-01-09 04:33:21 +00:00
|
|
|
if not getattr(self.wfile, "closed", False):
|
2014-11-07 03:01:41 +00:00
|
|
|
try:
|
|
|
|
self.wfile.flush()
|
2014-11-14 23:31:13 +00:00
|
|
|
self.wfile.close()
|
2014-11-07 03:01:41 +00:00
|
|
|
except NetLibDisconnect:
|
|
|
|
pass
|
2014-10-22 15:54:20 +00:00
|
|
|
|
2014-01-09 04:33:21 +00:00
|
|
|
self.rfile.close()
|
2014-10-22 15:54:20 +00:00
|
|
|
else:
|
|
|
|
try:
|
2014-01-09 04:33:21 +00:00
|
|
|
self.connection.shutdown()
|
2014-10-22 15:54:20 +00:00
|
|
|
except SSL.Error:
|
|
|
|
pass
|
2015-04-08 22:57:37 +00:00
|
|
|
except KeyError as e: # pragma: no cover
|
2015-03-07 00:31:31 +00:00
|
|
|
# Workaround for https://github.com/pyca/pyopenssl/pull/183
|
|
|
|
if OpenSSL.__version__ != "0.14":
|
|
|
|
raise e
|
2014-01-09 04:33:21 +00:00
|
|
|
|
2015-03-07 00:22:02 +00:00
|
|
|
"""
|
|
|
|
Creates an SSL Context.
|
|
|
|
"""
|
|
|
|
def _create_ssl_context(self,
|
|
|
|
method=SSLv23_METHOD,
|
|
|
|
options=(OP_NO_SSLv2 | OP_NO_SSLv3),
|
|
|
|
cipher_list=None
|
|
|
|
):
|
|
|
|
"""
|
|
|
|
:param method: One of SSLv2_METHOD, SSLv3_METHOD, SSLv23_METHOD, TLSv1_METHOD or TLSv1_1_METHOD
|
|
|
|
:param options: A bit field consisting of OpenSSL.SSL.OP_* values
|
|
|
|
:param cipher_list: A textual OpenSSL cipher list, see https://www.openssl.org/docs/apps/ciphers.html
|
|
|
|
:rtype : SSL.Context
|
|
|
|
"""
|
|
|
|
context = SSL.Context(method)
|
|
|
|
# Options (NO_SSLv2/3)
|
|
|
|
if options is not None:
|
|
|
|
context.set_options(options)
|
|
|
|
|
|
|
|
# Workaround for
|
|
|
|
# https://github.com/pyca/pyopenssl/issues/190
|
|
|
|
# https://github.com/mitmproxy/mitmproxy/issues/472
|
|
|
|
context.set_mode(SSL._lib.SSL_MODE_AUTO_RETRY) # Options already set before are not cleared.
|
|
|
|
|
|
|
|
# Cipher List
|
|
|
|
if cipher_list:
|
|
|
|
try:
|
|
|
|
context.set_cipher_list(cipher_list)
|
|
|
|
except SSL.Error, v:
|
|
|
|
raise NetLibError("SSL cipher specification error: %s"%str(v))
|
|
|
|
|
|
|
|
# SSLKEYLOGFILE
|
|
|
|
if log_ssl_key:
|
|
|
|
context.set_info_callback(log_ssl_key)
|
|
|
|
|
|
|
|
return context
|
|
|
|
|
2014-01-09 04:33:21 +00:00
|
|
|
|
2014-03-02 08:37:28 +00:00
|
|
|
class TCPClient(_Connection):
|
2012-06-29 22:52:28 +00:00
|
|
|
rbufsize = -1
|
|
|
|
wbufsize = -1
|
2014-09-08 22:08:56 +00:00
|
|
|
|
2014-10-22 15:54:20 +00:00
|
|
|
def close(self):
|
|
|
|
# Make sure to close the real socket, not the SSL proxy.
|
|
|
|
# OpenSSL is really good at screwing up, i.e. when trying to recv from a failed connection,
|
|
|
|
# it tries to renegotiate...
|
|
|
|
if type(self.connection) == SSL.Connection:
|
|
|
|
close_socket(self.connection._socket)
|
|
|
|
else:
|
|
|
|
close_socket(self.connection)
|
|
|
|
|
2014-01-28 16:26:35 +00:00
|
|
|
def __init__(self, address, source_address=None):
|
|
|
|
self.address = Address.wrap(address)
|
2014-01-30 19:07:30 +00:00
|
|
|
self.source_address = Address.wrap(source_address) if source_address else None
|
2012-06-18 21:42:32 +00:00
|
|
|
self.connection, self.rfile, self.wfile = None, None, None
|
|
|
|
self.cert = None
|
2012-06-26 11:52:35 +00:00
|
|
|
self.ssl_established = False
|
2014-02-04 03:51:41 +00:00
|
|
|
self.sni = None
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2015-03-07 00:22:02 +00:00
|
|
|
def create_ssl_context(self, cert=None, **sslctx_kwargs):
|
|
|
|
context = self._create_ssl_context(**sslctx_kwargs)
|
|
|
|
# Client Certs
|
2013-02-24 02:36:15 +00:00
|
|
|
if cert:
|
2013-01-20 09:36:54 +00:00
|
|
|
try:
|
2013-02-24 02:36:15 +00:00
|
|
|
context.use_privatekey_file(cert)
|
|
|
|
context.use_certificate_file(cert)
|
2013-01-20 09:36:54 +00:00
|
|
|
except SSL.Error, v:
|
|
|
|
raise NetLibError("SSL client certificate error: %s"%str(v))
|
2015-03-07 00:22:02 +00:00
|
|
|
return context
|
|
|
|
|
|
|
|
def convert_to_ssl(self, sni=None, **sslctx_kwargs):
|
|
|
|
"""
|
|
|
|
cert: Path to a file containing both client cert and private key.
|
|
|
|
|
|
|
|
options: A bit field consisting of OpenSSL.SSL.OP_* values
|
|
|
|
"""
|
|
|
|
context = self.create_ssl_context(**sslctx_kwargs)
|
2012-06-25 02:42:15 +00:00
|
|
|
self.connection = SSL.Connection(context, self.connection)
|
2012-06-25 21:50:42 +00:00
|
|
|
if sni:
|
2014-02-04 03:51:41 +00:00
|
|
|
self.sni = sni
|
2012-06-25 21:50:42 +00:00
|
|
|
self.connection.set_tlsext_host_name(sni)
|
2012-06-25 02:42:15 +00:00
|
|
|
self.connection.set_connect_state()
|
2012-06-26 02:49:23 +00:00
|
|
|
try:
|
|
|
|
self.connection.do_handshake()
|
|
|
|
except SSL.Error, v:
|
2014-09-08 16:38:05 +00:00
|
|
|
raise NetLibError("SSL handshake error: %s"%repr(v))
|
2014-10-08 16:40:46 +00:00
|
|
|
self.ssl_established = True
|
2012-06-27 22:59:03 +00:00
|
|
|
self.cert = certutils.SSLCert(self.connection.get_peer_certificate())
|
2012-09-23 22:47:41 +00:00
|
|
|
self.rfile.set_descriptor(self.connection)
|
|
|
|
self.wfile.set_descriptor(self.connection)
|
2012-06-25 02:42:15 +00:00
|
|
|
|
2012-06-18 21:42:32 +00:00
|
|
|
def connect(self):
|
|
|
|
try:
|
2014-01-28 16:26:35 +00:00
|
|
|
connection = socket.socket(self.address.family, socket.SOCK_STREAM)
|
2013-07-07 05:33:56 +00:00
|
|
|
if self.source_address:
|
2014-01-30 19:07:30 +00:00
|
|
|
connection.bind(self.source_address())
|
|
|
|
connection.connect(self.address())
|
2014-09-04 14:55:02 +00:00
|
|
|
if not self.source_address:
|
|
|
|
self.source_address = Address(connection.getsockname())
|
2012-09-23 23:10:21 +00:00
|
|
|
self.rfile = Reader(connection.makefile('rb', self.rbufsize))
|
|
|
|
self.wfile = Writer(connection.makefile('wb', self.wbufsize))
|
2013-07-29 21:42:13 +00:00
|
|
|
except (socket.error, IOError), err:
|
2014-01-30 19:07:30 +00:00
|
|
|
raise NetLibError('Error connecting to "%s": %s' % (self.address.host, err))
|
2012-06-25 02:42:15 +00:00
|
|
|
self.connection = connection
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2012-07-21 04:10:54 +00:00
|
|
|
def settimeout(self, n):
|
|
|
|
self.connection.settimeout(n)
|
|
|
|
|
|
|
|
def gettimeout(self):
|
2013-01-26 08:29:45 +00:00
|
|
|
return self.connection.gettimeout()
|
2012-07-21 04:10:54 +00:00
|
|
|
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2014-03-02 08:37:28 +00:00
|
|
|
class BaseHandler(_Connection):
|
2012-06-24 23:23:04 +00:00
|
|
|
"""
|
|
|
|
The instantiator is expected to call the handle() and finish() methods.
|
2013-07-29 21:42:13 +00:00
|
|
|
|
2012-06-24 23:23:04 +00:00
|
|
|
"""
|
2012-06-18 21:42:32 +00:00
|
|
|
rbufsize = -1
|
2012-06-26 02:49:23 +00:00
|
|
|
wbufsize = -1
|
2014-01-28 19:30:16 +00:00
|
|
|
|
|
|
|
def __init__(self, connection, address, server):
|
2012-06-18 21:42:32 +00:00
|
|
|
self.connection = connection
|
2014-01-28 16:26:35 +00:00
|
|
|
self.address = Address.wrap(address)
|
2014-01-28 19:30:16 +00:00
|
|
|
self.server = server
|
2012-09-23 23:10:21 +00:00
|
|
|
self.rfile = Reader(self.connection.makefile('rb', self.rbufsize))
|
|
|
|
self.wfile = Writer(self.connection.makefile('wb', self.wbufsize))
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2012-06-24 23:34:10 +00:00
|
|
|
self.finished = False
|
2012-06-26 11:52:35 +00:00
|
|
|
self.ssl_established = False
|
2013-01-20 09:13:38 +00:00
|
|
|
self.clientcert = None
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2015-03-07 00:22:02 +00:00
|
|
|
def create_ssl_context(self,
|
|
|
|
cert, key,
|
|
|
|
handle_sni=None,
|
|
|
|
request_client_cert=None,
|
|
|
|
chain_file=None,
|
|
|
|
dhparams=None,
|
|
|
|
**sslctx_kwargs):
|
2012-07-04 09:30:07 +00:00
|
|
|
"""
|
2013-08-12 04:03:29 +00:00
|
|
|
cert: A certutils.SSLCert object.
|
2014-09-08 22:08:56 +00:00
|
|
|
|
2013-02-25 08:11:09 +00:00
|
|
|
handle_sni: SNI handler, should take a connection object. Server
|
|
|
|
name can be retrieved like this:
|
|
|
|
|
2014-09-08 22:08:56 +00:00
|
|
|
connection.get_servername()
|
|
|
|
|
|
|
|
And you can specify the connection keys as follows:
|
2013-02-25 08:11:09 +00:00
|
|
|
|
2014-09-08 22:08:56 +00:00
|
|
|
new_context = Context(TLSv1_METHOD)
|
|
|
|
new_context.use_privatekey(key)
|
|
|
|
new_context.use_certificate(cert)
|
|
|
|
connection.set_context(new_context)
|
2013-05-12 20:48:21 +00:00
|
|
|
|
|
|
|
The request_client_cert argument requires some explanation. We're
|
|
|
|
supposed to be able to do this with no negative effects - if the
|
|
|
|
client has no cert to present, we're notified and proceed as usual.
|
|
|
|
Unfortunately, Android seems to have a bug (tested on 4.2.2) - when
|
|
|
|
an Android client is asked to present a certificate it does not
|
|
|
|
have, it hangs up, which is frankly bogus. Some time down the track
|
|
|
|
we may be able to make the proper behaviour the default again, but
|
|
|
|
until then we're conservative.
|
2012-07-04 09:30:07 +00:00
|
|
|
"""
|
2015-03-07 00:22:02 +00:00
|
|
|
context = self._create_ssl_context(**sslctx_kwargs)
|
|
|
|
|
|
|
|
context.use_privatekey(key)
|
|
|
|
context.use_certificate(cert.x509)
|
|
|
|
|
2013-02-25 08:11:09 +00:00
|
|
|
if handle_sni:
|
|
|
|
# SNI callback happens during do_handshake()
|
2015-03-07 00:22:02 +00:00
|
|
|
context.set_tlsext_servername_callback(handle_sni)
|
|
|
|
|
2013-05-12 20:48:21 +00:00
|
|
|
if request_client_cert:
|
2015-03-07 00:22:02 +00:00
|
|
|
def save_cert(conn, cert, errno, depth, preverify_ok):
|
|
|
|
self.clientcert = certutils.SSLCert(cert)
|
2013-12-07 21:15:19 +00:00
|
|
|
# Return true to prevent cert verification error
|
|
|
|
return True
|
2015-03-07 00:22:02 +00:00
|
|
|
context.set_verify(SSL.VERIFY_PEER, save_cert)
|
|
|
|
|
|
|
|
# Cert Verify
|
|
|
|
if chain_file:
|
|
|
|
context.load_verify_locations(chain_file)
|
|
|
|
|
|
|
|
if dhparams:
|
|
|
|
SSL._lib.SSL_CTX_set_tmp_dh(context._context, dhparams)
|
|
|
|
|
|
|
|
return context
|
2014-05-15 11:51:59 +00:00
|
|
|
|
2014-05-15 12:15:33 +00:00
|
|
|
def convert_to_ssl(self, cert, key, **sslctx_kwargs):
|
2014-05-15 11:51:59 +00:00
|
|
|
"""
|
|
|
|
Convert connection to SSL.
|
|
|
|
For a list of parameters, see BaseHandler._create_ssl_context(...)
|
|
|
|
"""
|
2015-03-07 00:22:02 +00:00
|
|
|
context = self.create_ssl_context(cert, key, **sslctx_kwargs)
|
|
|
|
self.connection = SSL.Connection(context, self.connection)
|
2012-06-18 21:42:32 +00:00
|
|
|
self.connection.set_accept_state()
|
2012-06-26 02:49:23 +00:00
|
|
|
try:
|
|
|
|
self.connection.do_handshake()
|
|
|
|
except SSL.Error, v:
|
2014-09-08 16:38:05 +00:00
|
|
|
raise NetLibError("SSL handshake error: %s"%repr(v))
|
2014-10-08 16:40:46 +00:00
|
|
|
self.ssl_established = True
|
2012-09-23 22:47:41 +00:00
|
|
|
self.rfile.set_descriptor(self.connection)
|
|
|
|
self.wfile.set_descriptor(self.connection)
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2015-03-07 00:22:02 +00:00
|
|
|
def handle(self): # pragma: no cover
|
2012-06-18 21:42:32 +00:00
|
|
|
raise NotImplementedError
|
|
|
|
|
2012-09-30 22:30:02 +00:00
|
|
|
def settimeout(self, n):
|
|
|
|
self.connection.settimeout(n)
|
|
|
|
|
2012-07-20 02:43:51 +00:00
|
|
|
|
2014-02-15 22:16:28 +00:00
|
|
|
class TCPServer(object):
|
2012-06-18 21:42:32 +00:00
|
|
|
request_queue_size = 20
|
2015-03-07 00:22:02 +00:00
|
|
|
|
2014-01-28 16:26:35 +00:00
|
|
|
def __init__(self, address):
|
|
|
|
self.address = Address.wrap(address)
|
2012-06-18 21:42:32 +00:00
|
|
|
self.__is_shut_down = threading.Event()
|
|
|
|
self.__shutdown_request = False
|
2014-01-28 16:26:35 +00:00
|
|
|
self.socket = socket.socket(self.address.family, socket.SOCK_STREAM)
|
2012-06-18 21:42:32 +00:00
|
|
|
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
2014-01-30 19:07:30 +00:00
|
|
|
self.socket.bind(self.address())
|
2014-01-28 16:26:35 +00:00
|
|
|
self.address = Address.wrap(self.socket.getsockname())
|
2012-06-18 21:42:32 +00:00
|
|
|
self.socket.listen(self.request_queue_size)
|
|
|
|
|
2014-01-09 00:57:37 +00:00
|
|
|
def connection_thread(self, connection, client_address):
|
2014-01-28 16:26:35 +00:00
|
|
|
client_address = Address(client_address)
|
2012-06-18 21:42:32 +00:00
|
|
|
try:
|
2014-01-09 00:57:37 +00:00
|
|
|
self.handle_client_connection(connection, client_address)
|
2012-06-18 21:42:32 +00:00
|
|
|
except:
|
2014-01-09 00:57:37 +00:00
|
|
|
self.handle_error(connection, client_address)
|
|
|
|
finally:
|
2014-10-22 15:54:20 +00:00
|
|
|
close_socket(connection)
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2012-06-19 23:01:40 +00:00
|
|
|
def serve_forever(self, poll_interval=0.1):
|
2012-06-18 21:42:32 +00:00
|
|
|
self.__is_shut_down.clear()
|
|
|
|
try:
|
|
|
|
while not self.__shutdown_request:
|
2013-08-24 22:22:09 +00:00
|
|
|
try:
|
|
|
|
r, w, e = select.select([self.socket], [], [], poll_interval)
|
2015-03-07 00:22:02 +00:00
|
|
|
except select.error as ex: # pragma: no cover
|
2015-04-09 00:09:33 +00:00
|
|
|
if ex[0] == EINTR:
|
|
|
|
continue
|
|
|
|
else:
|
|
|
|
raise
|
2012-06-18 21:42:32 +00:00
|
|
|
if self.socket in r:
|
2014-01-09 00:57:37 +00:00
|
|
|
connection, client_address = self.socket.accept()
|
2013-01-27 06:21:18 +00:00
|
|
|
t = threading.Thread(
|
2015-03-07 00:22:02 +00:00
|
|
|
target=self.connection_thread,
|
|
|
|
args=(connection, client_address),
|
|
|
|
name="ConnectionThread (%s:%s -> %s:%s)" %
|
|
|
|
(client_address[0], client_address[1],
|
|
|
|
self.address.host, self.address.port)
|
|
|
|
)
|
2013-01-27 06:21:18 +00:00
|
|
|
t.setDaemon(1)
|
2015-04-08 22:12:41 +00:00
|
|
|
try:
|
|
|
|
t.start()
|
|
|
|
except threading.ThreadError:
|
|
|
|
self.handle_error(connection, Address(client_address))
|
|
|
|
connection.close()
|
2012-06-18 21:42:32 +00:00
|
|
|
finally:
|
|
|
|
self.__shutdown_request = False
|
|
|
|
self.__is_shut_down.set()
|
|
|
|
|
|
|
|
def shutdown(self):
|
|
|
|
self.__shutdown_request = True
|
|
|
|
self.__is_shut_down.wait()
|
2012-06-19 22:51:02 +00:00
|
|
|
self.socket.close()
|
2012-06-18 21:42:32 +00:00
|
|
|
self.handle_shutdown()
|
|
|
|
|
2014-09-28 01:15:26 +00:00
|
|
|
def handle_error(self, connection, client_address, fp=sys.stderr):
|
2012-06-18 21:42:32 +00:00
|
|
|
"""
|
2014-01-09 00:57:37 +00:00
|
|
|
Called when handle_client_connection raises an exception.
|
2012-06-18 21:42:32 +00:00
|
|
|
"""
|
2012-07-10 04:22:45 +00:00
|
|
|
# If a thread has persisted after interpreter exit, the module might be
|
2012-07-20 02:43:51 +00:00
|
|
|
# none.
|
2012-07-10 04:22:45 +00:00
|
|
|
if traceback:
|
|
|
|
exc = traceback.format_exc()
|
2014-09-28 01:15:26 +00:00
|
|
|
print('-' * 40, file=fp)
|
2014-09-06 23:24:41 +00:00
|
|
|
print(
|
|
|
|
"Error in processing of request from %s:%s" % (
|
|
|
|
client_address.host, client_address.port
|
|
|
|
), file=fp)
|
2014-09-03 15:15:50 +00:00
|
|
|
print(exc, file=fp)
|
2014-09-28 01:15:26 +00:00
|
|
|
print('-' * 40, file=fp)
|
2012-06-18 21:42:32 +00:00
|
|
|
|
2014-02-15 22:16:28 +00:00
|
|
|
def handle_client_connection(self, conn, client_address): # pragma: no cover
|
2012-06-18 21:42:32 +00:00
|
|
|
"""
|
|
|
|
Called after client connection.
|
|
|
|
"""
|
|
|
|
raise NotImplementedError
|
|
|
|
|
|
|
|
def handle_shutdown(self):
|
|
|
|
"""
|
|
|
|
Called after server shutdown.
|
|
|
|
"""
|
|
|
|
pass
|