liable to incompatible change.
-Brightmail AntiSpam (BMI) suppport
+Brightmail AntiSpam (BMI) support
--------------------------------------------------------------
Brightmail AntiSpam is a commercial package. Please see
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
-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
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
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.
+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.
-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:
+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.
-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 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:<d3@myhost.test.ex>: 550 hard error
+Rationale:
+ This string sometimes give extra information over the
+ existing (already available) Diagnostic-Code field.
-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
-
-
-
-Event Actions
---------------------------------------------------------------
-(Renamed from TPDA, Transport post-delivery actions)
+Note that non-RFC-documented field names and data types are used.
-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 compile with
+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/
-EXPERIMENTAL_EVENT=yes
+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.
-in your Local/Makefile
+Visit https://github.com/LMDB/lmdb to download the library or find it in your
+operating systems package repository.
-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.
-
-A new variable, $event_name, is set to the event type when the
-expansion is done. The current list of events is:
+If building from source, this description assumes that headers will be in
+/usr/local/include, and that the libraries are in /usr/local/lib.
- 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
+1. In order to build exim with LMDB lookup support add or uncomment
-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.
+EXPERIMENTAL_LMDB=yes
-There is an auxilary variable, $event_data, for which the
-content is event_dependent:
+to your Local/Makefile. (Re-)build/install exim. exim -d should show
+Experimental_LMDB in the line "Support for:".
- msg:delivery smtp confirmation mssage
- msg:host:defer error string
- tls:cert verification chain depth
- smtp:connect smtp banner
+EXPERIMENTAL_LMDB=yes
+LDFLAGS += -llmdb
+# CFLAGS += -I/usr/local/include
+# LDFLAGS += -L/usr/local/lib
-The msg:host:defer event populates one extra variable, $event_defer_errno.
+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).
-The following variables are likely to be useful depending on the event type:
+2. Create your LMDB files, you can use the mdb_load utility which is
+part of the LMDB distribution our your favourite language bindings.
- 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
+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}}
-An example might look like:
-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:$domain}', \
- '${quote_pgsql:${lc:$local_part}}', \
- '${quote_pgsql:$host_address}', \
- '${quote_pgsql:${lc:$host}}', \
- '${quote_pgsql:$message_exim_id}')}} \
-} {}}
+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.
-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.
+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.
+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.
-The expansion of the event_action option should normally
-return an empty string. Should it return anything else the
-following will be forced:
+The mailscanner package is one of the processes that can take advantage
+of this transport to filter email.
- 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
+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.
-No other use is made of the result string.
+The transport only takes one option:
+* directory - This is used to specify the directory messages should be
+copied to. Expanded.
-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.
+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.
+Sample configuration:
-Redis Lookup
---------------------------------------------------------------
+(Router)
-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/.
+scan:
+ driver = accept
+ transport = scan
-Redis lookup support is added via the hiredis library. Visit:
+(Transport)
- https://github.com/redis/hiredis
+scan:
+ driver = queuefile
+ directory = /var/spool/baruwa-scanner/input
-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
+In order to build exim with Queuefile transport support add or uncomment
-EXPERIMENTAL_REDIS=yes
+EXPERIMENTAL_QUEUEFILE=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.
+Experimental_QUEUEFILE in the line "Support for:".
-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
+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.
+
+[RFC 8617 was published 2019/06. Draft 11 was 2018/01. A review of the
+changes has not yet been done]
-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 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.
-4. Example usage:
+Normally one would only bother doing ARC-signing when functioning as
+an intermediary. One might do verify for local destinations.
-(Host List)
-hostlist relay_from_ips = <\n ${lookup redis{SMEMBERS relay_from_ips}}
+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 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}}
+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 $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}}
+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.
-Where SPAMMER_SET is a macro and it is defined as
-
-"SET SPAMMER <some_value>"
-
-(Getting a value from Redis)
-
-set acl_c_spam_host = ${lookup redis{GET...}}
-
-
-Proxy Protocol Support
---------------------------------------------------------------
+ verify = arc/<acceptable_list> none:fail:pass
+
+ add_header = :at_start:${authresults {<admd-identifier>}}
-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. 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:
- "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!
-
-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
-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
-
-
-
-
-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).
+ Note that it would be wise to strip incoming messages of A-R headers
+ that claim to be from our own <admd-identifier>.
+
+There are four new variables:
+
+ $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 = <admd-identifier> : <selector> : <privkey> [ : <options> ]
+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[=<val>] Add an x= tag to the generated AMS header, with an expiry time.
+ If the value <val> 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
--------------------------------------------------------------