From 783b385fe846f97aa5d7a7675cc0600e917b8795 Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Mon, 12 May 2014 15:30:47 +0100 Subject: [PATCH] Propagate dnssec status from dnslookup router through transport to tpda --- src/src/deliver.c | 28 +++++++++++++++++------ src/src/host.c | 48 +++++++++++++++++++++++++++++++-------- src/src/route.c | 1 + src/src/structs.h | 3 +++ src/src/transports/smtp.c | 3 +++ 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/src/deliver.c b/src/src/deliver.c index 3334ba2cb..777ff8dc7 100644 --- a/src/src/deliver.c +++ b/src/src/deliver.c @@ -730,6 +730,7 @@ pointer to a single host item in their host list, for use by the transport. */ tpda_delivery_local_part = NULL; tpda_delivery_domain = NULL; tpda_delivery_confirmation = NULL; + lookup_dnssec_authenticated = NULL; #endif s = reset_point = store_get(size); @@ -793,7 +794,7 @@ if (addr->transport->info->local) else { - if (addr->host_used != NULL) + if (addr->host_used) { s = d_hostlog(s, &size, &ptr, addr); if (continue_sequence > 1) @@ -806,6 +807,11 @@ else tpda_delivery_local_part = addr->local_part; tpda_delivery_domain = addr->domain; tpda_delivery_confirmation = addr->message; + + /* DNS lookup status */ + lookup_dnssec_authenticated = addr->host_used->dnssec==DS_YES ? US"yes" + : addr->host_used->dnssec==DS_NO ? US"no" + : NULL; #endif } @@ -3019,7 +3025,7 @@ while (!done) } while (*ptr++); break; - #endif + #endif /*SUPPORT_TLS*/ case 'C': /* client authenticator information */ switch (*ptr++) @@ -3039,7 +3045,7 @@ while (!done) #ifdef EXPERIMENTAL_PRDR case 'P': - addr->flags |= af_prdr_used; break; + addr->flags |= af_prdr_used; break; #endif case 'A': @@ -3066,7 +3072,7 @@ while (!done) addr->user_message = (*ptr)? string_copy(ptr) : NULL; while(*ptr++); - /* Always two strings for host information, followed by the port number */ + /* Always two strings for host information, followed by the port number and DNSSEC mark */ if (*ptr != 0) { @@ -3077,6 +3083,10 @@ while (!done) while(*ptr++); memcpy(&(h->port), ptr, sizeof(h->port)); ptr += sizeof(h->port); + h->dnssec = *ptr == '2' ? DS_YES + : *ptr == '1' ? DS_NO + : DS_UNK; + ptr++; addr->host_used = h; } else ptr++; @@ -4104,11 +4114,9 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) retry_item *r; /* The certificate verification status goes into the flags */ - if (tls_out.certificate_verified) setflag(addr, af_cert_verified); /* Use an X item only if there's something to send */ - #ifdef SUPPORT_TLS if (addr->cipher) { @@ -4179,7 +4187,8 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) } #ifdef EXPERIMENTAL_PRDR - if (addr->flags & af_prdr_used) rmt_dlv_checked_write(fd, "P", 1); + if (addr->flags & af_prdr_used) + rmt_dlv_checked_write(fd, "P", 1); #endif /* Retry information: for most success cases this will be null. */ @@ -4233,6 +4242,11 @@ for (delivery_count = 0; addr_remote != NULL; delivery_count++) while(*ptr++); memcpy(ptr, &(addr->host_used->port), sizeof(addr->host_used->port)); ptr += sizeof(addr->host_used->port); + + /* DNS lookup status */ + *ptr++ = addr->host_used->dnssec==DS_YES ? '2' + : addr->host_used->dnssec==DS_NO ? '1' : '0'; + } rmt_dlv_checked_write(fd, big_buffer, ptr - big_buffer); } diff --git a/src/src/host.c b/src/src/host.c index a1db7717e..a59c4381b 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -2065,6 +2065,7 @@ for (i = 1; i <= times; host->port = PORT_NONE; host->status = hstatus_unknown; host->why = hwhy_unknown; + host->dnssec = DS_UNK; last = host; } @@ -2080,6 +2081,7 @@ for (i = 1; i <= times; next->port = PORT_NONE; next->status = hstatus_unknown; next->why = hwhy_unknown; + next->dnssec = DS_UNK; next->last_try = 0; next->next = last->next; last->next = next; @@ -2475,10 +2477,12 @@ int ind_type = 0; int yield; dns_answer dnsa; dns_scan dnss; -BOOL dnssec_request = match_isinlist(host->name, &dnssec_request_domains, - 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK; BOOL dnssec_require = match_isinlist(host->name, &dnssec_require_domains, 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK; +BOOL dnssec_request = dnssec_require + || match_isinlist(host->name, &dnssec_request_domains, + 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK; +dnssec_status_t dnssec; /* Set the default fully qualified name to the incoming name, initialize the resolver if necessary, set up the relevant options, and initialize the flag @@ -2487,7 +2491,7 @@ that gets set for DNS syntax check errors. */ if (fully_qualified_name != NULL) *fully_qualified_name = host->name; dns_init((whichrrs & HOST_FIND_QUALIFY_SINGLE) != 0, (whichrrs & HOST_FIND_SEARCH_PARENTS) != 0, - dnssec_request || dnssec_require + dnssec_request ); host_find_failed_syntax = FALSE; @@ -2509,9 +2513,17 @@ if ((whichrrs & HOST_FIND_BY_SRV) != 0) the input name, pass back the new original domain, without the prepended magic. */ + dnssec = DS_UNK; + lookup_dnssec_authenticated = NULL; rc = dns_lookup(&dnsa, buffer, ind_type, &temp_fully_qualified_name); - lookup_dnssec_authenticated = !dnssec_request ? NULL - : dns_is_secure(&dnsa) ? US"yes" : US"no"; + + if (dnssec_request) + { + if (dns_is_secure(&dnsa)) + { dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } + else + { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } + } if (temp_fully_qualified_name != buffer && fully_qualified_name != NULL) *fully_qualified_name = temp_fully_qualified_name + prefix_length; @@ -2547,9 +2559,17 @@ listed as one for which we continue. */ if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0) { ind_type = T_MX; + dnssec = DS_UNK; + lookup_dnssec_authenticated = NULL; rc = dns_lookup(&dnsa, host->name, ind_type, fully_qualified_name); - lookup_dnssec_authenticated = !dnssec_request ? NULL - : dns_is_secure(&dnsa) ? US"yes" : US"no"; + + if (dnssec_request) + { + if (dns_is_secure(&dnsa)) + { dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } + else + { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } + } switch (rc) { @@ -2593,9 +2613,19 @@ if (rc != DNS_SUCCEED) last = host; /* End of local chainlet */ host->mx = MX_NONE; host->port = PORT_NONE; + dnssec = DS_UNK; + lookup_dnssec_authenticated = NULL; rc = set_address_from_dns(host, &last, ignore_target_hosts, FALSE, fully_qualified_name, dnssec_request, dnssec_require); + if (dnssec_request) + { + if (dns_is_secure(&dnsa)) + { dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } + else + { dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; } + } + /* If one or more address records have been found, check that none of them are local. Since we know the host items all have their IP addresses inserted, host_scan_for_local_hosts() can only return HOST_FOUND or @@ -2665,9 +2695,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); the same precedence to sort randomly. */ if (ind_type == T_MX) - { weight = random_number(500); - } /* SRV records are specified with a port and a weight. The weight is used in a special algorithm. However, to start with, we just use it to order the @@ -2731,6 +2759,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); host->sort_key = precedence * 1000 + weight; host->status = hstatus_unknown; host->why = hwhy_unknown; + host->dnssec = dnssec; last = host; } @@ -2747,6 +2776,7 @@ for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS); next->sort_key = sort_key; next->status = hstatus_unknown; next->why = hwhy_unknown; + next->dnssec = dnssec; next->last_try = 0; /* Handle the case when we have to insert before the first item. */ diff --git a/src/src/route.c b/src/src/route.c index 271175e4b..0116e12af 100644 --- a/src/src/route.c +++ b/src/src/route.c @@ -1941,6 +1941,7 @@ DEBUG(D_route) if (h->mx >= 0) debug_printf(" MX=%d", h->mx); else if (h->mx != MX_NONE) debug_printf(" rgroup=%d", h->mx); if (h->port != PORT_NONE) debug_printf(" port=%d", h->port); + /* if (h->dnssec != DS_UNK) debug_printf(" dnssec=%s", h->dnssec==DS_YES ? "yes" : "no"); */ debug_printf("\n"); } } diff --git a/src/src/structs.h b/src/src/structs.h index aba579f89..989653e30 100644 --- a/src/src/structs.h +++ b/src/src/structs.h @@ -55,6 +55,8 @@ typedef struct ugid_block { but also used when checking lists of hosts and when transporting. Looking up host addresses is done using this structure. */ +typedef enum {DS_UNK=-1, DS_NO, DS_YES} dnssec_status_t; + typedef struct host_item { struct host_item *next; uschar *name; /* Host name */ @@ -65,6 +67,7 @@ typedef struct host_item { int status; /* Usable, unusable, or unknown */ int why; /* Why host is unusable */ int last_try; /* Time of last try if known */ + dnssec_status_t dnssec; } host_item; /* Chain of rewrite rules, read from the rewrite config, or parsed from the diff --git a/src/src/transports/smtp.c b/src/src/transports/smtp.c index fd8948620..020f76cac 100644 --- a/src/src/transports/smtp.c +++ b/src/src/transports/smtp.c @@ -2919,6 +2919,9 @@ for (cutoff_retry = 0; expired && deliver_host = host->name; deliver_host_address = host->address; + lookup_dnssec_authenticated = host->dnssec == DS_YES ? US"yes" + : host->dnssec == DS_NO ? US"no" + : US""; /* Set up a string for adding to the retry key if the port number is not the standard SMTP port. A host may have its own port setting that overrides -- 2.25.1