X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/4466248715466b6f251454283642b74de65e9d9a..6397b292615a5ffb9fdb5bd305736e2ef5f00e0d:/doc/doc-txt/experimental-spec.txt?ds=sidebyside diff --git a/doc/doc-txt/experimental-spec.txt b/doc/doc-txt/experimental-spec.txt index 1ec323433..5193f1729 100644 --- a/doc/doc-txt/experimental-spec.txt +++ b/doc/doc-txt/experimental-spec.txt @@ -6,126 +6,7 @@ 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, -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 -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. - -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, 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 -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). - -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. - - 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 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. - - - - -Brightmail AntiSpam (BMI) suppport +Brightmail AntiSpam (BMI) support -------------------------------------------------------------- Brightmail AntiSpam is a commercial package. Please see @@ -161,7 +42,7 @@ These four steps are explained in more details below. 1) Adding support for BMI at compile time To compile with BMI support, you need to link Exim against - the Brighmail client SDK, consisting of a library + the Brightmail client SDK, consisting of a library (libbmiclient_single.so) and a header file (bmi_api.h). You'll also need to explicitly set a flag in the Makefile to include BMI support in the Exim binary. Both can be achieved @@ -411,172 +292,18 @@ These four steps are explained in more details below. -Sender Policy Framework (SPF) support --------------------------------------------------------------- - -To learn more about SPF, visit http://www.openspf.org. This -document does not explain the SPF fundamentals, you should -read and understand the implications of deploying SPF on your -system before doing so. - -SPF support is added via the libspf2 library. Visit - - http://www.libspf2.org/ - -to obtain a copy, then compile and install it. By default, -this will put headers in /usr/local/include and the static -library in /usr/local/lib. - -To compile Exim with SPF support, set these additional flags in -Local/Makefile: - -EXPERIMENTAL_SPF=yes -CFLAGS=-DSPF -I/usr/local/include -EXTRALIBS_EXIM=-L/usr/local/lib -lspf2 - -This assumes that the libspf2 files are installed in -their default locations. - -You can now run SPF checks in incoming SMTP by using the "spf" -ACL condition in either the MAIL, RCPT or DATA ACLs. When -using it in the RCPT ACL, you can make the checks dependent on -the RCPT address (or domain), so you can check SPF records -only for certain target domains. This gives you the -possibility to opt-out certain customers that do not want -their mail to be subject to SPF checking. - -The spf condition takes a list of strings on its right-hand -side. These strings describe the outcome of the SPF check for -which the spf condition should succeed. Valid strings are: - - o pass The SPF check passed, the sending host - is positively verified by SPF. - o fail The SPF check failed, the sending host - is NOT allowed to send mail for the domain - in the envelope-from address. - o softfail The SPF check failed, but the queried - domain can't absolutely confirm that this - is a forgery. - o none The queried domain does not publish SPF - records. - o neutral The SPF check returned a "neutral" state. - This means the queried domain has published - a SPF record, but wants to allow outside - servers to send mail under its domain as well. - 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 -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 -strings matches the outcome of the SPF check, the condition -fails. - -Here is an example to fail forgery attempts from domains that -publish SPF records: - -/* ----------------- -deny message = $sender_host_address is not allowed to send mail from ${if def:sender_address_domain {$sender_address_domain}{$sender_helo_name}}. \ - Please see http://www.openspf.org/Why?scope=${if def:sender_address_domain {mfrom}{helo}};identity=${if def:sender_address_domain {$sender_address}{$sender_helo_name}};ip=$sender_host_address - spf = fail ---------------------- */ - -You can also give special treatment to specific domains: - -/* ----------------- -deny message = AOL sender, but not from AOL-approved relay. - sender_domains = aol.com - spf = fail:neutral ---------------------- */ - -Explanation: AOL publishes SPF records, but is liberal and -still allows non-approved relays to send mail from aol.com. -This will result in a "neutral" state, while mail from genuine -AOL servers will result in "pass". The example above takes -this into account and treats "neutral" like "fail", but only -for aol.com. Please note that this violates the SPF draft. - -When the spf condition has run, it sets up several expansion -variables. - - $spf_header_comment - This contains a human-readable string describing the outcome - of the SPF check. You can add it to a custom header or use - it for logging purposes. - - $spf_received - This contains a complete Received-SPF: header that can be - added to the message. Please note that according to the SPF - draft, this header must be added at the top of the header - list. Please see section 10 on how you can do this. - - Note: in case of "Best-guess" (see below), the convention is - to put this string in a header called X-SPF-Guess: instead. - - $spf_result - This contains the outcome of the SPF check in string form, - 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 - to the calling party. Useful for "fail". - -In addition to SPF, you can also perform checks for so-called -"Best-guess". Strictly speaking, "Best-guess" is not standard -SPF, but it is supported by the same framework that enables SPF -capability. Refer to http://www.openspf.org/FAQ/Best_guess_record -for a description of what it means. - -To access this feature, simply use the spf_guess condition in place -of the spf one. For example: - -/* ----------------- -deny message = $sender_host_address doesn't look trustworthy to me - spf_guess = fail ---------------------- */ - -In case you decide to reject messages based on this check, you -should note that although it uses the same framework, "Best-guess" -is NOT SPF, and therefore you should not mention SPF at all in your -reject message. - -When the spf_guess condition has run, it sets up the same expansion -variables as when spf condition is run, described above. - -Additionally, since Best-guess is not standardized, you may redefine -what "Best-guess" means to you by redefining spf_guess variable in -global config. For example, the following: - -/* ----------------- -spf_guess = v=spf1 a/16 mx/16 ptr ?all ---------------------- */ - -would relax host matching rules to a broader network range. - - SRS (Sender Rewriting Scheme) Support -------------------------------------------------------------- Exiscan currently includes SRS support via Miles Wilton's libsrs_alt library. The current version of the supported -library is 0.5. +library is 0.5, there are reports of 1.0 working. In order to use SRS, you must get a copy of libsrs_alt from -http://srs.mirtol.com/ +https://opsec.eu/src/srs/ + +(not the original source, which has disappeared.) Unpack the tarball, then refer to MTAs/README.EXIM to proceed. You need to set @@ -585,9 +312,40 @@ EXPERIMENTAL_SRS=yes in your Local/Makefile. +The following main-section options become available: + srs_config string + srs_hashlength int + srs_hashmin int + srs_maxage int + srs_secrets string + srs_usehash bool + srs_usetimestamp bool + +The redirect router gains these options (all of type string, unset by default): + srs + srs_alias + srs_condition + srs_dbinsert + srs_dbselect + +The following variables become available: + $srs_db_address + $srs_db_key + $srs_orig_recipient + $srs_orig_sender + $srs_recipient + $srs_status + +The predefined feature-macro _HAVE_SRS will be present. +Additional delivery log line elements, tagged with "SRS=" will show the srs sender. +For configuration information see https://github.com/Exim/exim/wiki/SRS . + + + DCC Support -------------------------------------------------------------- +Distributed Checksum Clearinghouse; http://www.rhyolite.com/dcc/ *) Building exim @@ -657,520 +415,326 @@ Then set something like mout-xforward.gmx.net 82.165.159.12 mout.gmx.net 212.227.15.16 -Use a reasonable IP. eg. one the sending cluster acutally uses. +Use a reasonable IP. eg. one the sending cluster actually uses. -DMARC Support --------------------------------------------------------------- -DMARC combines feedback from SPF, DKIM, and header From: in order -to attempt to provide better indicators of the authenticity of an -email. This document does not explain the fundamentals, you -should read and understand how it works by visiting the website at -http://www.dmarc.org/. -DMARC support is added via the libopendmarc library. Visit: +DSN extra information +--------------------- +If compiled with EXPERIMENTAL_DSN_INFO extra information will be added +to DSN fail messages ("bounces"), when available. The intent is to aid +tracing of specific failing messages, when presented with a "bounce" +complaint and needing to search logs. - http://sourceforge.net/projects/opendmarc/ - -to obtain a copy, or find it in your favorite rpm 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. To compile Exim with DMARC support, you must first enable SPF. -Please read the above section on enabling the EXPERIMENTAL_SPF -feature. You must also have DKIM support, so you cannot set the -DISABLE_DKIM feature. Once both of those conditions have been met -you can enable DMARC in Local/Makefile: - -EXPERIMENTAL_DMARC=yes -LDFLAGS += -lopendmarc -# 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 libopendmarc libraries into the -exim binary. The commented out lines should be uncommented if you -built opendmarc 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). +The remote MTA IP address, with port number if nonstandard. +Example: + Remote-MTA: X-ip; [127.0.0.1]:587 +Rationale: + Several addresses may correspond to the (already available) + dns name for the remote MTA. -2. Use the following global settings to configure DMARC: - -Required: -dmarc_tld_file Defines the location of a text file of valid - top level domains the opendmarc library uses - during domain parsing. Maintained by Mozilla, - the most current version can be downloaded - from a link at http://publicsuffix.org/list/. - -Optional: -dmarc_history_file Defines the location of a file to log results - of dmarc verification on inbound emails. The - contents are importable by the opendmarc tools - which will manage the data, send out DMARC - reports, and expire the data. Make sure the - directory of this file is writable by the user - exim runs as. - -dmarc_forensic_sender The email address to use when sending a - forensic report detailing alignment failures - if a sender domain's dmarc record specifies it - and you have configured Exim to send them. - Default: do-not-reply@$default_hostname - - -3. By default, the DMARC processing will run for any remote, -non-authenticated user. It makes sense to only verify DMARC -status of messages coming from remote, untrusted sources. You can -use standard conditions such as hosts, senders, etc, to decide that -DMARC verification should *not* be performed for them and disable -DMARC with a control setting: - - control = dmarc_disable_verify - -A DMARC record can also specify a "forensic address", which gives -exim an email address to submit reports about failed alignment. -Exim does not do this by default because in certain conditions it -results in unintended information leakage (what lists a user might -be subscribed to, etc). You must configure exim to submit forensic -reports to the owner of the domain. If the DMARC record contains a -forensic address and you specify the control statement below, then -exim will send these forensic emails. It's also advised that you -configure a dmarc_forensic_sender because the default sender address -construction might be inadequate. - - control = dmarc_forensic_enable - -(AGAIN: You can choose not to send these forensic reports by simply -not putting the dmarc_forensic_enable control line at any point in -your exim config. If you don't tell it to send them, it will not -send them.) - -There are no options to either control. Both must appear before -the DATA acl. - - -4. You can now run DMARC checks in incoming SMTP by using the -"dmarc_status" ACL condition in the DATA ACL. You are required to -call the spf condition first in the ACLs, then the "dmarc_status" -condition. Putting this condition in the ACLs is required in order -for a DMARC check to actually occur. All of the variables are set -up before the DATA ACL, but there is no actual DMARC check that -occurs until a "dmarc_status" condition is encountered in the ACLs. - -The dmarc_status condition takes a list of strings on its -right-hand side. These strings describe recommended action based -on the DMARC check. To understand what the policy recommendations -mean, refer to the DMARC website above. Valid strings are: - - o accept The DMARC check passed and the library recommends - accepting the email. - o reject The DMARC check failed and the library recommends - 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 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 -"accept". The string list is evaluated left-to-right in a -short-circuit fashion. When a string matches the outcome of the -DMARC check, the condition succeeds. If none of the listed -strings matches the outcome of the DMARC check, the condition -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. - -Several expansion variables are set before the DATA ACL is -processed, and you can use them in this ACL. The following -expansion variables are available: - - o $dmarc_status - This is a one word status indicating what the DMARC library - 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. - - o $dmarc_used_domain - 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. - - -5. How to enable DMARC advanced operation: -By default, Exim's DMARC configuration is intended to be -non-intrusive and conservative. To facilitate this, Exim will not -create any type of logging files without explicit configuration by -you, the admin. Nor will Exim send out any emails/reports about -DMARC issues without explicit configuration by you, the admin (other -than typical bounce messages that may come about due to ACL -processing or failure delivery issues). - -In order to log statistics suitable to be imported by the opendmarc -tools, you need to: -a. Configure the global setting dmarc_history_file. -b. Configure cron jobs to call the appropriate opendmarc history - import scripts and truncating the dmarc_history_file. - -In order to send forensic reports, you need to: -a. Configure the global setting dmarc_forensic_sender. -b. Configure, somewhere before the DATA ACL, the control option to - enable sending DMARC forensic reports. - - -6. Example usage: -(RCPT ACL) - warn domains = +local_domains - hosts = +local_hosts - control = dmarc_disable_verify - - 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 = * - log_message = DMARC DEBUG: $dmarc_status $dmarc_used_domain - add_header = $dmarc_ar_header - - warn dmarc_status = !accept - !authenticated = * - log_message = DMARC DEBUG: '$dmarc_status' for $dmarc_used_domain - - warn dmarc_status = quarantine - !authenticated = * - 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 --------------------------------------------------------------- +The remote MTA connect-time greeting. +Example: + X-Remote-MTA-smtp-greeting: X-str; 220 the.local.host.name ESMTP Exim x.yz Tue, 2 Mar 1999 09:44:33 +0000 +Rationale: + This string sometimes presents the remote MTA's idea of its + own name, and sometimes identifies the MTA software. -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. +The remote MTA response to HELO or EHLO. +Example: + X-Remote-MTA-helo-response: X-str; 250-the.local.host.name Hello localhost [127.0.0.1] +Limitations: + Only the first line of a multiline response is recorded. +Rationale: + This string sometimes presents the remote MTA's view of + the peer IP connecting to it. + +The reporting MTA detailed diagnostic. +Example: + X-Exim-Diagnostic: X-str; SMTP error from remote mail server after RCPT TO:: 550 hard error +Rationale: + This string sometimes give extra information over the + existing (already available) Diagnostic-Code field. -In order to use the feature, you must set -EXPERIMENTAL_TPDA=yes +Note that non-RFC-documented field names and data types are used. -in your Local/Makefile -and define the expandable strings in the runtime config file, to -be executed at end of delivery. +LMDB Lookup support +------------------- +LMDB is an ultra-fast, ultra-compact, crash-proof key-value embedded data store. +It is modeled loosely on the BerkeleyDB API. You should read about the feature +set as well as operation modes at https://symas.com/products/lightning-memory-mapped-database/ -Additionally, there are 6 more variables, available at end of -delivery: +LMDB single key lookup support is provided by linking to the LMDB C library. +The current implementation does not support writing to the LMDB database. -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 +Visit https://github.com/LMDB/lmdb to download the library or find it in your +operating systems package repository. -In case of a deferral caused by a host-error: -tpda_defer_errno Error number -tpda_defer_errstr Error string possibly containing more details +If building from source, this description assumes that headers will be in +/usr/local/include, and that the libraries are in /usr/local/lib. -The $router_name and $transport_name variables are also usable. +1. In order to build exim with LMDB lookup support add or uncomment +EXPERIMENTAL_LMDB=yes -To take action after successful deliveries, set the following option -on any transport of interest. +to your Local/Makefile. (Re-)build/install exim. exim -d should show +Experimental_LMDB in the line "Support for:". -tpda_delivery_action +EXPERIMENTAL_LMDB=yes +LDFLAGS += -llmdb +# CFLAGS += -I/usr/local/include +# LDFLAGS += -L/usr/local/lib -An example might look like: +The first line sets the feature to include the correct code, and +the second line says to link the LMDB libraries into the +exim binary. The commented out lines should be uncommented if you +built LMDB 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). -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}')}} +2. Create your LMDB files, you can use the mdb_load utility which is +part of the LMDB distribution our your favourite language bindings. -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. +3. Add the single key lookups to your exim.conf file, example lookups +are below. +${lookup{$sender_address_domain}lmdb{/var/lib/baruwa/data/db/relaydomains.mdb}{$value}} +${lookup{$sender_address_domain}lmdb{/var/lib/baruwa/data/db/relaydomains.mdb}{$value}fail} +${lookup{$sender_address_domain}lmdb{/var/lib/baruwa/data/db/relaydomains.mdb}} -In order to log host deferrals, add the following option to an SMTP -transport: -tpda_host_defer_action +Queuefile transport +------------------- +Queuefile is a pseudo transport which does not perform final delivery. +It simply copies the exim spool files out of the spool directory into +an external directory retaining the exim spool format. -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. +The spool files can then be processed by external processes and then +requeued into exim spool directories for final delivery. +However, note carefully the warnings in the main documentation on +qpool file formats. -Example: +The motivation/inspiration for the transport is to allow external +processes to access email queued by exim and have access to all the +information which would not be available if the messages were delivered +to the process in the standard email formats. -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 --------------------------------------------------------------- +The mailscanner package is one of the processes that can take advantage +of this transport to filter email. -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/. +The transport can be used in the same way as the other existing transports, +i.e by configuring a router to route mail to a transport configured with +the queuefile driver. -Redis lookup support is added via the hiredis library. Visit: +The transport only takes one option: - https://github.com/redis/hiredis +* directory - This is used to specify the directory messages should be +copied to. Expanded. -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. +The generic transport options (body_only, current_directory, disable_logging, +debug_print, delivery_date_add, envelope_to_add, event_action, group, +headers_add, headers_only, headers_remove, headers_rewrite, home_directory, +initgroups, max_parallel, message_size_limit, rcpt_include_affixes, +retry_use_local_part, return_path, return_path_add, shadow_condition, +shadow_transport, transport_filter, transport_filter_timeout, user) are +ignored. -1. In order to build exim with Redis lookup support add +Sample configuration: -EXPERIMENTAL_REDIS=yes +(Router) -to your Local/Makefile. (Re-)build/install exim. exim -d should show -Experimental_Redis in the line "Support for:". +scan: + driver = accept + transport = scan -EXPERIMENTAL_REDIS=yes -LDFLAGS += -lhiredis -# CFLAGS += -I/usr/local/include -# LDFLAGS += -L/usr/local/lib +(Transport) -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). +scan: + driver = queuefile + directory = /var/spool/baruwa-scanner/input -2. Use the following global settings to configure Redis lookup support: +In order to build exim with Queuefile transport support add or uncomment -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. +EXPERIMENTAL_QUEUEFILE=yes -For example: +to your Local/Makefile. (Re-)build/install exim. exim -d should show +Experimental_QUEUEFILE in the line "Support for:". -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. +ARC support +----------- +Specification: https://tools.ietf.org/html/draft-ietf-dmarc-arc-protocol-11 +Note that this is not an RFC yet, so may change. -4. Example usage: +[RFC 8617 was published 2019/06. Draft 11 was 2018/01. A review of the +changes has not yet been done] -(Host List) -hostlist relay_from_ips = <\n ${lookup redis{SMEMBERS relay_from_ips}} +ARC is intended to support the utility of SPF and DKIM in the presence of +intermediaries in the transmission path - forwarders and mailinglists - +by establishing a cryptographically-signed chain in headers. -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 -.. -. +Normally one would only bother doing ARC-signing when functioning as +an intermediary. One might do verify for local destinations. -(Domain list) -domainlist virtual_domains = ${lookup redis {HGET $domain domain}} +ARC uses the notion of a "ADministrative Management Domain" (ADMD). +Described in RFC 5598 (section 2.3), this is essentially a set of +mail-handling systems that mail transits that are all under the control +of one organisation. A label should be chosen to identify the ADMD. +Messages should be ARC-verified on entry to the ADMD, and ARC-signed on exit +from it. -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}} +Building with ARC Support +-- +Enable using EXPERIMENTAL_ARC=yes in your Local/Makefile. +You must also have DKIM present (not disabled), and you very likely +want to have SPF enabled. -Where SPAMMER_SET is a macro and it is defined as -"SET SPAMMER " +Verification +-- +An ACL condition is provided to perform the "verifier actions" detailed +in section 6 of the above specification. It may be called from the DATA ACL +and succeeds if the result matches any of a given list. +It also records the highest ARC instance number (the chain size) +and verification result for later use in creating an Authentication-Results: +standard header. -(Getting a value from Redis) + verify = arc/ none:fail:pass -set acl_c_spam_host = ${lookup redis{GET...}} + add_header = :at_start:${authresults {}} + Note that it would be wise to strip incoming messages of A-R headers + that claim to be from our own . -Proxy Protocol Support --------------------------------------------------------------- +There are four new variables: -Exim now has Experimental "Proxy Protocol" support. It was built on -specifications from: -http://haproxy.1wt.eu/download/1.5/doc/proxy-protocol.txt - -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 + $arc_state One of pass, fail, none + $arc_state_reason (if fail, why) + $arc_domains colon-sep list of ARC chain domains, in chain order. + problematic elements may have empty list elements + $arc_oldest_pass lowest passing instance number of chain +Example: + logwrite = oldest-p-ams: <${reduce {$lh_ARC-Authentication-Results:} \ + {} \ + {${if = {$arc_oldest_pass} \ + {${extract {i}{${extract {1}{;}{$item}}}}} \ + {$item} {$value}}} \ + }> + +Receive log lines for an ARC pass will be tagged "ARC". + + +Signing +-- +arc_sign = : : [ : ] +An option on the smtp transport, which constructs and prepends to the message +an ARC set of headers. The textually-first Authentication-Results: header +is used as a basis (you must have added one on entry to the ADMD). +Expanded as a whole; if unset, empty or forced-failure then no signing is done. +If it is set, all of the first three elements must be non-empty. + +The fourth element is optional, and if present consists of a comma-separated list +of options. The options implemented are + + timestamps Add a t= tag to the generated AMS and AS headers, with the + current time. + expire[=] Add an x= tag to the generated AMS header, with an expiry time. + If the value is an plain number it is used unchanged. + If it starts with a '+' then the following number is added + to the current time, as an offset in seconds. + If a value is not given it defaults to a one month offset. + +[As of writing, gmail insist that a t= tag on the AS is mandatory] + +Caveats: + * There must be an Authentication-Results header, presumably added by an ACL + while receiving the message, for the same ADMD, for arc_sign to succeed. + This requires careful coordination between inbound and outbound logic. + + Only one A-R header is taken account of. This is a limitation versus + the ARC spec (which says that all A-R headers from within the ADMD must + be used). + + * If passing a message to another system, such as a mailing-list manager + (MLM), between receipt and sending, be wary of manipulations to headers made + by the MLM. + + For instance, Mailman with REMOVE_DKIM_HEADERS==3 might improve + deliverability in a pre-ARC world, but that option also renames the + Authentication-Results header, which breaks signing. + + * Even if you use multiple DKIM keys for different domains, the ARC concept + should try to stick to one ADMD, so pick a primary domain and use that for + AR headers and outbound signing. + +Signing is not compatible with cutthrough delivery; any (before expansion) +value set for the option will result in cutthrough delivery not being +used via the transport in question. + + + + +TLS Session Resumption +---------------------- +TLS Session Resumption for TLS 1.2 and TLS 1.3 connections can be used (defined +in RFC 5077 for 1.2). The support for this can be included by building with +EXPERIMENTAL_TLS_RESUME defined. This requires GnuTLS 3.6.3 or OpenSSL 1.1.1 +(or later). + +Session resumption (this is the "stateless" variant) involves the server sending +a "session ticket" to the client on one connection, which can be stored by the +client and used for a later session. The ticket contains sufficient state for +the server to reconstruct the TLS session, avoiding some expensive crypto +calculation and one full packet roundtrip time. + +Operational cost/benefit: + The extra data being transmitted costs a minor amount, and the client has + extra costs in storing and retrieving the data. + + In the Exim/Gnutls implementation the extra cost on an initial connection + which is TLS1.2 over a loopback path is about 6ms on 2017-laptop class hardware. + The saved cost on a subsequent connection is about 4ms; three or more + connections become a net win. On longer network paths, two or more + connections will have an average lower startup time thanks to the one + saved packet roundtrip. TLS1.3 will save the crypto cpu costs but not any + packet roundtrips. + + Since a new hints DB is used, the hints DB maintenance should be updated + to additionally handle "tls". + +Security aspects: + The session ticket is encrypted, but is obviously an additional security + vulnarability surface. An attacker able to decrypt it would have access + all connections using the resumed session. + The session ticket encryption key is not committed to storage by the server + and is rotated regularly (OpenSSL: 1hr, and one previous key is used for + overlap; GnuTLS 6hr but does not specify any overlap). + Tickets have limited lifetime (2hr, and new ones issued after 1hr under + OpenSSL. GnuTLS 2hr, appears to not do overlap). + + There is a question-mark over the security of the Diffie-Helman parameters + used for session negotiation. TBD. q-value; cf bug 1895 + +Observability: + New log_selector "tls_resumption", appends an asterisk to the tls_cipher "X=" + element. + + Variables $tls_{in,out}_resumption have bits 0-4 indicating respectively + support built, client requested ticket, client offered session, + server issued ticket, resume used. A suitable decode list is provided + in the builtin macro _RESUME_DECODE for ${listextract {}{}}. + +Issues: + In a resumed session: + $tls_{in,out}_cipher will have values different to the original (under GnuTLS) + $tls_{in,out}_ocsp will be "not requested" or "no response", and + hosts_require_ocsp will fail --------------------------------------------------------------