|
Python Milter Mail PolicyThese are the policies implemented by thebms.py milter
application. The milter and Milter modules do not implement any policies
by themselves.
Classify connectionWhen the SMTP client connects, the connection IP address is saved for later verification, and the connection is classified as INTERNAL or EXTERNAL by matching the ip address against theinternal_connect configuration.
IP addresses with no PTR, and PTR names that look like
the kind assigned to dynamic IPs (as determined by a heuristic
algorithm) are flagged as DYNAMIC. IPs that match the
trusted_relay configuration are flagged as TRUSTED.
Examples from the log file (not the SMTP error message returned): 2005Jul29 13:56:53 [71207] connect from p50863492.dip0.t-ipconnect.de at ('80.134.52.146', 1858) EXTERNAL DYN 2005Jul29 18:10:15 [74511] connect from foopub at ('1.2.3.4', 46513) EXTERNAL TRUSTED 2005Jul29 14:41:00 [71805] connect from foobar at ('192.168.0.1', 41205) INTERNAL 2005Jul29 14:41:15 [71806] connect from cncln.online.ln.cn at ('218.25.240.137', 35992) EXTERNAL Certain obviously evil PTR names are blocked at this point: "localhost" (when IP is not 127.*) and ".". 2005Jul29 14:49:50 [71918] connect from localhost at ('221.132.0.6', 50507) EXTERNAL 2005Jul29 14:49:50 [71918] REJECT: PTR is localhost HELO CheckThe HELO name provided by the client is saved for later verification (for example by SPF). We could validate the HELO at this point by verifying that an A record for the HELO name matches the connect ip. However, currently we only block certain obvious problems. HELO names that look like an IP4 address and ones that match thehello_blacklist configuration
are immediately rejected. The hello_blacklist typically contains
the current MTAs own HELO name or email domains.
Clients that attempt to skip HELO are immediately rejected.
2005Jul29 18:10:15 [74512] hello from example.com 2005Jul29 18:10:15 [74512] REJECT: spam from self: example.com 2005Jul29 18:17:09 [74581] hello from 80.191.244.69 2005Jul29 18:17:09 [74581] REJECT: numeric hello name: 80.191.244.69 MAIL FROM CheckBefore calling our milter, sendmail checks a DNS blacklist to block banned sender domains. We never see a blocked domain.
The MAIL FROM address is saved for possible use by the smart-alias
feature. First, the wiretapThe wiretap feature can screen and/or monitor mail to/from certain users. If the MAIL FROM is being wiretapped, the recipients are altered accordingly.SPF checkThe MAIL FROM, connect IP, and HELO name are checked against any SPF records published via DNS for the alleged sender (MAIL FROM) to determine the official SPF policy result. The offical SPF result is then logged in the Received-SPF header field, but certain results are subjected to further processing to create an effective result for policy purposes. If the official result is 'none', we try to turn it into an effective result of 'pass' or 'fail'. First, we check for a local substitute SPF record under the domain defined in the[spf]delegate configuration.
It is often useful to add local SPF records for correspondents that are
too clueless to add their own. If there is no local substitute, we use a "best
guess" SPF record of "v=spf1 a/24 mx/24 ptr" for MAIL FROM or "v=spf1 a/24
mx/24" for HELO. In addition, a HELO that is a subdomain of MAIL FROM and
resolves to the connect IP results in an effective result of 'pass'.
If there is no local SPF record, and the effective result is still not
'pass', we check for either a valid HELO name or a valid PTR record for
the connect IP. A valid HELO or PTR cannot look like a dynamic name
as determined by the heuristic in Milter.dynip .
If HELO has an SPF record, and the result is anything but pass, we reject
the connection:
2005Jul30 19:45:16 [93991] connect from [221.200.41.54] at ('221.200.41.54', 3581) EXTERNAL DYN 2005Jul30 19:45:18 [93991] hello from adelphia.net 2005Jul30 19:45:19 [93991] mail fromNote that HELO does not have any forwarding issues like MAIL FROM, and so any result other than 'pass' or 'none' should be treated like 'fail'. Only if nothing about the SMTP envelope can be validated does the effective result remain 'none. I call this the "3 strikes" rule. If the official result is 'permerror' (a syntax error in the sender's policy), we use the 'lax' option in pyspf to try various heuristics to guess what they really meant. For instance, the invalid mechanism "ip:1.2.3.4" is treated as "ip4:1.2.3.4". The result of lax processing is then used as the effective result for policy purposes. With an effective SPF result in hand, we consult the sendmail access database to find our receiver policy for the sender.
SPF policy syntaxFirst, the full sender is checked:SPF-Fail:abeb@adelphia.net DSNThis says to accept mail from that adelphia.net user despite the SPF fail, but only after annoying them with a DSN about their ISP's broken policy. If there is no match on the full sender, the domain is checked: SPF-Neutral:aol.com REJECTThis says to reject mail from AOL with an SPF result of neutral. This means AOL users can't use their AOL address with another mail service to send us mail. This is good because the other mail service is likely a badly configured greeting card site or a virus. Finally, a default policy for the result is checked. While there are program defaults, you should have defaults in the access database for SPF results: SPF-Neutral: CBV SPF-Softfail: DSN SPF-PermError: DSN SPF-TempError: REJECT SPF-None: REJECT SPF-Fail: REJECT SPF-Pass: OK ReputationIf the sender has not been rejected by this point, and if a GOSSiP server is configured, we consult GOSSiP for the reputation score of the sender and SPF result. The score is a number from -100 to 100 with a confidence percentage from 0 to 100. A really bad reputation (less than -50 with confidence greater than 3) is rejected. Note that the reputation is tracked independently for each SPF result and sender combination. So aol.com:neutral might have a really bad reputation, while aol.com:pass would be ok. Furthermore, when a sender finally publishes an SPF policy and starts getting SPF pass, their reputation is effectively reset. |