This repository has been archived on 2025-03-31. You can view files and clone it, but cannot push or open issues or pull requests.
mail-arc/qmail-arc.py
2017-06-29 02:01:49 +02:00

94 lines
2.5 KiB
Python
Executable File

#!/usr/bin/env python2
"""Qmail mail validator
This is a script meant to be used in qmail before forwarding mail to e.g. Gmail. It will verify
the incoming mail against SPF, DKIM and more and add the appropriate ARC headers. This makes Gmail
(probably) accept mails for which there's a DMARC rule with "reject" set.
Inspiration taken from http://bazaar.launchpad.net/~dkimpy-hackers/dkimpy/trunk/view/head:/arcsign.py
"""
from __future__ import print_function
__author__ = "Markus Birth"
import os
import re
import socket
import sys
import authres
import dkim
import spf
AUTHSERV_ID = "uberspace.de" # domain or hostname of mail server
DKIM_DOMAIN = "birth-online.de"
DKIM_SELECTOR = "mbirth"
# pylint: disable=C0103
if sys.version_info[0] >= 3:
# Make sys.stdin and stdout binary streams.
sys.stdin = sys.stdin.detach()
sys.stdout = sys.stdout.detach()
privkey = open('.dkim-privkey', 'rb').read()
message = sys.stdin.read()
up_srv_ip_match = re.search(r"Received: from .* \(HELO (.*)\) \(([0-9.]+)\).*by ", message, re.MULTILINE | re.DOTALL)
up_srv_helo = up_srv_ip_match.group(1).lower()
up_srv_ip = up_srv_ip_match.group(2)
sender_address = os.getenv('SENDER')
### REV IP LOOKUP
iprev_res = "fail"
iprev_hn = "Lookup error"
try:
up_srv_hostn = socket.gethostbyaddr(up_srv_ip)
if up_srv_helo == up_srv_hostn[0]:
iprev_res = "pass"
iprev_hn = up_srv_hostn[0]
else:
iprev_res = "fail"
except:
iprev_res = "temperror"
iprev_result = authres.IPRevAuthenticationResult(result=iprev_res, policy_iprev=up_srv_ip, policy_iprev_comment=iprev_hn)
### SPF CHECK
# Find this line:
# Received: from unknown (HELO sv3-smtp2.lithium.com) (208.74.204.9)
# by serpens.uberspace.de with SMTP; 23 Jun 2017 18:43:18 -0000
spf_result = spf.check2(i=up_srv_ip, s=sender_address, h=up_srv_helo)
# TODO: Received-SPF
### PREP AUTH RESULT
spf_res = authres.SPFAuthenticationResult(result=spf_result[0], smtp_mailfrom=sender_address, smtp_helo=up_srv_helo, reason=spf_result[1])
auth_res = authres.AuthenticationResultsHeader(authserv_id=AUTHSERV_ID, results=[spf_res, iprev_result])
sys.stdout.write(str(auth_res)+"\n")
### ARC SIGNATURE
cv = dkim.CV_None
if re.search('arc-seal', message, re.IGNORECASE):
cv = dkim.CV_Pass
# parameters: message, selector, domain, privkey, auth_results, chain_validation_status
sig = dkim.arc_sign(message, DKIM_SELECTOR, DKIM_DOMAIN, privkey, str(auth_res)[24:], cv)
for line in sig:
sys.stdout.write(line)
sys.exit(0)
sys.stdout.write(message)