I wrote a python script I am calling rbl-check to be used from a TMDA filter via pipe to check mails that are forwarded to my accounts from other servers and so far so good. I thought it would be of use to others with forwarded mail and fetchmail users. YMMV

I'm sure it could be better but I'm just learning python. :)

#!/usr/bin/env python
#
# rbl-check: Check an email message from stdin for an RBL host
#            and return 1 if not found
#            Check all of the received lines
# rbl-check [dnsbl-list-file]
# Optional dnsbl-list-file shout have one RBL server per line
# 
# Portions stolen from:
# TMDA       http://tmda.net
# rbl-lookup http://hacks.u--3.com
# 
# GPL License - http://www.gnu.org/copyleft/gpl.html
# Use at your own risk!

import os
import sys

try:
    import paths
except ImportError:
    # Prepend /usr/lib/python2.x/site-packages/TMDA/pythonlib
    sitedir = os.path.join(sys.prefix, 'lib', 'python'+sys.version[:3],
                           'site-packages', 'TMDA', 'pythonlib')
    sys.path.insert(0, sitedir)

import string
import email
import fileinput
from cStringIO import StringIO
import re
import socket

rbls = []
if len(sys.argv)>1:
    try:
        for line in fileinput.input(sys.argv[1]):
            line = string.strip(line)
            if len(line)>0:
                rbls.append(line)
    except:
        pass

if len(rbls)<1:
    rbls = ['sbl.spamhaus.org','list.dsbl.org','bl.spamcop.net']

msg = email.message_from_file(StringIO(sys.stdin.read()))


def ip_ok(x):
    octets = string.split(x, '.')
    if len(octets) != 4:
        return 0
    for o in octets:
        try:
            o = int(o)
        except ValueError:
            return 0
        if not (0 <= o < 256):
            return 0
    if octets[0] == '10':
        return 0
    if octets[0] == '192' and octets[1] == '168':
        return 0
    return 1


def parse_received(l):
    l = string.join(string.split(l))
    mo = re.match(
        r'''
        from\s+
        (?:
          (\S+)\s+ # hostname + trailing space
          \(       # opening bracket
          (?:\S+\s+)?# maybe hostname and space
        )?
        (?:[\d\w:]+@)?\[(\d+.\d+.\d+.\d+)\]
        ''',
        l, re.IGNORECASE | re.VERBOSE)
    if mo and ip_ok(mo.group(2)):
        return mo.groups()
    else:
        return (None, None)


def lookup(ip, domain):
    foo = string.split(ip, '.')
    foo.reverse()
    rip = string.join(foo, '.')
    pala = rip + '.' + domain
    try:
        r = socket.gethostbyname(pala)
        if r:
            ret = 1
        else:
            ret = 0
    except socket.error, why:
        ret = 0
    return ret


def main():
    blacklisted = 0
    relays = map(parse_received,msg.get_all('received'))
    for domain,host in relays:
        if host:
            for rbl in rbls:
                if lookup(host,rbl):
                    blacklisted = 1
                    break
        if blacklisted:
            break
    if blacklisted:
        sys.exit(0)
    else:
        sys.exit(1)


if __name__ == '__main__':
    main()

Reply via email to