Re: [exim-dev] Mailop list: exim and google fighting over DK…

Top Page

Reply to this message
Author: Phil Pennock
Date:  
To: Andrew C Aitchison
CC: exim-dev
Subject: Re: [exim-dev] Mailop list: exim and google fighting over DKIM
On 2019-04-28 at 16:42 +0100, Andrew C Aitchison via Exim-dev wrote:
> Do the DKIM exim experts subscribe to the mailop list ?


I do, but I just started a new job and am behind on public
mailing-lists.

> There is an ongoing discussion on the mailop@???
> about a snafu with DKIM which implicates exim and google.


It looks like an instance of this:

https://bridge.grumpy-troll.org/2014/04/dmarc-stance/

but for p=none, not p=reject. It's been five years since I wrote that.
DMARC breaks mail for domains sending non-transactional non-bulk mail,
becauase DMARC breaks mailing-lists.

The only "out" is to implement ARC and hope that the receiving domain
does too. Gmail does, but you need to send enough mail for them to
decide to trust you as an ARC sender.

For the @exim.org mail-hub, we run with

------------------------8< exim.conf snippets >8------------------------
# This file is renewed daily by cron as user _exim:
.ifdef _HAVE_DMARC
dmarc_tld_file = /var/cache/exim/opendmarc.tlds
.elifdef _HAVE_ARC
dmarc_tld_file = /var/cache/exim/opendmarc.tlds
.endif

### ACLS section

acl_check_content:
# Outbound ARC-sign is disabled by default because people can auth to us
warn set acl_m_should_arcsign = false

  # Do add Message-ID: and Date: headers
  warn  condition = ${if !def:h_Message-ID: {1}}
        message = Message-ID: <E$message_id@$primary_hostname>
  warn  condition = ${if !def:h_Date: {1}}
        message = Date: $tod_full


  # If there's an AAR (ARC-Authentication-Results) header which claims to be
  # from us, but we're not receiving the mail from Mailman or other local
  # system or authenticated user, then we consider it to be fraudulent or a
  # mail-loop.
  #
  # We need to allow authenticated users for when someone is bouncing onwards
  # a received message; OUTSIDE->exim.org->fred@???, reads, bounces
  # onwards for processing elsewhere, but being sent from fred@??? gets
  # routed back via us (for DKIM/SPF alignment), so we appear in the AAR
  # headers already.
  #
  # Does not need to be _HAVE_ARC-guarded, this is pure Exim logic and safe
  # even when we're not signing.
  deny  message        = Mail-loop or fraudulent headers: found ourselves in ARC-Authentication-Results:
        !hosts         = +relay_from_hosts
        !authenticated = *
        condition      = ${if def:h_ARC-Authentication-Results: {yes}}
        condition      = ${if inlist{ADMD}{<; $h_ARC-Authentication-Results: }}


  warn  hosts = <;  ; 127.0.0.1 ; ::1
        condition = ${if def:h_X-Exim-Org-Should-ARC-Sign: {yes}}
        set acl_m_should_arcsign = $h_X-Exim-Org-Should-ARC-Sign:
        remove_header = X-Exim-Org-Should-ARC-Sign


# Bypass the content scanning for stuff injected from mailman etc
accept hosts = <; ; 127.0.0.1 ; ::1

### THERE ARE MORE STEPS HERE IN THIS ACL (unrelated to ARC)

  # list stuff & authenticated....
  accept  hosts         = +relay_from_hosts
  accept  authenticated = *


  # Insert DMARC headers for non-authenticated non-local senders
  warn    dmarc_status   = accept : reject : quarantine : none : norecord : nofrom : temperror : off
          log_message    = DMARC DEBUG: $dmarc_status $dmarc_used_domain
  warn    condition      = ${if !eq{$dmarc_status}{accept}}
          log_message    = DMARC DEBUG: not-accept '$dmarc_status' for $dmarc_used_domain
  warn    condition      = ${if eq{$dmarc_status}{quarantine}}
          set acl_m_quarantine = 1
  deny    condition      = ${if eq{$dmarc_status}{reject}}
          message        = Message from $dmarc_used_domain failed sender's DMARC policy, REJECT


.ifdef _HAVE_ARC
  # and ARC chaining
  warn    verify         = arc/pass:none:fail
          logwrite       = ARC: state=<$arc_state>${if def:arc_state_reason{ reason=<$arc_state_reason>}}
.endif


### TRANSPORTS SECTION

remote_smtp:
driver = smtp
rcpt_include_affixes
# hosts_try_chunking =
dnssec_request_domains = *
hosts_try_dane = *
tls_require_ciphers = TLS_OUTBOUND_DEFAULT
dane_require_tls_ciphers = TLS_OUTBOUND_HIGHSEC
dkim_domain = ${domain:$sender_address}
dkim_selector = ${lookup {$dkim_domain}lsearch{/etc/exim/dkim/domains-mapping} {$value}{SKIP}}
dkim_private_key = ${if eq{$dkim_selector}{SKIP}{false}{/etc/exim/dkim/rsa.private.$dkim_selector.$dkim_domain}}
dkim_strict = 1
.ifdef _HAVE_ARC
arc_sign = ${if bool{$acl_m_should_arcsign}{${lookup {ADMD}lsearch{/etc/exim/dkim/domains-mapping}{ADMD : $value : /etc/exim/dkim/rsa.private.$value.ADMD }fail}}fail}
.endif

.ifdef WANT_MAILMAN
mailman_transport:
    envelope_to_add
    driver = pipe
    command = MM_WRAP \
              '${if def:local_part_suffix \
                    {${sg{$local_part_suffix}{-(\\w+)(\\+.*)?}{\$1}}} \
                    {post}}' \
              $local_part
    headers_add = X-Exim-Org-Should-ARC-Sign: $acl_m_should_arcsign
    current_directory = MM_HOME
    home_directory = MM_HOME
    user = MM_UID
    group = MM_GID


.endif
------------------------8< exim.conf snippets >8------------------------

Our Mailman config has:

----------------------------8< mm_cfg.py >8-----------------------------
# DMARC/DKIM handling:
# This sets the minimum option allowed per-list; minimum is "Munge", not
# "Accept and destroy our reputation".
DEFAULT_DMARC_MODERATION_ACTION = 1
# and for dmarc p=none, also munge, so that sender's domain owner doesn't get
# reports from sites with folks subscribed to our lists:
DEFAULT_DMARC_NONE_MODERATION_ACTION = Yes
# REMOVE_DKIM_HEADERS=3 -> always remove, rename and preserve original DKIM headers
REMOVE_DKIM_HEADERS = 3
----------------------------8< mm_cfg.py >8-----------------------------

Also, per our upgrade notes, we have to manually edit one file of
Mailman which is buggy in the presence of ARC:

-----------------------8< mailman update notes >8-----------------------
## ARC configuration

Minor hack, applied 2018-03-25, such that DKIM header cleansing does _not_
touch the Authentication-Results header.

Edited: `/opt/mailman/Mailman/Handlers/CleanseDKIM.py`

```
    if (mm_cfg.REMOVE_DKIM_HEADERS == 3):
 ## ...
#       for value in msg.get_all('authentication-results', []):
#           msg['X-Mailman-Original-Authentication-Results'] = value
 ## ...
#   del msg['authentication-results']
-----------------------8< mailman update notes >8-----------------------


That's "leave Authentication-Results: alone, because we need to sign
it". I don't think that I ever got around to trying to feed this
upstream, which is on me (lazyness).

I _think_ that's it.