好了,打起精神来! 这篇文章很长 - 但恭喜你读到这里!
以下 ACL 包含了我们在这个实现中描述的所有检查。 但是,有些已被注释掉,原因如下:
灰名单。 这要么需要安装额外的软件,要么通过 Exim 配置文件中的额外 ACL 和定义进行相当复杂的内联配置。 不过,我强烈推荐它。
病毒扫描。 没有像 SpamAssassin 那样几乎每个人都使用的普遍扫描器来进行垃圾邮件识别。 另一方面,随附的文档Exiscan-ACL应该很容易理解。
SpamAssassin 的用户设置。 这对许多人来说是不可接受的权衡,因为它涉及到将邮件延迟到除邮件的第一个收件人之外的所有人。
信封发件人签名。 这会产生一些后果,例如对于漫游用户。 此外,它还涉及到配置路由器和传输以及 ACL。 有关详细信息,请参阅该部分。
仅接受真实用户的退回邮件。 有几种方法可以做到这一点,并且确定哪些用户是真实的,这取决于邮件的传递方式。
废话不多说,这是我们一直等待的最终结果。
# This access control list is used at the start of an incoming # connection. The tests are run in order until the connection is # either accepted or denied. acl_connect: # Record the current timestamp, in order to calculate elapsed time # for subsequent delays warn set acl_m2 = $tod_epoch # Accept mail received over local SMTP (i.e. not over TCP/IP). We do # this by testing for an empty sending host field. # Also accept mails received over a local interface, and from hosts # for which we relay mail. accept hosts = : +relay_from_hosts # If the connecting host is in one of several DNSbl's, then prepare # a warning message in $acl_c1. We will later add this message to # the mail header. In the mean time, its presence indicates that # we should keep stalling the sender. # warn !hosts = ${if exists {/etc/mail/whitelist-hosts} \ {/etc/mail/whitelist-hosts}} dnslists = list.dsbl.org : \ dnsbl.sorbs.net : \ dnsbl.njabl.org : \ bl.spamcop.net : \ dsn.rfc-ignorant.org : \ sbl-xbl.spamhaus.org : \ l1.spews.dnsbl.sorbs.net set acl_c1 = X-DNSbl-Warning: \ $sender_host_address is listed in $dnslist_domain\ ${if def:dnslist_text { ($dnslist_text)}} # Likewise, if reverse DNS lookup of the sender's host fails (i.e. # there is no rDNS entry, or a forward lookup of the resulting name # does not match the original IP address), then generate a warning # message in $acl_c1. We will later add this message to the mail # header. warn condition = ${if !def:acl_c1 {true}{false}} !verify = reverse_host_lookup set acl_m9 = Reverse DNS lookup failed for host $sender_host_address set acl_c1 = X-DNS-Warning: $acl_m9 # Accept the connection, but if we previously generated a message in # $acl_c1, stall the sender until 20 seconds has elapsed. accept set acl_m2 = ${if def:acl_c1 {${eval:20 + $acl_m2 - $tod_epoch}}{0}} delay = ${if >{$acl_m2}{0}{$acl_m2}{0}}s |
# This access control list is used for the HELO or EHLO command in # an incoming SMTP transaction. The tests are run in order until the # greeting is either accepted or denied. acl_helo: # Record the current timestamp, in order to calculate elapsed time # for subsequent delays warn set acl_m2 = $tod_epoch # Accept mail received over local SMTP (i.e. not over TCP/IP). # We do this by testing for an empty sending host field. # Also accept mails received from hosts for which we relay mail. # accept hosts = : +relay_from_hosts # If the remote host greets with an IP address, then prepare a reject # message in $acl_c0, and a log message in $acl_c1. We will later use # these in a "deny" statement. In the mean time, their presence indicate # that we should keep stalling the sender. # warn condition = ${if isip {$sender_helo_name}{true}{false}} set acl_c0 = Message was delivered by ratware set acl_c1 = remote host used IP address in HELO/EHLO greeting # Likewise if the peer greets with one of our own names # warn condition = ${if match_domain{$sender_helo_name}\ {$primary_hostname:+local_domains:+relay_to_domains}\ {true}{false}} set acl_c0 = Message was delivered by ratware set acl_c1 = remote host used our name in HELO/EHLO greeting. # If HELO verification fails, we prepare a warning message in acl_c1. # We will later add this message to the mail header. In the mean time, # its presence indicates that we should keep stalling the sender. # warn condition = ${if !def:acl_c1 {true}{false}} !verify = helo set acl_c1 = X-HELO-Warning: Remote host $sender_host_address \ ${if def:sender_host_name {($sender_host_name) }}\ incorrectly presented itself as $sender_helo_name log_message = remote host presented unverifiable HELO/EHLO greeting. # Accept the greeting, but if we previously generated a message in # $acl_c1, stall the sender until 20 seconds has elapsed. accept set acl_m2 = ${if def:acl_c1 {${eval:20 + $acl_m2 - $tod_epoch}}{0}} delay = ${if >{$acl_m2}{0}{$acl_m2}{0}}s |
# This access control list is used for the MAIL FROM: command in an # incoming SMTP transaction. The tests are run in order until the # sender address is either accepted or denied. # acl_mail_from: # Record the current timestamp, in order to calculate elapsed time # for subsequent delays warn set acl_m2 = $tod_epoch # Accept mail received over local SMTP (i.e. not over TCP/IP). # We do this by testing for an empty sending host field. # Also accept mails received from hosts for which we relay mail. # # Sender verification is omitted here, because in many cases # the clients are dumb MUAs that don't cope well with SMTP # error responses. # accept hosts = : +relay_from_hosts # Accept if the message arrived over an authenticated connection, # from any host. Again, these messages are usually from MUAs. # accept authenticated = * # If present, the ACL variables $acl_c0 and $acl_c1 contain rejection # and/or warning messages to be applied to every delivery attempt in # in this SMTP transaction. Assign these to the corresponding # $acl_m{0,1} message-specific variables, and add any warning message # from $acl_m1 to the message header. (In the case of a rejection, # $acl_m1 actually contains a log message instead, but this does not # matter, as we will discard the header along with the message). # warn set acl_m0 = $acl_c0 set acl_m1 = $acl_c1 message = $acl_c1 # If sender did not provide a HELO/EHLO greeting, then prepare a reject # message in $acl_m0, and a log message in $acl_m1. We will later use # these in a "deny" statement. In the mean time, their presence indicate # that we should keep stalling the sender. # warn condition = ${if def:sender_helo_name {0}{1}} set acl_m0 = Message was delivered by ratware set acl_m1 = remote host did not present HELO/EHLO greeting. # If we could not verify the sender address, create a warning message # in $acl_m1 and add it to the mail header. The presence of this # message indicates that we should keep stalling the sender. # # You may choose to omit the "callout" option. In particular, if # you are sending outgoing mail through a smarthost, it will not # give any useful information. # warn condition = ${if !def:acl_m1 {true}{false}} !verify = sender/callout set acl_m1 = Invalid sender <$sender_address> message = X-Sender-Verify-Failed: $acl_m1 log_message = $acl_m1 # Accept the sender, but if we previously generated a message in # $acl_c1, stall the sender until 20 seconds has elapsed. accept set acl_m2 = ${if def:acl_c1 {${eval:20 + $acl_m2 - $tod_epoch}}{0}} delay = ${if >{$acl_m2}{0}{$acl_m2}{0}}s |
# This access control list is used for every RCPT command in an # incoming SMTP message. The tests are run in order until the # recipient address is either accepted or denied. acl_rcpt_to: # Accept mail received over local SMTP (i.e. not over TCP/IP). # We do this by testing for an empty sending host field. # Also accept mails received from hosts for which we relay mail. # # Recipient verification is omitted here, because in many # cases the clients are dumb MUAs that don't cope well with # SMTP error responses. # accept hosts = : +relay_from_hosts # Accept if the message arrived over an authenticated connection, # from any host. Again, these messages are usually from MUAs, so # recipient verification is omitted. # accept authenticated = * # Deny if the local part contains @ or % or / or | or !. These are # rarely found in genuine local parts, but are often tried by people # looking to circumvent relaying restrictions. # # Also deny if the local part starts with a dot. Empty components # aren't strictly legal in RFC 2822, but Exim allows them because # this is common. However, actually starting with a dot may cause # trouble if the local part is used as a file name (e.g. for a # mailing list). # deny local_parts = ^.*[@%!/|] : ^\\. # Deny if we have previously given a reason for doing so in $acl_m0. # Also stall the sender for another 20s first. # deny message = $acl_m0 log_message = $acl_m1 condition = ${if and {{def:acl_m0}{def:acl_m1}} {true}} delay = 20s # If the recipient address is not in a domain for which we are handling # mail, stall the sender and reject. # deny message = relay not permitted !domains = +local_domains : +relay_to_domains delay = 20s # If the address is in a local domain or in a domain for which are # relaying, but is invalid, stall and reject. # deny message = unknown user !verify = recipient/callout=20s,defer_ok,use_sender delay = ${if def:sender_address {1m}{0s}} # Drop the connection if the envelope sender is empty, but there is # more than one recipient address. Legitimate DSNs are never sent # to more than one address. # drop message = Legitimate bounces are never sent to more than one \ recipient. senders = : postmaster@* condition = $recipients_count delay = 5m # -------------------------------------------------------------------- # Limit the number of recipients in each incoming message to one # to support per-user settings and data (e.g. for SpamAssassin). # # NOTE: Every mail sent to several users at your site will be # delayed for 30 minutes or more per recipient. This # significantly slow down the pace of discussion threads # involving several internal and external parties. # Thus, it is commented out by default. # #defer # message = We only accept one recipient at a time - please try later. # condition = $recipients_count # -------------------------------------------------------------------- # Accept the mail if the sending host is matched in the ".forwarders" # file in the recipient's home directory. Temporarily set $acl_m9 to # point to this file. If the host is found, set a flag in $acl_m0 and # clear $acl_m1 to indicate that we should not reject this mail later. # accept domains = +local_domains set acl_m9 = /home/${extract{1}{=}{${lc:$local_part}}}/.forwarders hosts = ${if exists {$acl_m9}{$acl_m9}} set acl_m0 = accept set acl_m1 = # Accept the mail if the sending host is matched in the global # whitelist file. Temporarily set $acl_m9 to point to this file. # If the host is found, set a flag in $acl_m0 and clear $acl_m1 to # indicate that we should not reject this mail later. # accept set acl_m9 = /etc/mail/whitelist-hosts hosts = ${if exists {$acl_m9}{$acl_m9}} set acl_m0 = accept set acl_m1 = # -------------------------------------------------------------------- # Envelope Sender Signature Check. # This is commented out by default, because it requires additional # configuration in the 'transports' and 'routers' sections. # # Accept the recipient addresss if it contains our own signature. # This means this is a response (DSN, sender callout verification...) # to a message that was previously sent from here. # #accept # domains = +local_domains # condition = ${if and {{match{${lc:$local_part}}{^(.*)=(.*)}}\ # {eq{${hash_8:${hmac{md5}{SECRET}{$1}}}}{$2}}}\ # {true}{false}} # # Otherwise, if this message claims to be a bounce (i.e. if there # is no envelope sender), but if the receiver has elected to use # and check against envelope sender signatures, reject it. # #deny # message = This address does not match a valid, signed \ # return path from here.\n\ # You are responding to a forged sender address. # log_message = bogus bounce. # senders = : postmaster@* # domains = +local_domains # set acl_m9 = /home/${extract{1}{=}{${lc:$local_part}}}/.return-path-sign # condition = ${if exists {$acl_m9}{true}} # -------------------------------------------------------------------- # -------------------------------------------------------------------- # Deny mail for local users that do not have a mailbox (i.e. postmaster, # webmaster...) if no sender address is provided. These users do # not send outgoing mail, so they should not receive returned mail. # # NOTE: This is commented out by default, because the condition is # specific to how local mail is delivered. If you want to # enable this check, uncomment one and only one of the # conditions below. # #deny # message = This address never sends outgoing mail. \ # You are responding to a forged sender address. # log_message = bogus bounce for system user <$local_part@$domain> # senders = : postmaster@* # domains = +local_domains # set acl_m9 = ${extract{1}{=}{${lc:$local_part}}} # # --- Uncomment the following 2 lines if recipients have local accounts: # set acl_m9 = ${extract{2}{:}{${lookup passwd {$acl_m9}{$value}}}{0}} # !condition = ${if and {{>={$acl_m9}{500}} {<${acl_m9}{60000}}} {true}} # # --- Uncomment the following line if you deliver mail to Cyrus: # condition = ${run {/usr/sbin/mbpath -q -s user.$acl_m9} {true}} # -------------------------------------------------------------------- # Query the SPF information for the sender address domain, if any, # to see if the sending host is authorized to deliver its mail. # If not, reject the mail. # deny message = [SPF] $sender_host_address is not allowed to send mail \ from $sender_address_domain log_message = SPF check failed. spf = fail # Add a SPF-Received: line to the message header warn message = $spf_received # -------------------------------------------------------------------- # Check greylisting status for this particular peer/sender/recipient. # Before uncommenting this statement, you need to install "greylistd". # See: http://packages.debian.org/unstable/main/greylistd # # Note that we do not greylist messages with NULL sender, because # sender callout verification would break (and we might not be able # to send mail to a host that performs callouts). # #defer # message = $sender_host_address is not yet authorized to deliver mail \ # from <$sender_address> to <$local_part@$domain>. \ # Please try later. # log_message = greylisted. # domains = +local_domains : +relay_to_domains # !senders = : postmaster@* # set acl_m9 = $sender_host_address $sender_address $local_part@$domain # set acl_m9 = ${readsocket{/var/run/greylistd/socket}{$acl_m9}{5s}{}{}} # condition = ${if eq {$acl_m9}{grey}{true}{false}} # delay = 20s # -------------------------------------------------------------------- # Accept the recipient. accept |
# This access control list is used for message data received via # SMTP. The tests are run in order until the recipient address # is either accepted or denied. acl_data: # Log some header lines warn logwrite = Subject: $h_Subject: # Add Message-ID if missing in messages received from our own hosts. warn condition = ${if !def:h_Message-ID: {1}} hosts = +relay_from_hosts message = Message-ID: <E$message_id@$primary_hostname> # Accept mail received over local SMTP (i.e. not over TCP/IP). # We do this by testing for an empty sending host field. # Also accept mails received from hosts for which we relay mail. # accept hosts = : +relay_from_hosts # Accept if the message arrived over an authenticated connection, from # any host. # accept authenticated = * # Deny if we have previously given a reason for doing so in $acl_m0. # Also stall the sender for another 20s first. # deny message = $acl_m0 log_message = $acl_m1 condition = ${if and {{def:acl_m0}{def:acl_m1}} {true}{false}} delay = 20s # enforce a message-size limit # deny message = Message size $message_size is larger than limit of \ MESSAGE_SIZE_LIMIT condition = ${if >{$message_size}{MESSAGE_SIZE_LIMIT}{yes}{no}} # Deny unless the addresses in the header is syntactically correct. # deny message = Your message does not conform to RFC2822 standard log_message = message header fail syntax check !verify = header_syntax # Uncomment the following to deny non-local messages without # a Message-ID:, Date:, or Subject: header. # # Note that some specialized MTAs, such as certain mailing list # servers, do not automatically generate a Message-ID for bounces. # Thus, we add the check for a non-empty sender. # #deny # message = Your message does not conform to RFC2822 standard # log_message = missing header lines # !hosts = +relay_from_hosts # !senders = : postmaster@* # condition = ${if !eq {$acl_m0}{accept}{true}} # condition = ${if or {{!def:h_Message-ID:}\ # {!def:h_Date:}\ # {!def:h_Subject:}} {true}{false}} # Warn unless there is a verifiable sender address in at least # one of the "Sender:", "Reply-To:", or "From:" header lines. # warn message = X-Sender-Verify-Failed: No valid sender in message header log_message = No valid sender in message header !verify = header_sender # -------------------------------------------------------------------- # Perform greylisting on messages with no envelope sender here. # We did not subject these to greylisting after RCPT TO: because # that would interfere with remote hosts doing sender callouts. # Note that the sender address is empty, so we don't bother using it. # # Before uncommenting this statement, you need to install "greylistd". # See: http://packages.debian.org/unstable/main/greylistd # #defer # message = $sender_host_address is not yet authorized to send \ # delivery status reports to <$recipients>. \ # Please try later. # log_message = greylisted. # senders = : postmaster@* # condition = ${if !eq {$acl_m0}{accept}{true}} # set acl_m9 = $sender_host_address $recipients # set acl_m9 = ${readsocket{/var/run/greylistd/socket}{$acl_m9}{5s}{}{}} # condition = ${if eq {$acl_m9}{grey}{true}{false}} # delay = 20s # -------------------------------------------------------------------- # --- BEGIN EXISCAN configuration --- # Reject messages that have serious MIME errors. # deny message = Serious MIME defect detected ($demime_reason) demime = * condition = ${if >{$demime_errorlevel}{2}{1}{0}} # Unpack MIME containers and reject file extensions used by worms. # This calls the demime condition again, but it will return cached results. # Note that the extension list may be incomplete. # deny message = We do not accept ".$found_extension" attachments here. demime = bat:btm:cmd:com:cpl:dll:exe:lnk:msi:pif:prf:reg:scr:vbs:url # Messages larger than MESSAGE_SIZE_SPAM_MAX are accepted without # spam or virus scanning accept condition = ${if >{$message_size}{MESSAGE_SIZE_SPAM_MAX} {true}} logwrite = :main: Not classified \ (message size larger than MESSAGE_SIZE_SPAM_MAX) # -------------------------------------------------------------------- # Anti-Virus scanning # This requires an 'av_scanner' setting in the main section. # #deny # message = This message contains a virus ($malware_name) # demime = * # malware = */defer_ok # -------------------------------------------------------------------- # Invoke SpamAssassin to obtain $spam_score and $spam_report. # Depending on the classification, $acl_m9 is set to "ham" or "spam". # # If the message is classified as spam, and we have not previously # set $acl_m0 to indicate that we want to accept it anyway, pretend # reject it. # warn set acl_m9 = ham # ------------------------------------------------------------------ # If you want to allow per-user settings for SpamAssassin, # uncomment the following line, and comment out "spam = mail". # We pass on the username specified in the recipient address, # i.e. the portion before any '=' or '@' character, converted # to lowercase. Multiple recipients should not occur, since # we previously limited delivery to one recipient at a time. # # spam = ${lc:${extract{1}{=@}{$recipients}{$value}{mail}}} # ------------------------------------------------------------------ spam = mail set acl_m9 = spam condition = ${if !eq {$acl_m0}{accept}{true}} control = fakereject logwrite = :reject: Rejected spam (score $spam_score): $spam_report # Add an appropriate X-Spam-Status: header to the message. # warn message = X-Spam-Status: \ ${if eq {$acl_m9}{spam}{Yes}{No}} (score $spam_score)\ ${if def:spam_report {: $spam_report}} logwrite = :main: Classified as $acl_m9 (score $spam_score) # --- END EXISCAN configuration --- # Accept the message. # accept |