summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/src/EDITME8
-rw-r--r--src/src/config.h.defaults1
-rw-r--r--src/src/dns.c58
-rw-r--r--src/src/functions.h1
-rw-r--r--src/src/globals.c2
-rw-r--r--src/src/globals.h2
-rw-r--r--src/src/host.c9
-rw-r--r--src/src/readconf.c1
8 files changed, 81 insertions, 1 deletions
diff --git a/src/src/EDITME b/src/src/EDITME
index 95857c707..95a0c02f4 100644
--- a/src/src/EDITME
+++ b/src/src/EDITME
@@ -412,6 +412,14 @@ EXIM_MONITOR=eximon.bin
#------------------------------------------------------------------------------
+# By default, Exim has support for checking the AD bit in a DNS response, to
+# determine if DNSSEC validation was successful. If your system libraries
+# do not support that bit, then set DISABLE_DNSSEC to "yes"
+
+# DISABLE_DNSSEC=yes
+
+
+#------------------------------------------------------------------------------
# Compiling Exim with experimental features. These are documented in
# experimental-spec.txt. "Experimental" means that the way these features are
# implemented may still change. Backward compatibility is not guaranteed.
diff --git a/src/src/config.h.defaults b/src/src/config.h.defaults
index f02aef12c..00168f84a 100644
--- a/src/src/config.h.defaults
+++ b/src/src/config.h.defaults
@@ -41,6 +41,7 @@ it's a default value. */
#define DELIVER_IN_BUFFER_SIZE 8192
#define DELIVER_OUT_BUFFER_SIZE 8192
#define DISABLE_DKIM
+#define DISABLE_DNSSEC
#define DISABLE_D_OPTION
#define ENABLE_DISABLE_FSYNC
diff --git a/src/src/dns.c b/src/src/dns.c
index ae76e9e3f..95db52686 100644
--- a/src/src/dns.c
+++ b/src/src/dns.c
@@ -201,6 +201,36 @@ if (dns_use_edns0 >= 0)
dns_use_edns0 ? "" : "un");
#endif
+#ifndef DISABLE_DNSSEC
+# ifdef RES_USE_DNSSEC
+# ifndef RES_USE_EDNS0
+# error Have RES_USE_DNSSEC but not RES_USE_EDNS0? Something hinky ...
+# endif
+if (dns_use_dnssec >= 0)
+ {
+ if (dns_use_edns0 == 0 && dns_use_dnssec != 0)
+ {
+ DEBUG(D_resolver)
+ debug_printf("CONFLICT: dns_use_edns0 forced false, dns_use_dnssec forced true!\n");
+ }
+ else
+ {
+ if (dns_use_dnssec)
+ resp->options |= RES_USE_DNSSEC;
+ else
+ resp->options &= ~RES_USE_DNSSEC;
+ DEBUG(D_resolver) debug_printf("Coerced resolver DNSSEC support %s.\n",
+ dns_use_dnssec ? "on" : "off");
+ }
+ }
+# else
+if (dns_use_dnssec >= 0)
+ DEBUG(D_resolver)
+ debug_printf("Unable to %sset DNSSEC without resolver support.\n",
+ dns_use_dnssec ? "" : "un");
+# endif
+#endif /* DISABLE_DNSSEC */
+
os_put_dns_resolver_res(resp);
}
@@ -395,6 +425,34 @@ return &(dnss->srr);
/*************************************************
+* Return whether AD bit set in DNS result *
+*************************************************/
+
+/* We do not perform DNSSEC work ourselves; if the administrator has installed
+a verifying resolver which sets AD as appropriate, though, we'll use that.
+(AD = Authentic Data)
+
+Argument: pointer to dns answer block
+Returns: bool indicating presence of AD bit
+*/
+
+BOOL
+dns_is_secure(dns_answer *dnsa)
+{
+#ifdef DISABLE_DNSSEC
+DEBUG(D_dns)
+ debug_printf("DNSSEC support disabled at build-time; dns_is_secure() false\n");
+return FALSE;
+#else
+HEADER *h = (HEADER *)dnsa->answer;
+return h->ad ? TRUE : FALSE;
+#endif
+}
+
+
+
+
+/*************************************************
* Turn DNS type into text *
*************************************************/
diff --git a/src/src/functions.h b/src/src/functions.h
index 2758a4aec..5616db2de 100644
--- a/src/src/functions.h
+++ b/src/src/functions.h
@@ -104,6 +104,7 @@ extern dns_address *dns_address_from_rr(dns_answer *, dns_record *);
extern void dns_build_reverse(uschar *, uschar *);
extern void dns_init(BOOL, BOOL);
extern int dns_basic_lookup(dns_answer *, uschar *, int);
+extern BOOL dns_is_secure(dns_answer *);
extern int dns_lookup(dns_answer *, uschar *, int, uschar **);
extern int dns_special_lookup(dns_answer *, uschar *, int, uschar **);
extern dns_record *dns_next_rr(dns_answer *, dns_scan *, int);
diff --git a/src/src/globals.c b/src/src/globals.c
index f29fb3c49..d5cb6c15f 100644
--- a/src/src/globals.c
+++ b/src/src/globals.c
@@ -549,6 +549,7 @@ BOOL dns_csa_use_reverse = TRUE;
uschar *dns_ipv4_lookup = NULL;
int dns_retrans = 0;
int dns_retry = 0;
+int dns_use_dnssec = -1; /* <0 = not coerced */
int dns_use_edns0 = -1; /* <0 = not coerced */
uschar *dnslist_domain = NULL;
uschar *dnslist_matched = NULL;
@@ -1066,6 +1067,7 @@ uschar **sender_host_aliases = &no_aliases;
uschar *sender_host_address = NULL;
uschar *sender_host_authenticated = NULL;
unsigned int sender_host_cache[(MAX_NAMED_LIST * 2)/32];
+BOOL sender_host_dnssec = FALSE;
uschar *sender_host_name = NULL;
int sender_host_port = 0;
BOOL sender_host_notsocket = FALSE;
diff --git a/src/src/globals.h b/src/src/globals.h
index b1ec5a20f..c61158e6d 100644
--- a/src/src/globals.h
+++ b/src/src/globals.h
@@ -335,6 +335,7 @@ extern BOOL dns_csa_use_reverse; /* Check CSA in reverse DNS? (non-standar
extern uschar *dns_ipv4_lookup; /* For these domains, don't look for AAAA (or A6) */
extern int dns_retrans; /* Retransmission time setting */
extern int dns_retry; /* Number of retries */
+extern int dns_use_dnssec; /* When constructing DNS query, set DO flag */
extern int dns_use_edns0; /* Coerce EDNS0 support on/off in resolver. */
extern uschar *dnslist_domain; /* DNS (black) list domain */
extern uschar *dnslist_matched; /* DNS (black) list matched key */
@@ -660,6 +661,7 @@ extern uschar *sender_fullhost; /* Sender host name + address */
extern uschar *sender_helo_name; /* Host name from HELO/EHLO */
extern uschar **sender_host_aliases; /* Points to list of alias names */
extern unsigned int sender_host_cache[(MAX_NAMED_LIST * 2)/32]; /* Cache bits for incoming host */
+extern BOOL sender_host_dnssec; /* true if sender_host_name verified in DNSSEC */
extern BOOL sender_host_notsocket; /* Set for -bs and -bS */
extern BOOL sender_host_unknown; /* TRUE for -bs and -bS except inetd */
extern uschar *sender_ident; /* Sender identity via RFC 1413 */
diff --git a/src/src/host.c b/src/src/host.c
index 9dc9c9a3e..03d944334 100644
--- a/src/src/host.c
+++ b/src/src/host.c
@@ -1597,7 +1597,7 @@ dns_record *rr;
dns_answer dnsa;
dns_scan dnss;
-host_lookup_deferred = host_lookup_failed = FALSE;
+sender_host_dnssec = host_lookup_deferred = host_lookup_failed = FALSE;
HDEBUG(D_host_lookup)
debug_printf("looking up host name for %s\n", sender_host_address);
@@ -1639,6 +1639,13 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))
int count = 0;
int old_pool = store_pool;
+ /* Ideally we'd check DNSSEC both forward and reverse, but we use the
+ gethost* routines for forward, so can't do that unless/until we rewrite. */
+ sender_host_dnssec = dns_is_secure(&dnsa);
+ DEBUG(D_dns)
+ debug_printf("Reverse DNS security status: %s\n",
+ sender_host_dnssec ? "DNSSEC verified (AD)" : "unverified");
+
store_pool = POOL_PERM; /* Save names in permanent storage */
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
diff --git a/src/src/readconf.c b/src/src/readconf.c
index 568990a70..553f2e455 100644
--- a/src/src/readconf.c
+++ b/src/src/readconf.c
@@ -216,6 +216,7 @@ static optionlist optionlist_config[] = {
{ "dns_ipv4_lookup", opt_stringptr, &dns_ipv4_lookup },
{ "dns_retrans", opt_time, &dns_retrans },
{ "dns_retry", opt_int, &dns_retry },
+ { "dns_use_dnssec", opt_int, &dns_use_dnssec },
{ "dns_use_edns0", opt_int, &dns_use_edns0 },
/* This option is now a no-op, retained for compability */
{ "drop_cr", opt_bool, &drop_cr },