Enhancement: Sanity Check Subscribers MX Record

Bug #1287604 reported by John Howe
6
This bug affects 1 person
Affects Status Importance Assigned to Milestone
GNU Mailman
Undecided
Unassigned

Bug Description

Attempted to path mailman 2.1.17 with a simple MX record check on web-based subscribers.

Running Debian 7.4
python 2.7.3-4+deb7u1
python-dns 2.3.6-1+deb7u1

Python-dns installed to /usr/lib/python2.7/dist-packages/DNS

Attempted patches follow

dragon@quantum:/usr/local/mailman/Mailman/Cgi
$ diff subscribe.py subscribe.py.dns
212a213,221
> except Errors.MMBadEmailHostNotFoundError:
> results = _("""\
> The email address you supplied is not valid. Host not found.""")
> except Errors.MMBadEmailMXRecordNotFoundError:
> results = _("""\
> The email address you supplied does not have a MX record.""")
> except Errors.MMBadEmailUnknownDNSError:
> results = _("""\
> The email address you supplied had some unknown DNS error.""")

dragon@quantum:/usr/local/mailman/Mailman
$ diff Utils.py Utils.py.dns
40a41
> import DNS
237a239,247
> # MX Record sanity checks
> try:
> mx_host - DNS.mxlookup(domain_parts)
> if len(mx_host) < 1:
> raise Errors.MMBadEmailMXRecordNotFoundError, s
> except DNS.Base.ServerError:
> raise Errors.MMBadEmailHostNotFoundError, s
> except:
> raise Errors.MMBadEmailUnknownDNSError, s

dragon@quantum:/usr/local/mailman/Mailman
$ diff Errors.py Errors.py.dns
98a99,110
> class MMBadEmailHostNotFoundError(EmailAddressError):
> """Email address domain name does not resolve to a known host."""
> pass
>
> class MMBadEmailMXRecordNotFoundError(EmailAddressError):
> """Email address domain name does not have a MX record."""
> pass
>
> class MMBadEmailUnknownDNSError(EmailAddressError):
> """Email address domain name had unknown DNS error."""
> pass
>

When running said patches, mailman complained with:

admin(13907): [----- Mailman Version: 2.1.17 -----]
admin(13907): [----- Traceback ------]
admin(13907): Traceback (most recent call last):
admin(13907): File "/usr/local/mailman-2.1.17/scripts/driver", line 102, in run_main
admin(13907): pkg = __import__('Mailman.Cgi', globals(), locals(), [scriptname])
admin(13907): File "/usr/local/mailman-2.1.17/Mailman/Cgi/confirm.py", line 27, in <module>
admin(13907): from Mailman import MailList
admin(13907): File "/usr/local/mailman-2.1.17/Mailman/MailList.py", line 45, in <module>
admin(13907): from Mailman import Utils
admin(13907): File "/usr/local/mailman-2.1.17/Mailman/Utils.py", line 41, in <module>
admin(13907): import DNS
admin(13907): ImportError: No module named DNS
admin(13907): [----- Python Information -----]
admin(13907): sys.version = 2.7.3 (default, Jan 2 2013, 13:56:14)
[GCC 4.7.2]
admin(13907): sys.executable = /usr/bin/python
admin(13907): sys.prefix = /usr
admin(13907): sys.exec_prefix = /usr
admin(13907): sys.path = ['/usr/local/mailman-2.1.17/pythonlib', '/usr/local/mailman-2.1.17', '/usr/local/mailman-2.1.17/scripts', '/usr/local/mailman-2.1.17', '/usr/lib/python2.7/', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/lib/python2.7/site-packages']
admin(13907): sys.platform = linux2

AFAICS, it seems like Utils.py isn't locating the system wide python-dns library.

How do I modify the sys.path to include python-dns under /usr/lib/python2.7/dist-packages?

Thanks

Revision history for this message
Mark Sapiro (msapiro) wrote : Re: [Bug 1287604] [NEW] Enhancement: Sanity Check Subscribers MX Record

> admin(13907): ImportError: No module named DNS
> admin(13907): [----- Python Information -----]
> admin(13907): sys.version = 2.7.3 (default, Jan 2 2013, 13:56:14)
> [GCC 4.7.2]
> admin(13907): sys.executable = /usr/bin/python
> admin(13907): sys.prefix = /usr
> admin(13907): sys.exec_prefix = /usr
> admin(13907): sys.path = ['/usr/local/mailman-2.1.17/pythonlib', '/usr/local/mailman-2.1.17', '/usr/local/mailman-2.1.17/scripts', '/usr/local/mailman-2.1.17', '/usr/lib/python2.7/', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/lib/python2.7/site-packages']
> admin(13907): sys.platform = linux2
>
> AFAICS, it seems like Utils.py isn't locating the system wide python-dns
> library.

Correct. sys.path does not include /usr/lib/python2.7/dist-packages/

> How do I modify the sys.path to include python-dns under
> /usr/lib/python2.7/dist-packages?

sys.path.append('/usr/lib/python2.7/dist-packages/')

However, this should not be necessary as
'/usr/lib/python2.7/dist-packages/' should already be included in
sys.path. Why it isn't is a Python question, but
/usr/lib/python2.7/site.py which is normally executed during python
startup should put it there. What do you see if you invoke an
interactive python session and import sys and print sys.path as in

$ python
Python 2.7.5+ (default, Feb 27 2014, 19:37:08)
[GCC 4.8.1] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.path
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-x86_64-linux-gnu',
'/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old',
'/usr/lib/python2.7/lib-dynload',
'/usr/local/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages',
'/usr/lib/python2.7/dist-packages/PILcompat',
'/usr/lib/python2.7/dist-packages/gtk-2.0',
'/usr/lib/pymodules/python2.7',
'/usr/lib/python2.7/dist-packages/ubuntu-sso-client',
'/usr/lib/python2.7/dist-packages/ubuntuone-client',
'/usr/lib/python2.7/dist-packages/ubuntuone-control-panel',
'/usr/lib/python2.7/dist-packages/ubuntuone-storage-protocol']
>>>

--
Mark Sapiro <email address hidden> The highway is for gamblers,
San Francisco Bay Area, California better use your sense - B. Dylan

Revision history for this message
John Howe (johnhowe-x) wrote :

Hrmm,

dragon@quantum:/usr/local/mailman/Mailman
$ python
Python 2.7.3 (default, Jan 2 2013, 13:56:14)
[GCC 4.7.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys
>>> print sys.path
['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/pymodules/python2.7']

I symlinked /usr/lib/python2.7/site-packages to /usr/lib/python2.7/dist-packages, since /usr/lib/python2.7/site-packages didn't exist on my install.

I ended up using python-dnspython 1.10.0-1, as it seems cleaner.

Here is what works for me now:

dragon@quantum:/usr/local/mailman/Mailman
$ diff Utils.py.org Utils.py
40a41
> import dns.resolver
237a239,246
> # MX Record sanity checks
> try:
> mx_domain = '.'.join(domain_parts)
> mx_query = dns.resolver.query(mx_domain)
> if len(mx_query) < 1:
> raise Errors.MMHostileAddress, s
> except:
> raise Errors.MMHostileAddress, s

Thanks for the assistance!

Revision history for this message
John Howe (johnhowe-x) wrote :

I adjusted my patch for the mailman-2.1.18-1 distribution, since that distribution requires dnspython as well for DMARC support.

I also corrected the lookup to search for MX records. Previous patch was searching A records incorrectly.

I also added user friendly error messaging for e-mail addresses being submitted with missing MX records.

Revision history for this message
John Howe (johnhowe-x) wrote :

Correct whitespace formatting...

Revision history for this message
Mark Sapiro (msapiro) wrote :

The major issue with your patch is not all valid email domains have MX records. A valid email domain must have either an A record, an AAAA record or an MX record pointing to a host name with an A or AAAA record. E.g., a domain with an MX pointing to a host name with only a CNAME or MX is not a valid email domain, but a domain with only an A or AAAA record is a valid email domain. A domain which has a CNAME is a valid email domain as long as the CNAME directly or indirectly points to a host with an A, AAAA or MX as above. See RFC 5321, Sec 5.1.

Another issue is Mailman tries not to use bare except: clauses to catch exceptions. We prefer to catch only those explicit exceptions which might occur. I.e., in this case, explicitly only those exceptions that might be returned by dns.resolver.query.

To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers