Skip to content

Python Exim

Search Exim logs for sender ip in specific subnet

#!/usr/bin/python3

import os
import re
import ipaddress
from datetime import datetime

## Extract Exim GZ archive logs with command: for f in /var/log/exim4/mainlog.*.gz; do STEM=$(basename "${f}" .gz); gunzip -c "${f}" > /home/username/exim/logs/"${STEM}"; done
log_directory = "/home/username/exim/logs"

## Get this list is subnets now minus limit relay subnets
dropout_subnets = ['192.168.0.0/21', '192.168.8.0/23', '192.168.10.0/24']

# Define the regular expression pattern
pattern = r"(\d{4}-\d{2}-\d{2}).* <= (.*) H=\(?.*\)? \[(.*)\] I.* for (.*)"

matches_not_covered = {}

## Match not in limit relay subnets
for filename in os.listdir(log_directory):
    if not os.path.isfile(os.path.join(log_directory, filename)):
        continue

    log_file = os.path.join(log_directory, filename)
    with open(log_file, "r") as file:
        try:
            for line in file:
                match = re.match(pattern, line)
                if match:
                    date = match.group(1)
                    mail_from = match.group(2)
                    sender_ip = match.group(3)
                    mail_to = match.group(4)
                    for subnet in dropout_subnets:
                        if ipaddress.IPv4Address(sender_ip) in ipaddress.IPv4Network(subnet, strict=False):
                            if sender_ip not in matches_not_covered:
                                print(f'sender ip: {sender_ip} is not in limit relay subnets')
                                print(f'    {line}')
                                matches_not_covered[sender_ip] = (mail_from, mail_to.split(" ")[0], date)
                            if sender_ip in matches_not_covered:
                                if datetime.strptime(date, "%Y-%m-%d") > datetime.strptime(matches_not_covered[sender_ip][2], "%Y-%m-%d"):
                                    matches_not_covered[sender_ip] = (mail_from, mail_to.split(" ")[0], date)
        except:
            continue

# Sort and print the matches
sorted_matches = sorted(matches_not_covered.items(), key=lambda x: x[0])

#### Save to file
file_path = "/home/username/exim/dropouts.txt"

# Open the file in write mode
with open(file_path, "w") as file:
    file.write(f'{"mail_from":<50}{"mail_to":<45}{"sender_ip":<16}{"date":<10}\n')
    for sender_ip, (mail_from, mail_to, date) in sorted_matches:
        file.write(f'{mail_from:<50}{mail_to:<45}{sender_ip:<16}{date:<10}\n')

print(f"Results have been saved to {file_path}")