-/* $Cambridge: exim/src/src/dns.c,v 1.19 2009/10/19 14:20:58 tom Exp $ */
-
/*************************************************
* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2007 */
+/* Copyright (c) University of Cambridge 1995 - 2014 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for interfacing with the DNS. */
Arguments:
qualify_single TRUE to set the RES_DEFNAMES option
search_parents TRUE to set the RES_DNSRCH option
+ use_dnssec TRUE to set the RES_USE_DNSSEC option
Returns: nothing
*/
void
-dns_init(BOOL qualify_single, BOOL search_parents)
+dns_init(BOOL qualify_single, BOOL search_parents, BOOL use_dnssec)
{
-if ((_res.options & RES_INIT) == 0)
+res_state resp = os_get_dns_resolver_res();
+
+if ((resp->options & RES_INIT) == 0)
{
- DEBUG(D_resolver) _res.options |= RES_DEBUG; /* For Cygwin */
+ DEBUG(D_resolver) resp->options |= RES_DEBUG; /* For Cygwin */
+ os_put_dns_resolver_res(resp);
res_init();
- DEBUG(D_resolver) _res.options |= RES_DEBUG;
+ DEBUG(D_resolver) resp->options |= RES_DEBUG;
+ os_put_dns_resolver_res(resp);
}
-_res.options &= ~(RES_DNSRCH | RES_DEFNAMES);
-_res.options |= (qualify_single? RES_DEFNAMES : 0) |
+resp->options &= ~(RES_DNSRCH | RES_DEFNAMES);
+resp->options |= (qualify_single? RES_DEFNAMES : 0) |
(search_parents? RES_DNSRCH : 0);
-if (dns_retrans > 0) _res.retrans = dns_retrans;
-if (dns_retry > 0) _res.retry = dns_retry;
+if (dns_retrans > 0) resp->retrans = dns_retrans;
+if (dns_retry > 0) resp->retry = dns_retry;
+
+#ifdef RES_USE_EDNS0
+if (dns_use_edns0 >= 0)
+ {
+ if (dns_use_edns0)
+ resp->options |= RES_USE_EDNS0;
+ else
+ resp->options &= ~RES_USE_EDNS0;
+ DEBUG(D_resolver)
+ debug_printf("Coerced resolver EDNS0 support %s.\n",
+ dns_use_edns0 ? "on" : "off");
+ }
+#else
+if (dns_use_edns0 >= 0)
+ DEBUG(D_resolver)
+ debug_printf("Unable to %sset EDNS0 without resolver support.\n",
+ 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 (use_dnssec)
+ resp->options |= RES_USE_DNSSEC;
+if (dns_dnssec_ok >= 0)
+ {
+ if (dns_use_edns0 == 0 && dns_dnssec_ok != 0)
+ {
+ DEBUG(D_resolver)
+ debug_printf("CONFLICT: dns_use_edns0 forced false, dns_dnssec_ok forced true, ignoring latter!\n");
+ }
+ else
+ {
+ if (dns_dnssec_ok)
+ resp->options |= RES_USE_DNSSEC;
+ else
+ resp->options &= ~RES_USE_DNSSEC;
+ DEBUG(D_resolver) debug_printf("Coerced resolver DNSSEC support %s.\n",
+ dns_dnssec_ok ? "on" : "off");
+ }
+ }
+# else
+if (dns_dnssec_ok >= 0)
+ DEBUG(D_resolver)
+ debug_printf("Unable to %sset DNSSEC without resolver support.\n",
+ dns_dnssec_ok ? "" : "un");
+if (use_dnssec)
+ DEBUG(D_resolver)
+ debug_printf("Unable to set DNSSEC without resolver support.\n");
+# endif
+#endif /* DISABLE_DNSSEC */
+
+os_put_dns_resolver_res(resp);
}
+/*************************************************
+* 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
+}
+
+static void
+dns_set_insecure(dns_answer * dnsa)
+{
+HEADER * h = (HEADER *)dnsa->answer;
+h->ad = 0;
+}
+
+
+
+
+
/*************************************************
* Turn DNS type into text *
*************************************************/
case T_AAAA: return US"AAAA";
case T_A6: return US"A6";
case T_TXT: return US"TXT";
+ case T_SPF: return US"SPF";
case T_PTR: return US"PTR";
case T_SOA: return US"SOA";
case T_SRV: return US"SRV";
case T_NS: return US"NS";
case T_CNAME: return US"CNAME";
+ case T_TLSA: return US"TLSA";
default: return US"?";
}
}
static int
dns_return(uschar *name, int type, int rc)
{
+res_state resp = os_get_dns_resolver_res();
tree_node *node = store_get_perm(sizeof(tree_node) + 290);
sprintf(CS node->name, "%.255s-%s-%lx", name, dns_text_type(type),
- _res.options);
+ resp->options);
node->data.val = rc;
(void)tree_insertnode(&tree_dns_fails, node);
return rc;
int
dns_basic_lookup(dns_answer *dnsa, uschar *name, int type)
{
-int rc = -1;
#ifndef STAND_ALONE
+int rc = -1;
uschar *save;
#endif
+res_state resp = os_get_dns_resolver_res();
tree_node *previous;
uschar node_name[290];
caching for successful lookups. */
sprintf(CS node_name, "%.255s-%s-%lx", name, dns_text_type(type),
- _res.options);
+ resp->options);
previous = tree_search(tree_dns_fails, node_name);
if (previous != NULL)
{
uschar *checkname = name;
int ovector[3*(EXPAND_MAXN+1)];
- if (regex_check_dns_names == NULL)
- regex_check_dns_names =
- regex_must_compile(check_dns_names_pattern, FALSE, TRUE);
+ dns_pattern_init();
/* For an SRV lookup, skip over the first two components (the service and
protocol names, which both start with an underscore). */
- if (type == T_SRV)
+ if (type == T_SRV || type == T_TLSA)
{
while (*checkname++ != '.');
while (*checkname++ != '.');
dns_lookup(dns_answer *dnsa, uschar *name, int type, uschar **fully_qualified_name)
{
int i;
-uschar *orig_name = name;
+const uschar *orig_name = name;
+BOOL secure_so_far = TRUE;
/* Loop to follow CNAME chains so far, but no further... */
/* If any data records of the correct type were found, we are done. */
- if (type_rr.data != NULL) return DNS_SUCCEED;
+ if (type_rr.data != NULL)
+ {
+ if (!secure_so_far) /* mark insecure if any element of CNAME chain was */
+ dns_set_insecure(dnsa);
+ return DNS_SUCCEED;
+ }
/* If there are no data records, we need to re-scan the DNS using the
domain given in the CNAME record, which should exist (otherwise we should
if (datalen < 0) return DNS_FAIL;
name = data;
+ if (!dns_is_secure(dnsa))
+ secure_so_far = FALSE;
+
DEBUG(D_dns) debug_printf("CNAME found: change to %s\n", name);
} /* Loop back to do another lookup */
return yield;
}
+
+
+void
+dns_pattern_init(void)
+{
+if (check_dns_names_pattern[0] != 0 && !regex_check_dns_names)
+ regex_check_dns_names =
+ regex_must_compile(check_dns_names_pattern, FALSE, TRUE);
+}
+
+/* vi: aw ai sw=2
+*/
/* End of dns.c */