2015-08-31 11:43:30 +00:00
|
|
|
from __future__ import (absolute_import, print_function, division)
|
2015-08-15 15:43:46 +00:00
|
|
|
|
2014-03-09 20:13:08 +00:00
|
|
|
import copy
|
|
|
|
import os
|
2015-08-15 15:43:46 +00:00
|
|
|
|
2014-03-10 21:36:47 +00:00
|
|
|
from netlib import tcp, certutils
|
2014-03-09 20:13:08 +00:00
|
|
|
from .. import stateobject, utils
|
|
|
|
|
2014-03-09 20:51:24 +00:00
|
|
|
|
2014-09-16 23:35:14 +00:00
|
|
|
class ClientConnection(tcp.BaseHandler, stateobject.StateObject):
|
2014-03-09 20:13:08 +00:00
|
|
|
def __init__(self, client_connection, address, server):
|
2015-05-30 00:03:28 +00:00
|
|
|
# Eventually, this object is restored from state. We don't have a
|
|
|
|
# connection then.
|
|
|
|
if client_connection:
|
2015-08-29 23:21:58 +00:00
|
|
|
super(ClientConnection, self).__init__(client_connection, address, server)
|
2014-03-09 20:13:08 +00:00
|
|
|
else:
|
|
|
|
self.connection = None
|
|
|
|
self.server = None
|
|
|
|
self.wfile = None
|
|
|
|
self.rfile = None
|
|
|
|
self.address = None
|
|
|
|
self.clientcert = None
|
2014-08-17 23:47:39 +00:00
|
|
|
self.ssl_established = None
|
2014-03-09 20:13:08 +00:00
|
|
|
|
|
|
|
self.timestamp_start = utils.timestamp()
|
|
|
|
self.timestamp_end = None
|
|
|
|
self.timestamp_ssl_setup = None
|
2015-07-30 11:52:50 +00:00
|
|
|
self.protocol = None
|
2014-03-09 20:13:08 +00:00
|
|
|
|
2015-08-18 12:15:08 +00:00
|
|
|
def __nonzero__(self):
|
|
|
|
return bool(self.connection) and not self.finished
|
|
|
|
|
2014-08-17 22:55:30 +00:00
|
|
|
def __repr__(self):
|
2015-11-26 22:15:21 +00:00
|
|
|
return "<ClientConnection: {ssl}{address}>".format(
|
2014-08-17 22:55:30 +00:00
|
|
|
ssl="[ssl] " if self.ssl_established else "",
|
2015-11-26 22:15:21 +00:00
|
|
|
address=repr(self.address)
|
2014-08-17 22:55:30 +00:00
|
|
|
)
|
|
|
|
|
2015-08-08 14:08:57 +00:00
|
|
|
@property
|
|
|
|
def tls_established(self):
|
|
|
|
return self.ssl_established
|
|
|
|
|
2014-03-09 20:13:08 +00:00
|
|
|
_stateobject_attributes = dict(
|
2014-08-17 23:47:39 +00:00
|
|
|
ssl_established=bool,
|
2014-03-09 20:13:08 +00:00
|
|
|
timestamp_start=float,
|
|
|
|
timestamp_end=float,
|
|
|
|
timestamp_ssl_setup=float
|
|
|
|
)
|
|
|
|
|
2014-09-17 01:58:56 +00:00
|
|
|
def get_state(self, short=False):
|
|
|
|
d = super(ClientConnection, self).get_state(short)
|
2014-03-09 20:13:08 +00:00
|
|
|
d.update(
|
2015-10-08 10:43:55 +00:00
|
|
|
address=({
|
2015-05-30 00:03:28 +00:00
|
|
|
"address": self.address(),
|
2015-10-08 10:43:55 +00:00
|
|
|
"use_ipv6": self.address.use_ipv6} if self.address else {}),
|
2015-05-30 00:03:28 +00:00
|
|
|
clientcert=self.cert.to_pem() if self.clientcert else None)
|
2014-03-09 20:13:08 +00:00
|
|
|
return d
|
|
|
|
|
2014-09-16 23:35:14 +00:00
|
|
|
def load_state(self, state):
|
|
|
|
super(ClientConnection, self).load_state(state)
|
2015-05-30 00:03:28 +00:00
|
|
|
self.address = tcp.Address(
|
|
|
|
**state["address"]) if state["address"] else None
|
|
|
|
self.clientcert = certutils.SSLCert.from_pem(
|
|
|
|
state["clientcert"]) if state["clientcert"] else None
|
2014-03-09 20:13:08 +00:00
|
|
|
|
|
|
|
def copy(self):
|
|
|
|
return copy.copy(self)
|
|
|
|
|
|
|
|
def send(self, message):
|
2015-07-30 11:52:50 +00:00
|
|
|
if isinstance(message, list):
|
|
|
|
message = b''.join(message)
|
2014-03-09 20:13:08 +00:00
|
|
|
self.wfile.write(message)
|
|
|
|
self.wfile.flush()
|
|
|
|
|
|
|
|
@classmethod
|
2014-09-16 23:35:14 +00:00
|
|
|
def from_state(cls, state):
|
2014-03-09 20:13:08 +00:00
|
|
|
f = cls(None, tuple(), None)
|
2014-09-16 23:35:14 +00:00
|
|
|
f.load_state(state)
|
2014-03-09 20:13:08 +00:00
|
|
|
return f
|
|
|
|
|
|
|
|
def convert_to_ssl(self, *args, **kwargs):
|
2015-08-29 23:21:58 +00:00
|
|
|
super(ClientConnection, self).convert_to_ssl(*args, **kwargs)
|
2014-03-09 20:13:08 +00:00
|
|
|
self.timestamp_ssl_setup = utils.timestamp()
|
|
|
|
|
|
|
|
def finish(self):
|
2015-08-29 23:21:58 +00:00
|
|
|
super(ClientConnection, self).finish()
|
2014-03-09 20:13:08 +00:00
|
|
|
self.timestamp_end = utils.timestamp()
|
|
|
|
|
|
|
|
|
2014-09-16 23:35:14 +00:00
|
|
|
class ServerConnection(tcp.TCPClient, stateobject.StateObject):
|
2016-01-08 14:46:59 +00:00
|
|
|
def __init__(self, address, source_address=None):
|
|
|
|
if source_address:
|
|
|
|
source_address = (source_address, 0)
|
|
|
|
tcp.TCPClient.__init__(self, address, source_address)
|
2014-03-09 20:13:08 +00:00
|
|
|
|
2015-08-18 12:15:08 +00:00
|
|
|
self.via = None
|
2014-03-09 20:13:08 +00:00
|
|
|
self.timestamp_start = None
|
|
|
|
self.timestamp_end = None
|
|
|
|
self.timestamp_tcp_setup = None
|
|
|
|
self.timestamp_ssl_setup = None
|
2015-07-30 11:52:50 +00:00
|
|
|
self.protocol = None
|
2014-03-09 20:13:08 +00:00
|
|
|
|
2015-08-16 21:25:02 +00:00
|
|
|
def __nonzero__(self):
|
2015-08-18 12:15:08 +00:00
|
|
|
return bool(self.connection) and not self.finished
|
2015-08-16 21:25:02 +00:00
|
|
|
|
2014-08-17 22:55:30 +00:00
|
|
|
def __repr__(self):
|
|
|
|
if self.ssl_established and self.sni:
|
|
|
|
ssl = "[ssl: {0}] ".format(self.sni)
|
|
|
|
elif self.ssl_established:
|
|
|
|
ssl = "[ssl] "
|
|
|
|
else:
|
|
|
|
ssl = ""
|
2015-11-26 22:15:21 +00:00
|
|
|
return "<ServerConnection: {ssl}{address}>".format(
|
2014-08-17 22:55:30 +00:00
|
|
|
ssl=ssl,
|
2015-11-26 22:15:21 +00:00
|
|
|
address=repr(self.address)
|
2014-08-17 22:55:30 +00:00
|
|
|
)
|
|
|
|
|
2015-08-08 14:08:57 +00:00
|
|
|
@property
|
|
|
|
def tls_established(self):
|
|
|
|
return self.ssl_established
|
|
|
|
|
2014-03-09 20:13:08 +00:00
|
|
|
_stateobject_attributes = dict(
|
|
|
|
timestamp_start=float,
|
|
|
|
timestamp_end=float,
|
|
|
|
timestamp_tcp_setup=float,
|
|
|
|
timestamp_ssl_setup=float,
|
|
|
|
address=tcp.Address,
|
|
|
|
source_address=tcp.Address,
|
|
|
|
cert=certutils.SSLCert,
|
|
|
|
ssl_established=bool,
|
|
|
|
sni=str
|
|
|
|
)
|
2014-09-17 15:30:19 +00:00
|
|
|
_stateobject_long_attributes = {"cert"}
|
2014-03-09 20:13:08 +00:00
|
|
|
|
2014-09-17 01:58:56 +00:00
|
|
|
def get_state(self, short=False):
|
|
|
|
d = super(ServerConnection, self).get_state(short)
|
2014-03-09 20:13:08 +00:00
|
|
|
d.update(
|
2015-10-08 00:30:31 +00:00
|
|
|
address=({"address": self.address(),
|
2015-10-08 10:43:55 +00:00
|
|
|
"use_ipv6": self.address.use_ipv6} if self.address else {}),
|
2015-08-16 21:25:02 +00:00
|
|
|
source_address=({"address": self.source_address(),
|
|
|
|
"use_ipv6": self.source_address.use_ipv6} if self.source_address else None),
|
2014-03-09 20:13:08 +00:00
|
|
|
cert=self.cert.to_pem() if self.cert else None
|
|
|
|
)
|
|
|
|
return d
|
|
|
|
|
2014-09-16 23:35:14 +00:00
|
|
|
def load_state(self, state):
|
|
|
|
super(ServerConnection, self).load_state(state)
|
2014-03-09 20:13:08 +00:00
|
|
|
|
2015-05-30 00:03:28 +00:00
|
|
|
self.address = tcp.Address(
|
|
|
|
**state["address"]) if state["address"] else None
|
|
|
|
self.source_address = tcp.Address(
|
|
|
|
**state["source_address"]) if state["source_address"] else None
|
|
|
|
self.cert = certutils.SSLCert.from_pem(
|
|
|
|
state["cert"]) if state["cert"] else None
|
2014-03-09 20:13:08 +00:00
|
|
|
|
|
|
|
@classmethod
|
2014-09-16 23:35:14 +00:00
|
|
|
def from_state(cls, state):
|
2014-09-03 18:12:30 +00:00
|
|
|
f = cls(tuple())
|
2014-09-16 23:35:14 +00:00
|
|
|
f.load_state(state)
|
2014-03-09 20:13:08 +00:00
|
|
|
return f
|
|
|
|
|
|
|
|
def copy(self):
|
|
|
|
return copy.copy(self)
|
|
|
|
|
|
|
|
def connect(self):
|
|
|
|
self.timestamp_start = utils.timestamp()
|
|
|
|
tcp.TCPClient.connect(self)
|
|
|
|
self.timestamp_tcp_setup = utils.timestamp()
|
|
|
|
|
|
|
|
def send(self, message):
|
2015-07-30 11:52:50 +00:00
|
|
|
if isinstance(message, list):
|
|
|
|
message = b''.join(message)
|
2014-03-09 20:13:08 +00:00
|
|
|
self.wfile.write(message)
|
|
|
|
self.wfile.flush()
|
|
|
|
|
2014-12-15 11:46:13 +00:00
|
|
|
def establish_ssl(self, clientcerts, sni, **kwargs):
|
2014-03-09 20:13:08 +00:00
|
|
|
clientcert = None
|
|
|
|
if clientcerts:
|
2015-12-28 20:20:45 +00:00
|
|
|
if os.path.isfile(clientcerts):
|
|
|
|
clientcert = clientcerts
|
|
|
|
else:
|
|
|
|
path = os.path.join(
|
|
|
|
clientcerts,
|
|
|
|
self.address.host.encode("idna")) + ".pem"
|
|
|
|
if os.path.exists(path):
|
|
|
|
clientcert = path
|
2015-07-27 09:46:49 +00:00
|
|
|
|
2015-08-01 08:41:21 +00:00
|
|
|
self.convert_to_ssl(cert=clientcert, sni=sni, **kwargs)
|
2014-12-15 11:46:13 +00:00
|
|
|
self.sni = sni
|
2014-09-02 16:13:18 +00:00
|
|
|
self.timestamp_ssl_setup = utils.timestamp()
|
2014-03-09 20:13:08 +00:00
|
|
|
|
|
|
|
def finish(self):
|
|
|
|
tcp.TCPClient.finish(self)
|
2014-09-16 23:35:14 +00:00
|
|
|
self.timestamp_end = utils.timestamp()
|
2015-08-18 12:15:08 +00:00
|
|
|
|
2015-08-30 13:27:29 +00:00
|
|
|
|
2015-08-19 13:23:52 +00:00
|
|
|
ServerConnection._stateobject_attributes["via"] = ServerConnection
|