X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/12d0043db4d843869ed6e85dcb1c87c17bc8b82e..e51c7be22dfccad376659a1a46cee93c9979bbf7:/doc/doc-txt/experimental-spec.txt diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt index 9f5999093..588543454 100644 --- a/doc/doc-txt/experimental-spec.txt +++ b/doc/doc-txt/experimental-spec.txt @@ -6,34 +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 -------------------------------------------------------------- @@ -69,7 +41,8 @@ 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". +or with GnuTLS 3.1.3 or later, 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 @@ -83,14 +56,21 @@ 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. +Under OpenSSL 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. +Also, given EXPERIMENTAL_OCSP, the smtp transport gains two options: +- "hosts_require_ocsp"; a host-list for which an OCSP Stapling +is requested and required for the connection to proceed. The default +value is empty. +- "hosts_request_ocsp"; a host-list for which (additionally) an OCSP +Stapling is requested (but not necessarily verified). The default +value is "*" meaning that requests are made unless configured +otherwise. + +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 @@ -99,6 +79,9 @@ 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). +Note that the proof only covers the terminal server certificate, +not any of the chain from CA to it. + 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. @@ -107,8 +90,8 @@ OCSP files and somehow handling multiple files. 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 + One failure mode seen was the OCSP Signer cert expiring before the end + of validity of the OCSP proof. The checking done by Exim/OpenSSL noted this as invalid overall, but the re-fetch script did not. @@ -452,15 +435,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 +499,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 @@ -755,11 +744,13 @@ mean, refer to the DMARC website above. Valid strings are: rejecting the email. o quarantine The DMARC check failed and the library recommends keeping it for further inspection. + o none The DMARC check passed and the library recommends + no specific action, neutral. o norecord No policy section in the DMARC record for this sender domain. o nofrom Unable to determine the domain of the sender. - o none There is no DMARC record for this sender domain. - o error Library error or dns error. + o temperror Library error or dns error. + o off The DMARC check was disabled for this email. You can prefix each string with an exclamation mark to invert its meaning, for example "!accept" will match all results but @@ -771,7 +762,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 @@ -779,7 +770,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. @@ -788,6 +782,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. @@ -823,6 +822,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 = * @@ -838,12 +840,331 @@ 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 +-------------------------------------------------------------- + +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. +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 + +EXPERIMENTAL_TPDA=yes + +in your Local/Makefile + +and define the expandable strings in the runtime config file, to +be executed at end of delivery. + +Additionally, there are 6 more variables, available at end of +delivery: + +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 + +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 $router_name and $transport_name variables are also usable. + + +To take action after successful deliveries, set the following option +on any transport of interest. + +tpda_delivery_action + +An example might look like: + +tpda_delivery_action = \ +${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. +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: + +tpda_host_defer_action + +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 +-------------------------------------------------------------- + +Redis is open source advanced key-value data store. This document +does not explain the fundamentals, you should read and understand how +it works by visiting the website at http://www.redis.io/. + +Redis lookup support is added via the hiredis library. Visit: + + https://github.com/redis/hiredis + +to obtain a copy, or find it in your operating systems package repository. +If building from source, this description assumes that headers will be in +/usr/local/include, and that the libraries are in /usr/local/lib. + +1. In order to build exim with Redis lookup support add + +EXPERIMENTAL_REDIS=yes + +to your Local/Makefile. (Re-)build/install exim. exim -d should show +Experimental_Redis in the line "Support for:". + +EXPERIMENTAL_REDIS=yes +LDFLAGS += -lhiredis +# CFLAGS += -I/usr/local/include +# LDFLAGS += -L/usr/local/lib + +The first line sets the feature to include the correct code, and +the second line says to link the hiredis libraries into the +exim binary. The commented out lines should be uncommented if you +built hiredis from source and installed in the default location. +Adjust the paths if you installed them elsewhere, but you do not +need to uncomment them if an rpm (or you) installed them in the +package controlled locations (/usr/include and /usr/lib). + + +2. Use the following global settings to configure Redis lookup support: + +Required: +redis_servers This option provides a list of Redis servers + and associated connection data, to be used in + conjunction with redis lookups. The option is + only available if Exim is configured with Redis + support. + +For example: + +redis_servers = 127.0.0.1/10/ - using database 10 with no password +redis_servers = 127.0.0.1//password - to make use of the default database of 0 with a password +redis_servers = 127.0.0.1// - for default database of 0 with no password + +3. Once you have the Redis servers defined you can then make use of the +experimental Redis lookup by specifying ${lookup redis{}} in a lookup query. + +4. Example usage: + +(Host List) +hostlist relay_from_ips = <\n ${lookup redis{SMEMBERS relay_from_ips}} + +Where relay_from_ips is a Redis set which contains entries such as "192.168.0.0/24" "10.0.0.0/8" and so on. +The result set is returned as +192.168.0.0/24 +10.0.0.0/8 +.. +. + +(Domain list) +domainlist virtual_domains = ${lookup redis {HGET $domain domain}} + +Where $domain is a hash which includes the key 'domain' and the value '$domain'. + +(Adding or updating an existing key) +set acl_c_spammer = ${if eq{${lookup redis{SPAMMER_SET}}}{OK}} + +Where SPAMMER_SET is a macro and it is defined as + +"SET SPAMMER " + +(Getting a value from Redis) + +set acl_c_spam_host = ${lookup redis{GET...}} + + +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 +will log the IP that is connecting to the proxy server instead of +the IP of the proxy server when it connects to Exim. It resets the +$sender_address_host and $sender_address_port to the IP:port of the +connection to the proxy. It also re-queries the DNS information for +this new IP address so that the original sender's hostname and IP +get logged in the Exim logfile. There is no logging if a host passes or +fails Proxy Protocol negotiation, but it can easily be determined and +recorded in an ACL (example is below). + +1. To compile Exim with Proxy Protocol support, put this in +Local/Makefile: + +EXPERIMENTAL_PROXY=yes + +2. Global configuration settings: + +proxy_required_hosts = HOSTLIST + +The proxy_required_hosts option will require any IP in that hostlist +to use Proxy Protocol. The specification of Proxy Protocol is very +strict, and if proxy negotiation fails, Exim will not allow any SMTP +command other than QUIT. (See end of this section for an example.) +The option is expanded when used, so it can be a hostlist as well as +string of IP addresses. Since it is expanded, specifying an alternate +separator is supported for ease of use with IPv6 addresses. + +To log the IP of the proxy in the incoming logline, add: + log_selector = +proxy + +A default incoming logline (wrapped for appearance) will look like this: + + 2013-11-04 09:25:06 1VdNti-0001OY-1V <= me@example.net + H=mail.example.net [1.2.3.4] P=esmtp S=433 + +With the log selector enabled, an email that was proxied through a +Proxy Protocol server at 192.168.1.2 will look like this: + + 2013-11-04 09:25:06 1VdNti-0001OY-1V <= me@example.net + H=mail.example.net [1.2.3.4] P=esmtp PRX=192.168.1.2 S=433 + +3. In the ACL's the following expansion variables are available. + +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 +an example, in my connect ACL, I have: + + warn condition = ${if and{ {bool{$proxy_session}} \ + {eq{$proxy_host_address}{}} } } + log_message = Failed required proxy protocol negotiation \ + from $sender_host_name [$sender_host_address] + + warn condition = ${if and{ {bool{$proxy_session}} \ + {!eq{$proxy_host_address}{}} } } + # But don't log health probes from the proxy itself + condition = ${if eq{$proxy_host_address}{$sender_host_address} \ + {false}{true}} + log_message = Successfully proxied from $sender_host_name \ + [$sender_host_address] through proxy protocol \ + host $proxy_host_address + + # 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. Runtime issues to be aware of: + - 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. + - 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: + "503 Command refused, required Proxy negotiation failed" + - If the incoming connection is configured in Exim to be a Proxy + Protocol host, but the proxy is not sending the header, the banner + does not get sent until the timeout occurs. If the sending host + sent any input (before the banner), this causes a standard Exim + synchronization error (i.e. trying to pipeline before PIPELINING + was advertised). + - This is not advised, but is mentioned for completeness if you have + a specific internal configuration that you want this: If the Exim + server only has an internal IP address and no other machines in your + organization will connect to it to try to send email, you may + simply set the hostlist to "*", however, this will prevent local + 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 +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 +rejected except for QUIT: + +# nc mail.example.net 25 +220-mail.example.net, ESMTP Exim 4.82+proxy, Mon, 04 Nov 2013 10:45:59 +220 -0800 RFC's enforced +EHLO localhost +503 Command refused, required Proxy negotiation failed +QUIT +221 mail.example.net closing connection + + + +Certificate name checking +-------------------------------------------------------------- +The X509 certificates used for TLS are supposed be verified +that they are owned by the expected host. The coding of TLS +support to date has not made these checks. + +If built with EXPERIMENTAL_CERTNAMES defined, code is +included to do so, and a new smtp transport option +"tls_verify_cert_hostname" supported which takes a list of +names for which the checks must be made. The host must +also be in "tls_verify_hosts". + +Both Subject and Subject-Alternate-Name certificate fields +are supported, as are wildcard certificates (limited to +a single wildcard being the initial component of a 3-or-more +component FQDN). + + -------------------------------------------------------------- End of file