Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

proxy server commits #4

Merged
merged 1 commit into from

2 participants

@cltrudeau
Collaborator

Commits we discussed.

@bcoe bcoe referenced this pull request from a commit
@bcoe Pulling in proxy server from cltrudeau. I've changed naming conventio…
…ns from camel case and renamed proxy to proxy_server and added argparse to setup.py so that the projedt is compatible with python 2.x. see #4
26ebfd8
@bcoe bcoe merged commit 6c175c3 into bcoe:master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
53 examples/mail_relay.py
@@ -0,0 +1,53 @@
+#!/usr/bin/env python
+
+import argparse
+from secure_smtpd import ProxyServer
+import asyncore
+
+def run(cmdargs):
+ args = [
+ (cmdargs.localhost, cmdargs.localport),
+ (cmdargs.remotehost, cmdargs.remoteport)
+ ]
+ kwargs = {}
+
+ if cmdargs.sslboth:
+ kwargs['ssl'] = True
+ elif cmdargs.sslout:
+ kwargs['sslOutOnly'] = True
+
+ if not cmdargs.quiet:
+ kwargs['printDebug'] = True
+
+ ProxyServer(*args, **kwargs)
+ asyncore.loop()
+
+parser = argparse.ArgumentParser(description='mail relay tool')
+parser.add_argument('--localhost', default='127.0.0.1',
+ help='Local address to attach to for receiving mail. Defaults to ' +\
+ '127.0.0.1')
+parser.add_argument('--localport', default=1025, type=int,
+ help='Local port to attach to for receiving mail. Defaults to 1025')
+parser.add_argument('--remotehost', required=True,
+ help='Address of the remote server for connection.')
+parser.add_argument('--remoteport', default=25, type=int,
+ help='Port of the remote server for connection. Defaults to 25')
+parser.add_argument('--quiet', action='store_true',
+ help='Use this to turn off the message printing')
+group = parser.add_mutually_exclusive_group()
+group.add_argument('--sslboth', action='store_true',
+ help='Use this parameter if both the inbound and outbound connections ' +\
+ 'should use SSL')
+group.add_argument('--sslout', action='store_true',
+ help='Use this parameter if inbound connection is plain but the ' +\
+ 'outbound connection uses SSL')
+
+args = parser.parse_args()
+
+print 'Starting ProxyServer'
+print 'local: %s:%s' % (args.localhost, args.localport)
+print 'remote: %s:%s' % (args.remotehost, args.remoteport)
+print 'sslboth: ', args.sslboth
+print 'sslout: ', args.sslout
+print
+run(args)
View
92 secure_smtpd/proxy.py
@@ -0,0 +1,92 @@
+import secure_smtpd
+
+from smtp_server import SMTPServer
+from store_credentials import StoreCredentials
+
+class ProxyServer(SMTPServer):
+ """Implements an open relay. Inherits from secure_smtpd, so can handle
+ SSL incoming. Modifies attributes slightly:
+
+ * if "ssl" is true accepts SSL connections inbound and connects via SSL
+ outbound
+ * adds "sslOutOnly", which can be set to True when "ssl" is False so that
+ inbound connections are in plain text but outbound are in SSL
+ * adds "printDebug", which if True prints all inbound messages to stdout
+ * ignores any credential validators, passing any credentials upstream
+ """
+ def __init__(self, *args, **kwargs):
+ self.sslOutOnly = False
+ if kwargs.has_key('sslOutOnly'):
+ self.sslOutOnly = kwargs.pop('sslOutOnly')
+
+ self.printDebug = False
+ if kwargs.has_key('printDebug'):
+ self.printDebug = kwargs.pop('printDebug')
+
+ kwargs['credential_validator'] = StoreCredentials()
+ SMTPServer.__init__(self, *args, **kwargs)
+
+ def process_message(self, peer, mailfrom, rcpttos, data):
+ if self.printDebug:
+ # ------------------------
+ # stolen directly from stmpd.DebuggingServer
+ inheaders = 1
+ lines = data.split('\n')
+ print '---------- MESSAGE FOLLOWS ----------'
+ for line in lines:
+ # headers first
+ if inheaders and not line:
+ print 'X-Peer:', peer[0]
+ inheaders = 0
+ print line
+ print '------------ END MESSAGE ------------'
+
+ # ------------------------
+ # following code is direct from smtpd.PureProxy
+ lines = data.split('\n')
+ # Look for the last header
+ i = 0
+ for line in lines:
+ if not line:
+ break
+ i += 1
+ lines.insert(i, 'X-Peer: %s' % peer[0])
+ data = '\n'.join(lines)
+ self._deliver(mailfrom, rcpttos, data)
+
+ def _deliver(self, mailfrom, rcpttos, data):
+ # ------------------------
+ # following code is adapted from smtpd.PureProxy with modifications to
+ # handle upstream SSL
+
+ import smtplib
+ refused = {}
+ try:
+ if self.ssl or self.sslOutOnly:
+ s = smtplib.SMTP_SSL()
+ else:
+ s = smtplib.SMTP()
+
+ s.connect(self._remoteaddr[0], self._remoteaddr[1])
+ if self.credential_validator.stored:
+ # we had credentials passed in, use them
+ s.login(self.credential_validator.username,
+ self.credential_validator.password)
+ try:
+ refused = s.sendmail(mailfrom, rcpttos, data)
+ print 'refused: ', refused
+ finally:
+ s.quit()
+ except smtplib.SMTPRecipientsRefused, e:
+ print '********* ERROR: got SMTPRecipientsRefused'
+ refused = e.recipients
+ except (socket.error, smtplib.SMTPException), e:
+ print '********* ERROR: got', e.__class__
+ # All recipients were refused. If the exception had an associated
+ # error code, use it. Otherwise,fake it with a non-triggering
+ # exception code.
+ errcode = getattr(e, 'smtp_code', -1)
+ errmsg = getattr(e, 'smtp_error', 'ignore')
+ for r in rcpttos:
+ refused[r] = (errcode, errmsg)
+ return refused
View
11 secure_smtpd/store_credentials.py
@@ -0,0 +1,11 @@
+class StoreCredentials(object):
+ def __init__(self):
+ self.stored = False
+ self.username = None
+ self.password = None
+
+ def validate(self, username, password):
+ self.stored = True
+ self.username = username
+ self.password = password
+ return True
Something went wrong with that request. Please try again.