Skip to content
Snippets Groups Projects
Commit 83529320 authored by Stuart Gathman's avatar Stuart Gathman
Browse files

Add private relay.

parent e5685c60
No related branches found
No related tags found
No related merge requests found
Here is a history of user visible changes to Python milter. Here is a history of user visible changes to Python milter.
0.8.8 move AddrCache, parse_addr, iniplist, parse_header to Milter package
fix plock for missing source and can't change owner/group
add sample spfmilter.py milter
0.8.7 Move spf module to pyspf 0.8.7 Move spf module to pyspf
Prevent PTR cache poisoning Prevent PTR cache poisoning
More lame bounce heuristics More lame bounce heuristics
......
...@@ -51,8 +51,9 @@ Xpythonfilter, S=local:/home/username/pythonsock ...@@ -51,8 +51,9 @@ Xpythonfilter, S=local:/home/username/pythonsock
Note that milters should almost certainly not run as root. Note that milters should almost certainly not run as root.
That's it. Incoming mail will cause the milter to print some things, and That's it. Incoming mail will cause the milter to print some things, and
some email will be rejected (see the "header" method). Edit and play. See some email will be rejected (see the "header" method). Edit and play.
bms.py for an example milter used in production. See spfmilter.py for a functional SPF milter, or see bms.py for an complex
milter used in production.
Not-so-quick Installation Not-so-quick Installation
......
Need to use wildcards in blacklist.log: *.madcowsrecord.net
Need to exclude emails like !*-admin@example.com in whitelist_sender.
Need to exclude robot users from autowhitelist. Don't want to have to Need to exclude robot users from autowhitelist. Don't want to have to
list all users, so implement something like !*-admin@bmsi.com,@bmsi.com. list all users, so implement something like !*-admin@bmsi.com,@bmsi.com.
Milter won't start when a whitelist/blacklist file is missing.
Milter won't start when it can't change permissions on *.lock to match
*.log. Should maybe ignore that error - the effect will be to set
the permissions to default.
GOSSiP feedback from user training is ignored because UMIS has already been GOSSiP feedback from user training is ignored because UMIS has already been
removed from queue. Maybe keep UMIS in queue, and add method to removed from queue. Maybe keep UMIS in queue, and add method to
alter last feedback for ID. alter last feedback for ID.
...@@ -15,27 +11,17 @@ Generate DSNs according to RFC 3464 ...@@ -15,27 +11,17 @@ Generate DSNs according to RFC 3464
Get temperror policy from access file. Get temperror policy from access file.
When training with spam, REJECT after data so that mistakenly blacklisted
senders at least get an error.
Reporting explanation for failure should show source if sender Reporting explanation for failure should show source if sender
provided explanation. provided explanation.
Bug in Auto-whitelist. Recent Auto-whitelist doesn't override expired entry. Bug in Auto-whitelist. Recent Auto-whitelist doesn't override expired entry.
Need to use wildcards in blacklist.log: *.madcowsrecord.net
Need to exclude emails like !*-admin@example.com in whitelist_sender.
SPF permerror diagnostics should include corrected mechanism. SPF permerror diagnostics should include corrected mechanism.
Delay SPF check until RCPT TO. Cache result to avoid repeating Delay SPF check until RCPT TO. Cache result to avoid repeating
for multiple RCPT. This avoids overhead for invalid RCPT, and for multiple RCPT. This avoids overhead for invalid RCPT, and
allows for per RCPT local policy. allows for per RCPT local policy.
Add auto-blacklisted senders to blacklist.log with timestamp.
Received-SPF header field should show identity that was checked.
Check SPF for outgoing mail (including local policy for internal addresses). Check SPF for outgoing mail (including local policy for internal addresses).
This could also solve the second part of the mail from relay problem below. This could also solve the second part of the mail from relay problem below.
...@@ -47,6 +33,7 @@ For selected domains, check rcpts via CBV before accepting mail. Cache ...@@ -47,6 +33,7 @@ For selected domains, check rcpts via CBV before accepting mail. Cache
results. This will kick out dictonary attacks against a mail domain results. This will kick out dictonary attacks against a mail domain
behind a gateway sooner. behind a gateway sooner.
Add auto-blacklisted senders to blacklist.log with timestamp.
Add emails blacklisted via CBV so that they are remembered across milter Add emails blacklisted via CBV so that they are remembered across milter
restarts. restarts.
...@@ -59,9 +46,6 @@ to train on error to minimize labor. ...@@ -59,9 +46,6 @@ to train on error to minimize labor.
Allow unsigned DSNs from selected domains (that don't accept signed MFROM, Allow unsigned DSNs from selected domains (that don't accept signed MFROM,
e.g. verizon.net). e.g. verizon.net).
Added Message-ID header to DSN with SRS signed sender. When seen on incoming
rfc ignorant failure message, blacklist sender.
Allow verified hostnames for trusted_relay. E.g. HELO name that Allow verified hostnames for trusted_relay. E.g. HELO name that
passes SPF. passes SPF.
...@@ -86,11 +70,9 @@ wildcard (e.g. empty localpart). ...@@ -86,11 +70,9 @@ wildcard (e.g. empty localpart).
Quarantined mail is missing headers modified/added by milter after Quarantined mail is missing headers modified/added by milter after
checking dspam. checking dspam.
Require signed MFROM for all incoming bounces when signing all outgoing mail -
except from trusted relays.
Send DSN for permerror before processing extended result. An additional Send DSN for permerror before processing extended result. An additional
DSN may be sent based on extended result. DSN may be sent based on extended result. Send permerror DSN to
postmaster@sending_domain.
Rescind whitelist for banned extensions, in case sender is infected. Rescind whitelist for banned extensions, in case sender is infected.
...@@ -104,9 +86,6 @@ SPF-Neutral:aol.com ERROR:"550 AOL mail must get SPF PASS" ...@@ -104,9 +86,6 @@ SPF-Neutral:aol.com ERROR:"550 AOL mail must get SPF PASS"
Defer TEMPERROR in SPF evaluation - give precedence to security Defer TEMPERROR in SPF evaluation - give precedence to security
(only defer for PASS mechanisms). (only defer for PASS mechanisms).
Option to add Received-SPF header, but never reject on SPF.
I think the above will handle this.
Create null config that does nothing - except maybe add Received-SPF Create null config that does nothing - except maybe add Received-SPF
headers. Many admins would like to turn features on one at a time. headers. Many admins would like to turn features on one at a time.
...@@ -153,6 +132,26 @@ Need a test module to feed sample messages to a milter though a live ...@@ -153,6 +132,26 @@ Need a test module to feed sample messages to a milter though a live
sendmail and SMTP. The mockup currently used is probably not very accurate, sendmail and SMTP. The mockup currently used is probably not very accurate,
and doesn't test the threading code. and doesn't test the threading code.
DONE Require signed MFROM for all incoming bounces when signing all outgoing
mail - except from trusted relays.
DONE Added Message-ID header to DSN with SRS signed sender. When seen on
incoming rfc ignorant failure message, blacklist sender.
DONE Option to add Received-SPF header, but never reject on SPF.
I think the above will handle this.
DONE Received-SPF header field should show identity that was checked.
DONE When training with spam, REJECT after data so that mistakenly blacklisted
senders at least get an error.
DONE Milter won't start when it can't change permissions on *.lock to match
*.log. Should maybe ignore that error - the effect will be to set
the permissions to default.
DONE Milter won't start when a whitelist/blacklist file is missing.
DONE Delayed failure detection should parse From header to find email address. DONE Delayed failure detection should parse From header to find email address.
DONE When bms.py can't find templates, it passes None to dsn.create_msg(), DONE When bms.py can't find templates, it passes None to dsn.create_msg(),
......
#!/usr/bin/env python #!/usr/bin/env python
# A simple milter that has grown quite a bit. # A simple milter that has grown quite a bit.
# $Log$ # $Log$
# Revision 1.89 2007/01/22 02:46:01 customdesigned
# Convert tabs to spaces.
#
# Revision 1.88 2007/01/19 23:31:38 customdesigned # Revision 1.88 2007/01/19 23:31:38 customdesigned
# Move parse_header to Milter.utils. # Move parse_header to Milter.utils.
# Test case for delayed DSN parsing. # Test case for delayed DSN parsing.
...@@ -157,6 +160,7 @@ scan_html = True ...@@ -157,6 +160,7 @@ scan_html = True
scan_rfc822 = True scan_rfc822 = True
internal_connect = () internal_connect = ()
trusted_relay = () trusted_relay = ()
private_relay = ()
trusted_forwarder = () trusted_forwarder = ()
internal_domains = () internal_domains = ()
banned_users = () banned_users = ()
...@@ -222,7 +226,7 @@ def read_config(list): ...@@ -222,7 +226,7 @@ def read_config(list):
tempfile.tempdir = cp.get('milter','tempdir') tempfile.tempdir = cp.get('milter','tempdir')
global socketname, timeout, check_user, log_headers global socketname, timeout, check_user, log_headers
global internal_connect, internal_domains, trusted_relay, hello_blacklist global internal_connect, internal_domains, trusted_relay, hello_blacklist
global case_sensitive_localpart global case_sensitive_localpart, private_relay
socketname = cp.get('milter','socket') socketname = cp.get('milter','socket')
timeout = cp.getint('milter','timeout') timeout = cp.getint('milter','timeout')
check_user = cp.getaddrset('milter','check_user') check_user = cp.getaddrset('milter','check_user')
...@@ -230,6 +234,7 @@ def read_config(list): ...@@ -230,6 +234,7 @@ def read_config(list):
internal_connect = cp.getlist('milter','internal_connect') internal_connect = cp.getlist('milter','internal_connect')
internal_domains = cp.getlist('milter','internal_domains') internal_domains = cp.getlist('milter','internal_domains')
trusted_relay = cp.getlist('milter','trusted_relay') trusted_relay = cp.getlist('milter','trusted_relay')
private_relay = cp.getlist('milter','private_relay')
hello_blacklist = cp.getlist('milter','hello_blacklist') hello_blacklist = cp.getlist('milter','hello_blacklist')
case_sensitive_localpart = cp.getboolean('milter','case_sensitive_localpart') case_sensitive_localpart = cp.getboolean('milter','case_sensitive_localpart')
...@@ -898,6 +903,10 @@ class bmsMilter(Milter.Milter): ...@@ -898,6 +903,10 @@ class bmsMilter(Milter.Milter):
return self.forged_bounce() return self.forged_bounce()
self.data_allowed = not srs_reject_spoofed self.data_allowed = not srs_reject_spoofed
if not self.internal_connection and domain in private_relay:
self.log('REJECT: RELAY:',to)
self.setreply('550','5.7.1','Unauthorized relay for %s' % domain)
return Milter.REJECT
# non DSN mail to SRS address will bounce due to invalid local part # non DSN mail to SRS address will bounce due to invalid local part
canon_to = '@'.join(t) canon_to = '@'.join(t)
self.recipients.append(canon_to) self.recipients.append(canon_to)
......
...@@ -23,6 +23,9 @@ log_headers = 0 ...@@ -23,6 +23,9 @@ log_headers = 0
# SPF checks are bypassed for internal connections and trusted relays. # SPF checks are bypassed for internal connections and trusted relays.
;trusted_relay = 1.2.3.4, 66.12.34.56 ;trusted_relay = 1.2.3.4, 66.12.34.56
# Relaying to these domains is allowed from internal connections only.
;private_relay = mycorp.com
# Reject external senders with hello names no legit external sender would use. # Reject external senders with hello names no legit external sender would use.
# SPF will do this also, but listing your own domain and mailserver here # SPF will do this also, but listing your own domain and mailserver here
# will save some DNS lookups when rejecting certain viruses. # will save some DNS lookups when rejecting certain viruses.
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment