94 lines
2.5 KiB
Python
Executable File
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)
|