[exim] DMARC spf_domain= empty

Pàgina inicial
Delete this message
Reply to this message
Autor: Niels Dettenbach
Data:  
A: exim-users
Assumpte: [exim] DMARC spf_domain= empty
Hiho Dears,


after investigating my EXIM DMARC (opendmarc EXP) setup and the current docs about Exim DMARC in more detail i've found that anything seems to work except that the SPF variable(s) - expescially "spf_domain=" are not filled correctly within dmarc.c. This leads to bad XML reports too, because of "failed" empty SPF fields.

Could someone pls explain how the "spf_domain" vs. spf data within DMARC whould work?

Here is an example of a googlemail.com email going through DMARC here:

--- snip ---
2017-05-31 10:40:11 1dFzAp-0007cW-UY DKIM: d=googlemail.com s=20161025 c=relaxed/relaxed a=rsa-sha256 b=2048 [verification succeeded]
2017-05-31 10:40:11 1dFzAp-0007cW-UY DMARC results: spf_domain= dmarc_domain=googlemail.com spf_align=no dkim_align=yes enforcement='Accept'
2017-05-31 10:40:11 1dFzAp-0007cW-UY H=mail-wr0-f195.google.com [209.85.128.195] Warning: [DMARC] ACCEPTED: accept googlemail.com
2017-05-31 10:40:11 1dFzAp-0007cW-UY H=mail-wr0-f195.google.com [209.85.128.195] Warning: [DMARC] DEBUG: 'accept' for googlemail.com STATUS Accept USED_DOMAIN googlemail.com DMARC_HEADER Authentication-Results: mail.syndicat.com; dmarc=pass header.from=googlemail.com
--- snap ---

I use EXIM 4.89nb1 on NetBSD

build against:
    - libspf2-1.2.10
    - opendmarc 1.3.1


with:
    LOOKUP_LIBS=-lmysqlclient -lssl -lcrypto -lopendmarc -Wl,-R/usr/pkg/lib -L/usr/pkg/lib -lsasl2 -lspf2
    EXPERIMENTAL_SPF=yes
    EXPERIMENTAL_DMARC=yes
    WITH_CONTENT_SCAN=YES
    ...


OpenDMARC is build with SPF support (tried it without too):
    opendmarc: OpenDMARC Filter v1.3.1
        SMFI_VERSION 0x1000001
        libmilter version 1.0.1
        Active code options:
                WITH_SPF


in opendmarc.conf these are commented our / default:

##  SPFIgnoreResults { true | false }
##      default "false"


#SPFSelfValidate true

##  Syslog { true | false }
##      default "false"


I'm not sure if Exim DMARC uses this over i.e. libopendmarc or SPF directly from libspf2.

As described, i do the SPF checks "before" DMARC checks within


acl_check_rcpt:
...

### SPF native

        warn    set acl_m_spf_record = ${lookup dnsdb{txt=$sender_address_domain}{$value}}


        # No record
        warn    !condition      = ${if def:acl_m_spf_record}
                !hosts          = +3rdmxes : +relay_from_hosts
                log_message     = [SPF] no record


        # SPF +all is meaningless
        warn    condition       = ${if match {$acl_m_spf_record}{\\+all}}
                log_message     = [SPF] meaningless +all
                !hosts          = +3rdmxes : +relay_from_hosts


        warn    spf             = fail
                !hosts          = +3rdmxes : +relay_from_hosts : +nosa_from_hosts
                log_message     = [SPF] $sender_host_address is not allowed to send mail from $sender_address_domain


        # Add a SPF-Received: header to the message
        warn    message         = $spf_received
                !hosts          = +3rdmxes : +relay_from_hosts


        accept  spf             = pass
                log_message     = [SPF] pass
                !hosts          = +3rdmxes : +relay_from_hosts



### DMARC niels
# --- check sender's DMARC policy
        warn    domains        = +local_domains
                hosts          = +3rdmxes : +relay_from_hosts
                log_message    = [DMARC] no check for OUR hosts
                control        = dmarc_disable_verify



        warn    !domains       = +screwed_up_dmarc_records
                #log_message    = [DMARC] check forensics
                control        = dmarc_enable_forensic
###


and then DMARC (as described) in

acl_check_data:
...

## test
  # --- check sender's DMARC policy
  warn   dmarc_status   = *
         add_header     = $dmarc_ar_header


  deny   dmarc_status   = reject
         message        = Rejected by sender's DMARC policy


  warn   dmarc_status   = quarantine
         set acl_c0     = ${eval:$acl_c0+40}
         set acl_c1     = QDMARC(40) suspicious message according DMARC policy; $acl_c1


## test


For me it seems, in dmarc.c spf_domain is set not correctly (however?)., but seems relatively "hard wired" there Any idea, what could be wrong here?
https://github.com/Exim/exim/blob/master/src/src/dmarc.c
--- snip ---
  /* Use the envelope sender domain for this part of DMARC */
  spf_sender_domain = expand_string(US"$sender_address_domain");
  if (!spf_response)
    {
    /* No spf data means null envelope sender so generate a domain name
     * from the sender_helo_name  */
    if (!spf_sender_domain)
      {
      spf_sender_domain = sender_helo_name;
      log_write(0, LOG_MAIN, "DMARC using synthesized SPF sender domain = %s\n",
                 spf_sender_domain);
      DEBUG(D_receive)
    debug_printf("DMARC using synthesized SPF sender domain = %s\n",
      spf_sender_domain);
      }
    dmarc_spf_result = DMARC_POLICY_SPF_OUTCOME_NONE;
    dmarc_spf_ares_result = ARES_RESULT_UNKNOWN;
    origin = DMARC_POLICY_SPF_ORIGIN_HELO;
    spf_human_readable = US"";
    }
  else
    {
    sr = spf_response->result;
    dmarc_spf_result = sr == SPF_RESULT_NEUTRAL  ? DMARC_POLICY_SPF_OUTCOME_NONE :
               sr == SPF_RESULT_PASS     ? DMARC_POLICY_SPF_OUTCOME_PASS :
               sr == SPF_RESULT_FAIL     ? DMARC_POLICY_SPF_OUTCOME_FAIL :
               sr == SPF_RESULT_SOFTFAIL ? DMARC_POLICY_SPF_OUTCOME_TMPFAIL :
               DMARC_POLICY_SPF_OUTCOME_NONE;
    dmarc_spf_ares_result = sr == SPF_RESULT_NEUTRAL   ? ARES_RESULT_NEUTRAL :
                sr == SPF_RESULT_PASS      ? ARES_RESULT_PASS :
                sr == SPF_RESULT_FAIL      ? ARES_RESULT_FAIL :
                sr == SPF_RESULT_SOFTFAIL  ? ARES_RESULT_SOFTFAIL :
                sr == SPF_RESULT_NONE      ? ARES_RESULT_NONE :
                sr == SPF_RESULT_TEMPERROR ? ARES_RESULT_TEMPERROR :
                sr == SPF_RESULT_PERMERROR ? ARES_RESULT_PERMERROR :
                ARES_RESULT_UNKNOWN;
    origin = DMARC_POLICY_SPF_ORIGIN_MAILFROM;
    spf_human_readable = (uschar *)spf_response->header_comment;
    DEBUG(D_receive)
      debug_printf("DMARC using SPF sender domain = %s\n", spf_sender_domain);
    }
  if (strcmp( CCS spf_sender_domain, "") == 0)
dmarc_abort = TRUE;
--- snap ---


...and here the "spf_sender_domain" is used for rendering of "spf_sender":
--- snip ---
    {
    log_write(0, LOG_MAIN, "DMARC results: spf_domain=%s dmarc_domain=%s "
               "spf_align=%s dkim_align=%s enforcement='%s'",
               spf_sender_domain, dmarc_used_domain,
               (sa==DMARC_POLICY_SPF_ALIGNMENT_PASS) ?"yes":"no",
               (da==DMARC_POLICY_DKIM_ALIGNMENT_PASS)?"yes":"no",
               dmarc_status_text);
    history_file_status = dmarc_write_history_file();
    /* Now get the forensic reporting addresses, if any */
    ruf = opendmarc_policy_fetch_ruf(dmarc_pctx, NULL, 0, 1);
    dmarc_send_forensic_report(ruf);
    }
}
--- snap ---


many thanks in advance for any help or hint!

best regards,




Niels.
--
---
Niels Dettenbach
Syndicat IT & Internet
http://www.syndicat.com
PGP: https://syndicat.com/pub_key.asc
---