Support timeout option on malware=
[users/heiko/exim.git] / doc / doc-txt / experimental-spec.txt
index b80e02b4cfa2a6a89cf3381c3ebec5392c28a55f..aae8338f17b55fd0b09a7ec4e80e42b3f4392670 100644 (file)
@@ -6,114 +6,6 @@ about experimental  features, all  of which  are unstable and
 liable to incompatible change.
 
 
-PRDR support
---------------------------------------------------------------
-
-Per-Recipient Data Reponse is an SMTP extension proposed by Eric Hall
-in a (now-expired) IETF draft from 2007.  It's not hit mainstream
-use, but has apparently been implemented in the META1 MTA.
-
-There is mention at http://mail.aegee.org/intern/sendmail.html
-of a patch to sendmail "to make it PRDR capable".
-
- ref: http://www.eric-a-hall.com/specs/draft-hall-prdr-00.txt
-
-If Exim is built with EXPERIMENTAL_PRDR there is a new config
-boolean "prdr_enable" which controls whether PRDR is advertised
-as part of an EHLO response, a new "acl_data_smtp_prdr" ACL
-(called for each recipient, after data arrives but before the
-data ACL), and a new smtp transport option "hosts_try_prdr".
-
-PRDR may be used to support per-user content filtering.  Without it
-one must defer any recipient after the first that has a different
-content-filter configuration.  With PRDR, the RCPT-time check
-for this can be disabled when the MAIL-time $smtp_command included
-"PRDR".  Any required difference in behaviour of the main DATA-time
-ACL should however depend on the PRDR-time ACL having run, as Exim
-will avoid doing so in some situations (eg.  single-recipient mails).
-
-
-
-OCSP Stapling support
---------------------------------------------------------------
-
-X.509 PKI certificates expire and can be revoked; to handle this, the
-clients need some way to determine if a particular certificate, from a
-particular Certificate Authority (CA), is still valid.  There are three
-main ways to do so.
-
-The simplest way is to serve up a Certificate Revocation List (CRL) with
-an ordinary web-server, regenerating the CRL before it expires.  The
-downside is that clients have to periodically re-download a potentially
-huge file from every certificate authority it knows of.
-
-The way with most moving parts at query time is Online Certificate
-Status Protocol (OCSP), where the client verifies the certificate
-against an OCSP server run by the CA.  This lets the CA track all
-usage of the certs.  This requires running software with access to the
-private key of the CA, to sign the responses to the OCSP queries.  OCSP
-is based on HTTP and can be proxied accordingly.
-
-The only widespread OCSP server implementation (known to this writer)
-comes as part of OpenSSL and aborts on an invalid request, such as
-connecting to the port and then disconnecting.  This requires
-re-entering the passphrase each time some random client does this.
-
-The third way is OCSP Stapling; in this, the server using a certificate
-issued by the CA periodically requests an OCSP proof of validity from
-the OCSP server, then serves it up inline as part of the TLS
-negotiation.   This approach adds no extra round trips, does not let the
-CA track users, scales well with number of certs issued by the CA and is
-resilient to temporary OCSP server failures, as long as the server
-starts retrying to fetch an OCSP proof some time before its current
-proof expires.  The downside is that it requires server support.
-
-If Exim is built with EXPERIMENTAL_OCSP and it was built with OpenSSL,
-then it gains a new global option: "tls_ocsp_file".
-
-The file specified therein is expected to be in DER format, and contain
-an OCSP proof.  Exim will serve it as part of the TLS handshake.  This
-option will be re-expanded for SNI, if the tls_certificate option
-contains $tls_sni, as per other TLS options.
-
-Exim does not at this time implement any support for fetching a new OCSP
-proof.  The burden is on the administrator to handle this, outside of
-Exim.  The file specified should be replaced atomically, so that the
-contents are always valid.  Exim will expand the "tls_ocsp_file" option
-on each connection, so a new file will be handled transparently on the
-next connection.
-
-Exim will check for a valid next update timestamp in the OCSP proof;
-if not present, or if the proof has expired, it will be ignored.
-
-Also, given EXPERIMENTAL_OCSP and OpenSSL, the smtp transport gains
-a "hosts_require_ocsp" option; a host-list for which an OCSP Stapling
-is requested and required for the connection to proceed.  The host(s)
-should also be in "hosts_require_tls", and "tls_verify_certificates"
-configured for the transport.
-
-For the client to be able to verify the stapled OCSP the server must
-also supply, in its stapled information, any intermediate
-certificates for the chain leading to the OCSP proof from the signer
-of the server certificate.  There may be zero or one such. These
-intermediate certificates should be added to the server OCSP stapling
-file (named by tls_ocsp_file).
-
-At this point in time, we're gathering feedback on use, to determine if
-it's worth adding complexity to the Exim daemon to periodically re-fetch
-OCSP files and somehow handling multiple files.
-
-  A helper script "ocsp_fetch.pl" for fetching a proof from a CA
-  OCSP server is supplied.  The server URL may be included in the
-  server certificate, if the CA is helpful.
-
-  One fail mode seen was the OCSP Signer cert expiring before the end
-  of vailidity of the OCSP proof. The checking done by Exim/OpenSSL
-  noted this as invalid overall, but the re-fetch script did not.
-
-
-
-
 Brightmail AntiSpam (BMI) suppport
 --------------------------------------------------------------
 
@@ -452,15 +344,21 @@ which the spf condition should succeed. Valid strings are:
               This means the queried domain has published
               a SPF record, but wants to allow outside
               servers to send mail under its domain as well.
-  o err_perm  This indicates a syntax error in the SPF
-              record of the queried domain. This should be
-              treated like "none".
-  o err_temp  This indicates a temporary error during all
+              This should be treated like "none".
+  o permerror This indicates a syntax error in the SPF
+              record of the queried domain. You may deny
+              messages when this occurs. (Changed in 4.83)
+  o temperror This indicates a temporary error during all
               processing, including Exim's SPF processing.
               You may defer messages when this occurs.
+              (Changed in 4.83)
+  o err_temp  Same as permerror, deprecated in 4.83, will be
+              removed in a future release.
+  o err_perm  Same as temperror, deprecated in 4.83, will be
+              removed in a future release.
 
 You can prefix each string with an exclamation mark to  invert
-is meaning,  for example  "!fail" will  match all  results but
+its meaning,  for example  "!fail" will  match all  results but
 "fail".  The  string  list is  evaluated  left-to-right,  in a
 short-circuit fashion.  When a  string matches  the outcome of
 the SPF check, the condition  succeeds. If none of the  listed
@@ -510,8 +408,8 @@ variables.
 
   $spf_result
   This contains the outcome of the SPF check in string form,
-  one of pass, fail, softfail, none, neutral, err_perm or
-  err_temp.
+  one of pass, fail, softfail, none, neutral, permerror or
+  temperror.
 
   $spf_smtp_comment
   This contains a string that can be used in a SMTP response
@@ -773,7 +671,7 @@ fails.
 
 Of course, you can also use any other lookup method that Exim
 supports, including LDAP, Postgres, MySQL, etc, as long as the
-result is a list of colon-separated strings;
+result is a list of colon-separated strings.
 
 Several expansion variables are set before the DATA ACL is
 processed, and you can use them in this ACL.  The following
@@ -781,7 +679,10 @@ expansion variables are available:
 
   o $dmarc_status
     This is a one word status indicating what the DMARC library
-    thinks of the email.
+    thinks of the email.  It is a combination of the results of
+    DMARC record lookup and the SPF/DKIM/DMARC processing results
+    (if a DMARC record was found).  The actual policy declared
+    in the DMARC record is in a separate expansion variable.
 
   o $dmarc_status_text
     This is a slightly longer, human readable status.
@@ -790,6 +691,11 @@ expansion variables are available:
     This is the domain which DMARC used to look up the DMARC
     policy record.
 
+  o $dmarc_domain_policy
+    This is the policy declared in the DMARC record.  Valid values
+    are "none", "reject" and "quarantine".  It is blank when there
+    is any error, including no DMARC record.
+
   o $dmarc_ar_header
     This is the entire Authentication-Results header which you can
     add using an add_header modifier.
@@ -825,6 +731,9 @@ b. Configure, somewhere before the DATA ACL, the control option to
   warn    !domains       = +screwed_up_dmarc_records
           control        = dmarc_enable_forensic
 
+  warn    condition      = (lookup if destined to mailing list)
+          set acl_m_mailing_list = 1
+
 (DATA ACL)
   warn    dmarc_status   = accept : none : off
           !authenticated = *
@@ -840,96 +749,113 @@ b. Configure, somewhere before the DATA ACL, the control option to
           set $acl_m_quarantine = 1
           # Do something in a transport with this flag variable
 
+  deny    condition      = ${if eq{$dmarc_domain_policy}{reject}}
+          condition      = ${if eq{$acl_m_mailing_list}{1}}
+          message        = Messages from $dmarc_used_domain break mailing lists
+
   deny    dmarc_status   = reject
           !authenticated = *
           message        = Message from $domain_used_domain failed sender's DMARC policy, REJECT
 
 
 
-Transport post-delivery actions
+Event Actions
 --------------------------------------------------------------
 
-An arbitrary per-transport string can be expanded on successful delivery,
-and (for SMTP transports) a second string on deferrals caused by a host error.
+(Renamed from TPDA, Transport post-delivery actions)
+
+An arbitrary per-transport string can be expanded upon various transport events.
+Additionally a main-section configuration option can be expanded on some
+per-message events.
 This feature may be used, for example, to write exim internal log information
 (not available otherwise) into a database.
 
-In order to use the feature, you must set
+In order to use the feature, you must compile with
 
-EXPERIMENTAL_TPDA=yes
+EXPERIMENTAL_EVENT=yes
 
 in your Local/Makefile
 
-and define the expandable strings in the runtime config file, to
-be executed at end of delivery.
+and define one or both of
+- the event_action option in the transport
+- the event_action main option
+to be expanded when the event fires.
 
-Additionally, there are 6 more variables, available at end of
-delivery:
+A new variable, $event_name, is set to the event type when the
+expansion is done.  The current list of events is:
 
-tpda_delivery_ip             IP of host, which has accepted delivery
-tpda_delivery_port           Port of remote host which has accepted delivery
-tpda_delivery_fqdn           FQDN of host, which has accepted delivery
-tpda_delivery_local_part     local part of address being delivered
-tpda_delivery_domain         domain part of address being delivered
-tpda_delivery_confirmation   SMTP confirmation message
+ msg:complete          after  main       per message
+ msg:delivery          after  transport  per recipient
+ msg:host:defer                after  transport  per attempt
+ msg:fail:delivery     after  main       per recipient
+ msg:fail:internal     after  main       per recipient
+ tcp:connect           before transport  per connection
+ tcp:close             after  transport  per connection
+ tls:cert              before both       per certificate in verification chain
+ smtp:connect          after  transport  per connection
 
-In case of a deferral caused by a host-error:
-tpda_defer_errno             Error number
-tpda_defer_errstr            Error string possibly containing more details
+The expansion is called for all event types, and should use the $event_name
+value to decide when to act.  The variable data is a colon-separated
+list, describing an event tree.
 
-The $router_name and $transport_name variables are also usable.
+There is an auxilary variable, $event_data, for which the
+content is event_dependent:
 
+       msg:delivery            smtp confirmation mssage
+       msg:host:defer          error string
+       tls:cert                verification chain depth
+       smtp:connect            smtp banner
 
-To take action after successful deliveries, set the following option
-on any transport of interest.
+The msg:host:defer event populates one extra variable, $event_defer_errno.
+
+The following variables are likely to be useful depending on the event type:
+
+       router_name, transport_name
+       local_part, domain
+       host, host_address, host_port
+       tls_out_peercert
+       lookup_dnssec_authenticated, tls_out_dane
+       sending_ip_address, sending_port
+       message_exim_id, verify_mode
 
-tpda_delivery_action
 
 An example might look like:
 
-tpda_delivery_action = \
-${lookup pgsql {SELECT * FROM record_Delivery( \
+event_action = ${if = {msg:delivery}{$event_name} \
+{${lookup pgsql {SELECT * FROM record_Delivery( \
     '${quote_pgsql:$sender_address_domain}',\
     '${quote_pgsql:${lc:$sender_address_local_part}}', \
-    '${quote_pgsql:$tpda_delivery_domain}', \
-    '${quote_pgsql:${lc:$tpda_delivery_local_part}}', \
-    '${quote_pgsql:$tpda_delivery_ip}', \
-    '${quote_pgsql:${lc:$tpda_delivery_fqdn}}', \
-    '${quote_pgsql:$message_exim_id}')}}
-
-The string is expanded after the delivery completes and any
-side-effects will happen.  The result is then discarded.
+    '${quote_pgsql:$domain}', \
+    '${quote_pgsql:${lc:$local_part}}', \
+    '${quote_pgsql:$host_address}', \
+    '${quote_pgsql:${lc:$host}}', \
+    '${quote_pgsql:$message_exim_id}')}} \
+} {}}
+
+The string is expanded when each of the supported events occur
+and any side-effects of the expansion will happen.
 Note that for complex operations an ACL expansion can be used.
 
 
-In order to log host deferrals, add the following option to an SMTP
-transport:
+The expansion of the event_action option should normally
+return an empty string.  Should it return anything else the
+following will be forced:
 
-tpda_host_defer_action
+       msg:delivery    (ignored)
+       msg:host:defer  (ignored)
+       msg:fail:delivery (ignored)
+       tcp:connect     do not connect
+       tcp:close       (ignored)
+       tls:cert        refuse verification
+       smtp:connect    close connection
 
-This is a private option of the SMTP transport. It is intended to
-log failures of remote hosts. It is executed only when exim has
-attempted to deliver a message to a remote host and failed due to
-an error which doesn't seem to be related to the individual
-message, sender, or recipient address.
-See section 47.2 of the exim documentation for more details on how
-this is determined.
+No other use is made of the result string.
 
-Example:
 
-tpda_host_defer_action = \
-${lookup mysql {insert into delivlog set \
-    msgid = '${quote_mysql:$message_exim_id}', \
-    senderlp = '${quote_mysql:${lc:$sender_address_local_part}}', \
-    senderdom = '${quote_mysql:$sender_address_domain}', \
-    delivlp = '${quote_mysql:${lc:$tpda_delivery_local_part}}', \
-    delivdom = '${quote_mysql:$tpda_delivery_domain}', \
-    delivip = '${quote_mysql:$tpda_delivery_ip}', \
-    delivport = '${quote_mysql:$tpda_delivery_port}', \
-    delivfqdn = '${quote_mysql:$tpda_delivery_fqdn}', \
-    deliverrno = '${quote_mysql:$tpda_defer_errno}', \
-    deliverrstr = '${quote_mysql:$tpda_defer_errstr}' \
-    }}
+Known issues:
+- the tls:cert event is only called for the cert chain elements
+  received over the wire, with GnuTLS.  OpenSSL gives the entire
+  chain including thse loaded locally.
 
 
 Redis Lookup
@@ -1021,6 +947,8 @@ Proxy Protocol Support
 Exim now has Experimental "Proxy Protocol" support.  It was built on
 specifications from:
 http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt
+Above URL revised May 2014 to change version 2 spec:
+http://git.1wt.eu/web?p=haproxy.git;a=commitdiff;h=afb768340c9d7e50d8e
 
 The purpose of this function is so that an application load balancer,
 such as HAProxy, can sit in front of several Exim servers and Exim
@@ -1066,10 +994,16 @@ Proxy Protocol server at 192.168.1.2 will look like this:
 
 3. In the ACL's the following expansion variables are available.
 
-proxy_host_address  The src IP of the proxy server making the connection
-proxy_host_port     The src port the proxy server is using
-proxy_session       Boolean, yes/no, the connected host is required to use
-                    Proxy Protocol.
+proxy_host_address   The (internal) src IP of the proxy server
+                     making the connection to the Exim server.
+proxy_host_port      The (internal) src port the proxy server is
+                     using to connect to the Exim server.
+proxy_target_address The dest (public) IP of the remote host to
+                     the proxy server.
+proxy_target_port    The dest port the remote host is using to
+                     connect to the proxy server.
+proxy_session        Boolean, yes/no, the connected host is required
+                     to use Proxy Protocol.
 
 There is no expansion for a failed proxy session, however you can detect
 it by checking if $proxy_session is true but $proxy_host is empty.  As
@@ -1089,11 +1023,34 @@ an example, in my connect ACL, I have:
                            [$sender_host_address] through proxy protocol \
                            host $proxy_host_address
 
-4. Runtime issues to be aware of:
+  # Possibly more clear
+  warn logwrite = Remote Source Address: $sender_host_address:$sender_host_port
+       logwrite = Proxy Target Address: $proxy_target_address:$proxy_target_port
+       logwrite = Proxy Internal Address: $proxy_host_address:$proxy_host_port
+       logwrite = Internal Server Address: $received_ip_address:$received_port
+
+
+4. Recommended ACL additions:
    - Since the real connections are all coming from your proxy, and the
      per host connection tracking is done before Proxy Protocol is
      evaluated, smtp_accept_max_per_host must be set high enough to
      handle all of the parallel volume you expect per inbound proxy.
+   - With the smtp_accept_max_per_host set so high, you lose the ability
+     to protect your server from massive numbers of inbound connections
+     from one IP.  In order to prevent your server from being DOS'd, you
+     need to add a per connection ratelimit to your connect ACL.  I
+     suggest something like this:
+
+  # Set max number of connections per host
+  LIMIT   = 5
+  # Or do some kind of IP lookup in a flat file or database
+  # LIMIT = ${lookup{$sender_host_address}iplsearch{/etc/exim/proxy_limits}}
+
+  defer   message        = Too many connections from this IP right now
+          ratelimit      = LIMIT / 5s / per_conn / strict
+
+
+5. Runtime issues to be aware of:
    - The proxy has 3 seconds (hard-coded in the source code) to send the
      required Proxy Protocol header after it connects.  If it does not,
      the response to any commands will be:
@@ -1112,7 +1069,7 @@ an example, in my connect ACL, I have:
      mail programs from working because that would require mail from
      localhost to use Proxy Protocol.  Again, not advised!
 
-5. Example of a refused connection because the Proxy Protocol header was
+6. Example of a refused connection because the Proxy Protocol header was
 not sent from a host configured to use Proxy Protocol.  In the example,
 the 3 second timeout occurred (when a Proxy Protocol banner should have
 been sent), the banner was displayed to the user, but all commands are
@@ -1128,6 +1085,153 @@ QUIT
 
 
 
+
+DANE
+------------------------------------------------------------
+DNS-based Authentication of Named Entities, as applied
+to SMTP over TLS, provides assurance to a client that
+it is actually talking to the server it wants to rather
+than some attacker operating a Man In The Middle (MITM)
+operation.  The latter can terminate the TLS connection
+you make, and make another one to the server (so both
+you and the server still think you have an encrypted
+connection) and, if one of the "well known" set of
+Certificate Authorities has been suborned - something
+which *has* been seen already (2014), a verifiable
+certificate (if you're using normal root CAs, eg. the
+Mozilla set, as your trust anchors).
+
+What DANE does is replace the CAs with the DNS as the
+trust anchor.  The assurance is limited to a) the possibility
+that the DNS has been suborned, b) mistakes made by the
+admins of the target server.   The attack surface presented
+by (a) is thought to be smaller than that of the set
+of root CAs.
+
+It also allows the server to declare (implicitly) that
+connections to it should use TLS.  An MITM could simply
+fail to pass on a server's STARTTLS.
+
+DANE scales better than having to maintain (and
+side-channel communicate) copies of server certificates
+for every possible target server.  It also scales
+(slightly) better than having to maintain on an SMTP
+client a copy of the standard CAs bundle.  It also
+means not having to pay a CA for certificates.
+
+DANE requires a server operator to do three things:
+1) run DNSSEC.  This provides assurance to clients
+that DNS lookups they do for the server have not
+been tampered with.  The domain MX record applying
+to this server, its A record, its TLSA record and
+any associated CNAME records must all be covered by
+DNSSEC.
+2) add TLSA DNS records.  These say what the server
+certificate for a TLS connection should be.
+3) offer a server certificate, or certificate chain,
+in TLS connections which is traceable to the one
+defined by (one of?) the TSLA records
+
+There are no changes to Exim specific to server-side
+operation of DANE.
+
+The TLSA record for the server may have "certificate
+usage" of DANE-TA(2) or DANE-EE(3).  The latter specifies
+the End Entity directly, i.e. the certificate involved
+is that of the server (and should be the sole one transmitted
+during the TLS handshake); this is appropriate for a
+single system, using a self-signed certificate.
+  DANE-TA usage is effectively declaring a specific CA
+to be used; this might be a private CA or a public,
+well-known one.  A private CA at simplest is just
+a self-signed certificate which is used to sign
+cerver certificates, but running one securely does
+require careful arrangement.  If a private CA is used
+then either all clients must be primed with it, or
+(probably simpler) the server TLS handshake must transmit
+the entire certificate chain from CA to server-certificate.
+If a public CA is used then all clients must be primed with it
+(losing one advantage of DANE) - but the attack surface is
+reduced from all public CAs to that single CA.
+DANE-TA is commonly used for several services and/or
+servers, each having a TLSA query-domain CNAME record,
+all of which point to a single TLSA record.
+
+The TLSA record should have a Selector field of SPKI(1)
+and a Matching Type field of SHA2-512(2).
+
+At the time of writing, https://www.huque.com/bin/gen_tlsa
+is useful for quickly generating TLSA records; and commands like
+
+  openssl x509 -in -pubkey -noout <certificate.pem \
+  | openssl rsa -outform der -pubin 2>/dev/null \
+  | openssl sha512 \
+  | awk '{print $2}'
+
+are workable for 4th-field hashes.
+
+For use with the DANE-TA model, server certificates
+must have a correct name (SubjectName or SubjectAltName).
+
+The use of OCSP-stapling should be considered, allowing
+for fast revocation of certificates (which would otherwise
+be limited by the DNS TTL on the TLSA records).  However,
+this is likely to only be usable with DANE-TA.  NOTE: the
+default of requesting OCSP for all hosts is modified iff
+DANE is in use, to:
+
+  hosts_request_ocsp = ${if or { {= {0}{$tls_out_tlsa_usage}} \
+                                {= {4}{$tls_out_tlsa_usage}} } \
+                         {*}{}}
+
+The (new) variable $tls_out_tlsa_usage is a bitfield with
+numbered bits set for TLSA record usage codes.
+The zero above means DANE was not in use,
+the four means that only DANE-TA usage TLSA records were
+found. If the definition of hosts_request_ocsp includes the
+string "tls_out_tlsa_usage", they are re-expanded in time to
+control the OCSP request.
+
+This modification of hosts_request_ocsp is only done if
+it has the default value of "*".  Admins who change it, and
+those who use hosts_require_ocsp, should consider the interaction
+with DANE in their OCSP settings.
+
+
+For client-side DANE there are two new smtp transport options,
+hosts_try_dane and hosts_require_dane.  They do the obvious thing.
+[ should they be domain-based rather than host-based? ]
+
+DANE will only be usable if the target host has DNSSEC-secured
+MX, A and TLSA records.
+
+A TLSA lookup will be done if either of the above options match
+and the host-lookup succeded using dnssec.
+If the TLSA lookup succeeds, a TLS connection will be required
+for the host.
+
+(TODO: specify when fallback happens vs. when the host is not used)
+
+If dane is in use the following transport options are ignored:
+  hosts_require_tls
+  tls_verify_hosts
+  tls_try_verify_hosts
+  tls_verify_certificates
+  tls_crl
+  tls_verify_cert_hostnames
+
+Currently dnssec_request_domains must be active (need to think about that)
+and dnssec_require_domains is ignored.
+
+If verification was successful using DANE then the "CV" item
+in the delivery log line will show as "CV=dane".
+
+There is a new variable $tls_out_dane which will have "yes" if
+verification succeeded using DANE and "no" otherwise (only useful
+in combination with EXPERIMENTAL_EVENT), and a new variable
+$tls_out_tlsa_usage (detailed above).
+
+
 --------------------------------------------------------------
 End of file
 --------------------------------------------------------------