#!/usr/bin/env python
#
# Help hunt down spammers.  My mutt macros are:
#
#   macro pager H |spamhunter.py\n
#   macro index H |spamhunter.py\n
#
# Received lines are printed along with information on each IP address
# found.  Email can quickly be sent to relay or originating domains.  If
# the @ sign is left off an address abuse.net used to find the correct
# address (you need to register).  Also, if desired, an IP can be
# submitted to the RSS database.
#
# Go forth and cancel spammer accounts.
#
#
# April 19, 2000
# Neil Schemenauer <nas@arctrix.com>
# Placed in the Public Domain

# your from address (change this)
FROM='spam-hater@example.com'

RELAY_MESSAGE = """\
I think your mail server may be being used as an unsolicited email
relay.  You may wish to check it out (http://maps.vix.com/tsi/).
I have attached a copy of the email with the complete headers for
reference.  Thank you for your time.
"""

ABUSE_MESSAGE = """\
I believe one of your users or customers is sending unsolicited
email from your network.  I have attached a copy of the email
with the complete headers for reference.  Thank you for your
time.
"""

# for rblcheck
BLACKLISTS = [
    'relays.ordb.org',
    'inputs.orbz.org',
    'outputs.orbz.org',
    'dns.rfc-ignorant.org',
    'postmaster.rfc-ignorant.org',
    'spamhaus.relays.osirusoft.com',
    ]

# ip addresses to skip (add known networks here)
SKIP = [
    '127.0.',
    '192.168.',
    '10.'
    ]

import re
import string
import sys
import os
import socket
import time

def sendmail(message, subject, attachement, address):
    date = time.strftime("%a, %d %b %Y %T GMT", time.gmtime(time.time()))
    message = ("From: %s\n"
               "To: %s\n"
               "Date: %s\n"
               "Subject: %s\n"
               "\n"
               "%s\n"
               "--- message follows ---\n"
               "%s") % (FROM, address, date, subject, message, attachement)
    p = os.popen('sendmail %s' % address, 'w')
    p.write(message)
    p.close()

def resolve(ip):
    try:
        host = socket.gethostbyaddr(ip)
    except socket.error:
        return "???"
    return host[0]

def check(ip):
    for domain in BLACKLISTS:
        l = string.split(ip, ".")
        l.reverse()
        l.append(domain)
        host = string.join(l, ".")
        try:
            addr = socket.gethostbyname(host)
        except socket.error:
            continue
        if addr:
            return domain
    return ""


def main():
    ip_re = re.compile(r'(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})')
    message = sys.stdin.readlines()
    ips = []
    header = None
    subject = 'Email Abuse'
    for line in message:
        if not string.rstrip(line):
            break # end of headers
        m = re.search('^([^:\t ]+):[ \t](.*)', line)
        if m:
            header = string.lower(m.group(1))
            if header == 'subject':
                subject = '[Email Abuse] %s' % m.group(2)
        if header == 'received':
            sys.stdout.write(line)
            for ip in ip_re.findall(line):
                if not ip in ips:
                    ips.append(ip)

    # print info on IP addresses found
    print
    for ip in ips:
        skip = 0
        for p in SKIP:
            if ip[:len(p)] == p:
                skip = 1
                break
        if not skip:
            print '%16s %s %s' % (ip, resolve(ip), check(ip))
    print

    spam = string.join(message, '')

    # this is required because of the way mutt pipes messages
    sys.stdin = open('/dev/tty')

    if raw_input("Report spammer [y/N]? ") in ("y", "Y"):
        # send to relay admin
        address = raw_input('Relay Address or Domain (nothing to skip): ')
        if address:
            if '@' not in address:
                address = address + '@abuse.net'
            sendmail(RELAY_MESSAGE, subject, spam, address)
            # send to RSS
            ip = raw_input('Relay IP for RSS (nothing to skip): ')
            if '.' in ip:
                sendmail('Relay: %s\n' % ip, subject, spam,
                         'relays@mail-abuse.org')

        # send to source admin
        address = raw_input('Abuse Address or Domain (nothing to skip): ')
        if address:
            if '@' not in address:
                address = address + '@abuse.net'
            sendmail(ABUSE_MESSAGE, subject, spam, address)

main()
