diff --git a/setup.py b/setup.py index 0d7d4e4e..17c01904 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,7 @@ setup(name='python-slimta', - version='4.0.2', + version='4.0.3', author='Ian Good', author_email='icgood@gmail.com', description='Lightweight, asynchronous SMTP libraries.', diff --git a/slimta/edge/smtp.py b/slimta/edge/smtp.py index 78b92431..c35a6433 100644 --- a/slimta/edge/smtp.py +++ b/slimta/edge/smtp.py @@ -248,7 +248,7 @@ def handle(self, socket, address): smtp_server = None try: handlers = SmtpSession(address, self.validator_class, self.handoff) - smtp_server = Server(socket, handlers, self.auth, + smtp_server = Server(socket, handlers, address, self.auth, self.context, self.tls_immediately, command_timeout=self.command_timeout, data_timeout=self.data_timeout) diff --git a/slimta/smtp/io.py b/slimta/smtp/io.py index 810174af..c897c8fd 100644 --- a/slimta/smtp/io.py +++ b/slimta/smtp/io.py @@ -72,6 +72,8 @@ def close(self): if self.encrypted: try: self.socket.unwrap() + except ValueError: + pass except SSLWantReadError: pass except socket_error as e: diff --git a/slimta/smtp/server.py b/slimta/smtp/server.py index 9ed49417..b70add4e 100644 --- a/slimta/smtp/server.py +++ b/slimta/smtp/server.py @@ -75,6 +75,7 @@ class Server(object): corresponding SMTP commands are received. These methods can modify the |Reply| before the command response is sent. + :param address: The address of the connected client. :param auth: If True, enable authentication with default mechanisms. May also be given as a list of SASL mechanism names to support, e.g. ``['PLAIN', 'LOGIN', 'CRAM-MD5']``. @@ -90,13 +91,13 @@ class Server(object): """ - def __init__(self, socket, handlers, auth=False, + def __init__(self, socket, handlers, address=None, auth=False, context=None, tls_immediately=False, command_timeout=None, data_timeout=None): self.handlers = handlers self.extensions = Extensions() - self.io = IO(socket) + self.io = IO(socket, address) self.bannered = False self.have_mailfrom = None diff --git a/slimta/util/proxyproto.py b/slimta/util/proxyproto.py index e270ede4..79b157ea 100644 --- a/slimta/util/proxyproto.py +++ b/slimta/util/proxyproto.py @@ -32,6 +32,7 @@ from gevent import socket +from slimta.edge import EdgeServer from slimta.logging import getSocketLogger __all__ = ['ProxyProtocol', 'ProxyProtocolV1', 'ProxyProtocolV2'] @@ -157,6 +158,22 @@ def process_pp_v1(cls, sock, initial): log.recv(sock, line) return cls.parse_pp_line(line) + @classmethod + def mixin(cls, edge): + """Dynamically mix-in the :class:`ProxyProtocolV1` class as a base of + the given edge object. Use with caution. + + :param edge: the edge object to use proxy protocol on. + :type edge: :class:`~slimta.edge.EdgeServer` + :raises: ValueError + + """ + if not isinstance(edge, EdgeServer): + raise ValueError(edge) + old_class = edge.__class__ + new_class_name = cls.__name__ + old_class.__name__ + edge.__class__ = type(new_class_name, (cls, old_class), {}) + def handle(self, sock, addr): """Intercepts calls to :meth:`~slimta.edge.EdgeServer.handle`, reads the proxy protocol header, and then resumes the original call. @@ -209,32 +226,32 @@ def __read_pp_data(cls, sock, length, initial): def __parse_pp_data(cls, data): assert data[0:12] == b'\r\n\r\n\x00\r\nQUIT\n', \ 'Invalid proxy protocol v2 signature' - assert data[13] & 0xf0 == 0x20, 'Invalid proxy protocol version' + assert data[12] & 0xf0 == 0x20, 'Invalid proxy protocol version' command = cls.__commands.get(data[12] & 0x0f) family = cls.__families.get(data[13] & 0xf0) protocol = cls.__protocols.get(data[13] & 0x0f) - addr_len = struct.unpack('