From 1f4a55daf88541563ceaa66959acb9127604b15a Mon Sep 17 00:00:00 2001 From: Phil Pennock Date: Fri, 1 Jun 2012 10:15:14 -0400 Subject: DNSSEC babystep: dns_use_dnssec & $sender_host_dnssec --- src/src/EDITME | 8 +++++++ src/src/config.h.defaults | 1 + src/src/dns.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++ src/src/functions.h | 1 + src/src/globals.c | 2 ++ src/src/globals.h | 2 ++ src/src/host.c | 9 +++++++- src/src/readconf.c | 1 + 8 files changed, 81 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/src/EDITME b/src/src/EDITME index 95857c707..95a0c02f4 100644 --- a/src/src/EDITME +++ b/src/src/EDITME @@ -411,6 +411,14 @@ EXIM_MONITOR=eximon.bin # DISABLE_DKIM=yes +#------------------------------------------------------------------------------ +# 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 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); } @@ -394,6 +424,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 }, -- cgit v1.2.3