zdkimfilter.conf(5)

NAME
zdkimfilter.conf - zdkimfilter configuration file

SYNTAX
The file consists of zero or more lines.

    logic line = [ "#" comment ] |

        [ keyword ] [ name ] [ "=" ] [ value ]

Backslashes ("\") can be used to wrap multiple physical lines into a single logical one, also comments.

There are two keywords:

include
    In this case no name is given, the value is the file to be included. Files are included recursively at the point where this keyword is found. A maximum of 20 recursive inclusions is supported.

override
    This keyword allows to override a previously assigned value. In any case, the last assignment is the value used during subsequent processing, but a warning is issued on re-assigning unless override is used.

The name is always given, except for include. Valid names are shown in OPTIONS.

The equal sign ("=") is always optional. You must use it if a file name starts with that character.

Value types can be strings, array of strings, integers, or boolean, depending on the name.

NOTE
The configuration file can be reloaded by sending a HUP signal to the parent process, except for the "all_mode" item which needs restarting the filter.

Use "zdkimsign --config" to check if the file is valid.

Names in the following section are in the same order as output by the above command, rather than alphabetically.

OPTIONS
Valid names and their types are listed below. All boolean values default to "N", while "Y" is assumed if the name is specified but the value is omitted. Most values default to NULL, otherwise, the default values are mentioned after the relevant description. To see default values it is also possible to run:

"zdkimsign -f "" --config"

The database options, "db_*", are documented in zfilter_db(1).

all_mode bool
    Courier runs all-mode filters after non-all-mode ones, in alphabetical order. Non-all-mode filters can be whitelisted by local filters. In addition, any global filter can whitelist the filters running after it.

    The value of this parameter determines in which directory zdkimfilter creates the socket which connects it to Courier. Therefore, changing this parameter will have no effect until the filter is reloaded.

trust_a_r bool
    Don't remove any Authentication-Results: (A-R) header field. Courier renames existing A-R fields since 0.71.0 if ALLOW_EXCLUSIVE is set. Set this option after enabling ALLOW_EXCLUSIVE in Courier's esmtpd.

verbose int
    Additional control on the amount of output. The filter prints to stderr, assuming that Courier's logger will capture it and send to syslog. Hence the amount of output can also be filtered by severity. Verbosity and severity are not strictly related. Verbosity is tentatively being used as follows (each level includes the preceding ones):

    0   Startup issues and totally unexpected errors.

    1   Failures and unexpected events.

    2   Unexpected Authentication-Results fields found on verifying. Missing domain on signing.

    3   Start/stop info, relevant verify results, sign errors, responses except 250.

    4   Response returned to Courier for each message.

    5   Verify errors or notices, except no signature found.

    6   Domain/selector used on signing, any A-R field found.

    7   No key on signing. Signature details and count of Authentication-Results fields written on verifying.

    8   More debugging; for example, key_choice_header processing.

    default: verbose = 3.

domain_keys string
    Directory for domain private keys.

    File names should match the domain name; for example, when signing for user@example.com, zdkimfilter looks for a file named example.com in this directory. If the file is a symbolic link, the basename of the target file is be used as the selector. See the signing section of zdkimfilter(8) for examples.

    Default: domain_keys = /etc/courier/filters/keys

header_canon_relaxed bool
body_canon_relaxed bool
    Canonicalization for header/body can be simple or relaxed. It is recommended to use "relaxed", especially for the header, because both Courier's SMTP client and some SMTP receivers alter white space in the header.

sign_rsa_sha1 bool
    The signing algorithm can be one of rsa-sha1, rsa-sha256, or ed25519-sha256. If it set, signing will force rsa-sha1, which is deprecated. If it is not set, signing will use a sha256 digest and an algorithm, rsa or ed25519, compatible with the first key found.

key_choice_header string
    Header fields that determine the signing domain. This is an array of strings. An element of the array can be either a header field name leading to a mailbox name, or one two special tokens, dash ("-") and star ("*"), which have the following meaning:

    -   Dash refers to the default_domain.

    *   Star refers to the user domain, if any, or the default_domain. The user domain is the domain of the user id, if it contains an "@". The user id, in turn, is either the authenticated user id as set by Courier's SMTPAUTH after calling the relevant authentication module, or the content of the RELAYCLIENT environment variable as set, for example in smtpaccess files if no SMTPAUTH takes place.

    The array elements are in order of decreasing preference. Field names are looked up in the message header, and the domain name is derived from any mailbox specification found in their value.

    This parameter is disabled when making ARC signatures.

    For example, with

        key_choice_header = from -

    then if a key and possibly a selector are defined for the domain in the From: header field, then they are used for signing, otherwise the default domain is used, irrespectively of the user id.

    If the array is empty, the default, the user domain is used. That is, the filter behaves as if:

        key_choice_header *

default_domain string
    It is used if no domain can be derived from the previous option, for example if it has a dash ("-") or the user id has no at-sign ("@"). It is empty by default.

sign_local int
    Whether to sign local messages. You need to set enablefiltering in courierd in order to filter local messages. You need to set this parameter in order to sign them. Possible values are:

    0 never sign local mail
    1 always sign local mail
    > 1 sign local mail unless the message already contains any DKIM-Signature.

    The default value is 2.

i_signer string
    The Agent or User Identifier (AUID) on behalf of which the signing domain is taking responsibility.

    The syntax is a standard email address where the local-part may be omitted. The domain part of the address must be the same as, or a subdomain of, the signing domain.

let_relayclient_alone bool
    If user is not authenticated, but has relay privileges and the content of the RELAYCLIENT environment variable is an at ("@") followed by a domain name, then zdkimfilter uses the domain name to sign the message, and then rewrites recipient addresses removing such trailing string and replacing the last percent ("%"), if any, with an at (<@>). This behavior is new in version 1.6. It can be disabled by setting this parameter.

    It is not necessary to set this parameter for typical "allow,RELAYCLIENT" settings where "RELAYCLIENT" is empty or doesn't start with an at (<@>).

selector string
    In case a selector cannot be determined following a soft link, then the selector specified here, if any, or the constant "s" will be used.

sign_hfields array
    header fields to be signed. This is a space-separated list of header field names. The default value is implemented in OpenDKIM according to RFC 6376 Sec. 5.4, with additions from RFCs 8058 and 9477:

        sign_hfields = From Reply-To Subject Date To Cc In-Reply-To References Resent-Date Resent-From Resent-Sender Resent-To Resent-Cc List-Id List-Help List-Unsubscribe List-Subscribe List-Post List-Owner List-Archive List-Unsubscribe-Post CFBL-Address CFBL-Feedback-ID

oversign_hfields array
    header fields to be oversigned, that is mentioned once more in the h= tag. That way adding a header field with the same name breaks the signature. The intent is to protect fields like From: which should be unique. This is a space-separated list of header field names. The default value is empty.

skip_hfields array
    header fields not to be signed; they are discarded at an earlier stage. This is a space-separated list of header field names. The default value is implemented in OpenDKIM according to RFC 6376 Sec. 5.4:

        skip_hfields = Return-Path Received Comments Keywords

xtag_value string
    Set an extension tag to be added to DKIM signatures. This string must be in the format "tag=value", without spaces around the equal sign.

no_signlen bool
    Set this to avoid specifying the l= parameter of the body length. Specifying the length enables the addition of text at the bottom of messages, so it was considered more permissive. However, if Content-Type: is not signed, having l= allows arbitrary modifications of the message, reducing the original body to a MIME prologue.

    Signing Content-Type: can hamper the ability to recover signatures after mailing list transformations. So it is actually more flexible to not set l=. On loading zdkimfilter, an error is logged if neither no_signlen nor signing Content-Type: are set, and l= is not set.

no_qp_conversion bool
    Set this to disable quoted-printable to base64 conversion. This conversion was introduced because quoted-printable encoding is very hard to recover. Signing a base64 is provides for more robust signatures.

    This parameter is automatically enabled when making ARC signatures.

min_key_bits int
    The minimal length of a DKIM key, in bits. This affects RSA keys used for signing as well as for verifying. Ed25519 keys have size = 256. The default value is 1024, according to RFC 8301 Sec. 3.2.

redact_received_auth string
    Rewrite the value of AUTH: in Courier's Received: header field. That value is the login id, so it is useful to know it. However, it may be a privacy violation and it may help password crackers. Full-featured redaction provides for replacing the given value with an obscured string obtained by scrambling the original value and a secret text. In that case, the redact utility can reconstruct the value, possibly up to character case, if the secret text did not change. If the redaction is not fully functional, because it was not compiled in, a warning is logged on startup and the obscured string is a constant.

    Just the first Received: field where AUTH: matches the authenticated user is changed.

    NOTE: don't configure for signing Received: or changing it will break the signature.

    NOTE: the scrambling used for obfuscation is NOT cryptographically secure.

    To enable this behavior, specify some secret text (1 to 256 chars) here. For example:

        redact_received_auth = This is the secret text (change and uncomment)

add_auth_pass bool
    Add an A-R field to signed outgoing messages. The field just says auth=pass, with the signing domain name, and no other details. It can be signed (see sign_hfields). It may be useful for messages delivered on the same server, which would get no A-R field otherwise.

    The field may be placed on the top of the header, on the bottom, or right before the header field which determined the key choice.

    This parameter is disabled when zdkimfilter is wrapped by zdkimsign.

tmp string
    Temporary directory. libopendkim uses /var/tmp by default. If you specify a value like /tmp/*, then zdkimfilter attempts to mkdir of it if it cannot stat it, on loading.

tempfail_on_error bool
    On some errors, e.g. out of memory, return 432 to have the sender retry; otherwise, just let the msg through unfiltered.

split_verify string
    Separate filter processes, one for verifying and one for signing. This is useful if you need authentication results to be available to a third filter which has to run before the signing filter.

    The string contains the executable name of the verifying processes.

    For example, to install "dkimfilter" (without "z") as a verifier, create a link with that name to zdkimfilter, in /usr/lib/filters. Then set

        split_verify = dkimfilter

    Invoke filterctl start dkimfilter to start the second process. Both processes read the same configuration file, but create sockets and pid files according to the executable name used to invoke them. In this example, the first process stops verifying as soon as it reloads the configuration.

    zdkimfilter can also run with a different configuration file. This can be done by embedding the new configuration filename in the link name; see "MULTIPLE FILTERS" in zdkimfilter. In that case, to have this filter sign only, it is sufficient to define split_verify with any string different from the program name. For example:

        split_verify = sign only

add_ztags bool
    DKIM signatures can have a copy of signed header fields values inside the signature field itself, tag "z=". That does not affect verification, but can be useful when investigating the reasons why a signature does not verify.

blocked_user_list string
    Filename of the list of blocked users. Users on this list can only send to the postmaster at the user's domain, if they authenticate. The user's domain is the domain in the user-id, if any, or the default_domain. The list is automatically updated when the query db_sql_check_user returns a non-zero reason. It can be updated at any time (creating a temporary file and then moving it can avoid race conditions.) zdkimfilter keeps the file in memory and reloads it when it realizes that it changed.

    A blocked_user_list could be used even without defining any database option, but an alternative means to add users to it has to be devised in that case. In any case, no mechanism is provided to remove users from such list. The assumption is that user's credentials have been hijacked, so user's password has to be changed, queued messages canceled, bounces removed, CSIRTs of any third party's hacked site notified, and finally it is a nice idea to set up monitoring and reporting of any further spam that the botnet will unwittingly continue to submit using the stolen credentials. I'm really far from automating such switch.

    Using a query, this works as an alternative to Courier's native ratefilter. See zfilter_db(8) for details on the query.

no_spf bool
    If Courier sets Received-SPF: pass for sender or helo, that is reported in A-R. This option may prevent such behavior.

save_from_anyway bool
    Save the From: header field even if it's not authenticated. If true, this can result in more incoming messages and domains being inserted in the database. This setting is overridden by publicsuffix, which implies even more domains can be stored although unauthenticated.

add_a_r_anyway bool
    Add an A-R field also if no signature nor other results had been found.

report_all_sigs bool
    If multiple signatures are found, normally only the most important ones are reported in the A-R field. By enabling this option, all the signatures are reported, in order of decreasing importance.

verify_one_domain bool
    If signatures by multiple domains are found, and database logging is enabled, all domains are verified. By enabling this option, only the first domain is verified, in order of decreasing importance.

disable_experimental bool
    Turn off experimental feature introduced in v3.0. For signing, this disables "Original-*:" header fields and conversion to base64. For verifying, it disables attempt to retry signatures with the modified header and/or body of the message.

noaddrrewrite bool
    Turn off address rewriting of To:, Reply-To:, From:, and Cc: header fields in outgoing mail.

    Courier sometimes wraps these header fields in an attempt to stay within 70 columns width. So zdkimfilter can apply the same algorithm before signing. Setting this parameter disables the rewriting. That is similar to the parameter with the same name in Courier esmtpd* config files.

    This parameter is automatically set when zdkimfilter is invoked via zdkimsign, as it seems that Courier rewriting works differently for messages submitted locally via sendmail.

still_allow_no_from bool
    Messages with no From: or multiple From: fields or such that the sender domain cannot be determined are illegal. The filter choked on them, and likely ended up issuing 432 Mail filter momentarily unavailable. Since v3.18 it rejects such messages, unless this flag is set.

checkhelo_if_no_auth bool
    This is a restricted version of BOFHCHECKHELO. When this parameter is set, messages are rejected if the HELO domain doesn't exist and either there is no authentication (SPF or DKIM) or the only authentication is a DKIM signature whose signer (the d= tag) is not a parent domain of the HELO domain. This still allows messages with d=example.com and HELO non.existing.something.example.com. (Spammers that don't know the machine name usually invent random names irrespective of the signature they replay.

max_signatures int
    The absolutely maximum number of signatures. Messages having more signatures than that are considered denial of service (DoS) attacks and rejected outright. The default value is 128.

log_dkim_order_above int
    The highest number of signatures you expect. If this is non-zero, a warning is logged whenever an incoming message has more signers than that, if verbose is 3 or higher. This is to help a reasonable setting of db_sql_dmarc_agg_record. The default value is 0.

publicsuffix string
    The full path to a file like effective_tld_names.dat that implements the Public Suffix List (PSL) as maintained by publicsuffix.org.

    The default value is NULL, which may prevent verifying whether traditional DMARC alignment, using the PSL, is different from the result obtained using the newer method, tha Tree Walk. In addition, the PSL is used to find the registerd domain of other domains (non-From:) stored in the database.

    Setting this value also enables storage of unauthenticated domains, in a way similar to save_from_anyway. That is necessary to generate aggregate reports. Yet, any value would enable such storage, even though a missing file prevents the other functionalities.

honored_report_interval
    The number of seconds between successive invocations of zaggregate, according to cron settings. It is used to adjust a domain's dmarc_ri to a multiple of this value. The default is 86400, which assumes zaggregate is run once a day.

honor_dmarc bool
    Honor DMARC policy, if any. This item can be changed on a per-domain basis.

honor_author_domain bool
    Honor ADSP policy, if any. This item can be changed on a per-domain basis.

reject_on_nxdomain bool
    This option can be set to complement ADSP, or independently of ADSP. This catches invalid From: like <john.doe@NOSPAM.example.com>, typical of some mailing lists. The three conditions that drive the resulting behavior are as follows:

    1 nxdomain
        the author's address, as given in the "From:" header, contains a non-existing domain name.

    2 all
        the author domain specifies a policy whereby all messages must have an author domain signature, but this messages has none.

    3 discardable
        as case all, but the author domain further asks that non-compliant messages be just discarded, in order to avoid useless backscatter.

    When reject_on_nxdomain is enabled, the filter rejects in case 1. When honor_author_domain is enabled, the filter rejects in case 2 and drops in case 3. In any case, the action is retracted if an authenticated domain is whitelisted in the database or authenticated by dnswl=pass. Any of SPF and DKIM authentications are valid to establish whitelisting, but only "MAIL FROM" SPF and DKIM can be used for VBR.

    If one of the cases above is detected, but the action not enforced, an A-R field will have a line specifying the result as dkim-adsp=nxdomain (for case 1), dkim-adsp=fail (case 2), or dkim-adsp=discard (3).

    Recall that ADSP was declared "Historic" in November 2013.

action_header string
    An RFC 822 header field name that an upstream filter adds to the message to mark it as bad. If that header is found, the message is dropped or rejected according to the next option.

    This option is meant to be a last resort for messages caught by anti-virus or anti-phishing filters that add a given header field instead of discarding the message tout-court. That way, a reject/drop decision can be undone according to dnswl_worthiness_pass and/or whitelisted_pass.

header_action_is_reject bool
    Reject, rather than drop, if the action_header is found.

save_drop string
    Quarantine directory path. Messages dropped because of the action_header are saved there, if set. Saved messages are named after the content of the header.

    The message content is preceded by a "pre-header"; that is, a part of the envelope separated by an empty line. The part of the envelope consists of a possibly empty sender followed by the recipients. The pre-header enables users to recover the message from quarantine in case of false positives; see the scripts etc/resend-with-preheader.* in the tarball.

dnswl_worthiness_pass
    This item refers to the externally retrieved dnswl value.

    A worthiness greater or equal than this causes acceptance of a message even if it if it should have been rejected due to DMARC or ADSP policy, action_header or shoot_on_sight. Must be a number between 0 and 255.

    Default: 1 (low for dnswl.org)

dnswl_invalid_ip
    An invalid IP is returned in some cases, e.g. if a name server issues too many queries. Finding this is logged at LOG_CRIT if verbose is 1 or greater.

    The ip has to be given as a 32bit integer, with the right endianness.

    Default: -16777089, which works for dnswl.org

dnswl_octet_index
    This is the octet in policy.ip where the worthiness value is found. Must be a number between 0 and 3.

    Default: 3, which works for dnswl.org

trusted_dnswl array
    A space-separated list of trusted dns zones. When an A-R field that contains "dnswl=pass" is found, if the dns.zone is trusted and the result contains a policy.txt with a domain name in it, the domain in the policy.txt is associated to the message. At most one domain can get associated this way.

    The default is "list.dnswl.zone". Unless you know a different operator that does the same service, it shouldn't be necessary to modify this default, because the lookup has to be configured in Courier's sysconfdir/esmtpd. If you use a local server, e.g. downloading rbldns data from dnswl.org, you can configure the correct display zone rather than change this default. For example:

    -allow=dnswl.local=list.dnswl.org,DNSWL,

    (note the trailing comma, which is necessary to query the TXT record too.)

whitelisted_pass int
    This refers to the whitelisted value read by "db_sql_domain_flags" in zfilter_db, not to be conflated with dnswl.

    A value greater or equal than this configured value causes acceptance of a message even if it should have been rejected due to DMARC or ADSP policy, action_header or shoot_on_sight.

    This value should be greater than 2, since a value of 1 can be set automatically when a DKIM signature verifies, and a value of 2 is set when sending to a domain from a personal address (not an rfc2142 address.)

    Since version 3.6, the string whitelisted inside a parethesized comment of Authentication-Results: is only added when this value is met. This enables to control the placement of that string and possibly use it for actual whitelisting. For example, Maildrop recipes can limit trashing like so:

        if (/^X-Spam-Flag: YES/:H && \
           !/^Authentication-Results: .*?\(.*?whitelisted.*?\)/:H)
        {
            KEYWORDS="Junk"
            # ...
        }

    Default: 3

AUTHOR
Alessandro Vesely <vesely@tana.it>

SEE ALSO
courier(8), zdkimfilter(8), zfilter_db(1), ratefilter(8), maildropfilter(7)