commit 012ef1a4020c5d7b70f027a0184d32b440c7babb Author: Cecylia Bocovich cohosh@torproject.org Date: Mon May 25 11:06:57 2020 -0400
Check to see if email is from an autoresponder
This checks to see if an incoming request is from a known autoresponder. GetTor can get into infinite loops with itself or postmaster addresses (Bug #34286) --- gettor/parse/email.py | 4 ++-- gettor/utils/validate_email.py | 21 +++++++++++++++++++++ tests/test_email_service.py | 17 ++++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-)
diff --git a/gettor/parse/email.py b/gettor/parse/email.py index d37614d..41b34ce 100644 --- a/gettor/parse/email.py +++ b/gettor/parse/email.py @@ -86,8 +86,8 @@ class EmailParser(object): )
# Add a check for auto-generated mail-daemon emails - if "mailer-daemon@" in norm_addr.lower(): - raise AddressError("Received mail from Mail Delivery System {}" + if validate_email.autoresponder(norm_addr): + raise AddressError("Received mail from a known autoresponder {}" .format(msg['From'])) return True
diff --git a/gettor/utils/validate_email.py b/gettor/utils/validate_email.py index 0f18e3e..337849e 100644 --- a/gettor/utils/validate_email.py +++ b/gettor/utils/validate_email.py @@ -96,6 +96,13 @@ MX_DNS_CACHE = {} MX_CHECK_CACHE = {}
+# List of known autoresponder email patterns +autoresponders = [ + r'mailer-daemon@.*', + r'postmaster@.*', + r'gettor.*@torproject.org' +] + def get_mx_ip(hostname): if hostname not in MX_DNS_CACHE: try: @@ -176,6 +183,20 @@ def validate_email(email, check_mx=False, verify=False, debug=False, smtp_timeou return None return True
+def autoresponder(from_addr): + """ + We sometimes receive messages from autoresponders like Mail Deliver System + or postmaster due to bounced messages. This can send GetTor into an infinite + loop with the autoresponder (or itself). + + Returns true if the email address matches a known autoresponder pattern. + """ + for pattern in autoresponders: + if re.match(pattern, from_addr.lower()) is not None: + return True + + return False + if __name__ == "__main__": import time while True: diff --git a/tests/test_email_service.py b/tests/test_email_service.py index a41669f..47d7e5f 100644 --- a/tests/test_email_service.py +++ b/tests/test_email_service.py @@ -289,13 +289,28 @@ class EmailServiceTests(unittest.TestCase): ">\n") self.assertEqual(request["command"], "help")
- def test_bounce(self): + def test_from_autoresponder(self): ep = conftests.EmailParser(self.settings, "gettor@torproject.org") request = ep.parse("From: MAILER-DAEMON@mx1.riseup.net\n" "Subject: Undelivered Mail Returned to Sender\r\n" "To: gettor@torproject.org\n osx en\n")
self.assertEqual(request, {}) + request = ep.parse("From: postmaster@example.sk\n" + "Subject: Undelivered Mail Returned to Sender\r\n" + "To: gettor@torproject.org\n\n osx en\n") + + self.assertEqual(request, {}) + request = ep.parse("From: gettor@torproject.org\n" + "Subject: links\r\n" + "To: gettor@torproject.org\n\n osx en\n") + + self.assertEqual(request, {}) + request = ep.parse("From: gettor+en@torproject.org\n" + "Subject: links\r\n" + "To: gettor@torproject.org\n\n osx en\n") + + self.assertEqual(request, {})
if __name__ == "__main__": unittest.main()
tor-commits@lists.torproject.org