Support secondary-separator specifier for MX, SRV and TLSA dnsdb lookups
[exim.git] / doc / doc-txt / experimental-spec.txt
index 333307b74e9f1a7d78c5368ef2c572b1af19d340..e7a0d06682e95e507edf0d8c376bb1b6788e9a65 100644 (file)
@@ -762,87 +762,94 @@ b. Configure, somewhere before the DATA ACL, the control option to
 Transport post-delivery actions
 --------------------------------------------------------------
 
-An arbitrary per-transport string can be expanded on successful delivery,
+An arbitrary per-transport string can be expanded upon various transport events
 and (for SMTP transports) a second string on deferrals caused by a host error.
+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
 
 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 tpda_event_action option in the transport
+- the delivery_event_action
+to be expanded when the event fires.
 
-Additionally, there are 6 more variables, available at end of
-delivery:
+A new variable, $tpda_event, 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            main            per message
+       msg:delivery            transport       per recipient
+       msg:host:defer          transport       per attempt
+       msg:fail:delivery       main            per recipient
+       msg:fail:internal       main            per recipient
+       tcp:connect             transport       per connection
+       tcp:close               transport       per connection
+       tls:cert                transport       per certificate in verification chain
+       smtp:connect            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 $tpda_event
+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, $tpda_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, $tpda_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
 
-tpda_delivery_action
 
 An example might look like:
 
-tpda_delivery_action = \
-${lookup pgsql {SELECT * FROM record_Delivery( \
+tpda_event_action = ${if = {msg:delivery}{$tpda_event} \
+{${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
+    '${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 for each of the supported events and any
 side-effects will happen.  The result is then discarded.
 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 tpda_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.
 
-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}' \
-    }}
 
 
 Redis Lookup
@@ -1171,6 +1178,10 @@ 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
@@ -1181,7 +1192,10 @@ 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.
+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,
@@ -1192,12 +1206,12 @@ 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
+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
+  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
@@ -1209,43 +1223,84 @@ 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
+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 fiels of SHA2-512(2).
+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
+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).
+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}} } \
+                         {*}{}}
 
-For client-side DANE there is a new smtp transport option,
-hosts_try_dane.  It does the obvious thing.
-[ may add a hosts_require_dane, too? ]
-[ should it be domain-based rather than host-based? ]
+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
-  hosts_require_ocsp           (might rethink those two)
-  hosts_request_ocsp
 
 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_TPDA), and a new variable
+$tls_out_tlsa_usage (detailed above).
+
 
 --------------------------------------------------------------
 End of file