release: no .lz by default for now
[exim.git] / src / src / dns.c
index 1a940b6abdd6818ec78554385a9b42dbccfad4f2..ae76e9e3f89277903f5f3512f4dd95af48bc8e0d 100644 (file)
@@ -1,10 +1,8 @@
-/* $Cambridge: exim/src/src/dns.c,v 1.14 2006/02/16 10:05:33 ph10 Exp $ */
-
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
 *************************************************/
 
-/* Copyright (c) University of Cambridge 1995 - 2006 */
+/* Copyright (c) University of Cambridge 1995 - 2012 */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for interfacing with the DNS. */
 /* See the file NOTICE for conditions of use and distribution. */
 
 /* Functions for interfacing with the DNS. */
@@ -168,18 +166,42 @@ Returns:            nothing
 void
 dns_init(BOOL qualify_single, BOOL search_parents)
 {
 void
 dns_init(BOOL qualify_single, BOOL search_parents)
 {
-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();
   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);
                 (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
+
+os_put_dns_resolver_res(resp);
 }
 
 
 }
 
 
@@ -393,6 +415,7 @@ switch(t)
   case T_AAAA:  return US"AAAA";
   case T_A6:    return US"A6";
   case T_TXT:   return US"TXT";
   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_PTR:   return US"PTR";
   case T_SOA:   return US"SOA";
   case T_SRV:   return US"SRV";
@@ -424,9 +447,10 @@ Returns:     the return code
 static int
 dns_return(uschar *name, int type, int rc)
 {
 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),
 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;
 node->data.val = rc;
 (void)tree_insertnode(&tree_dns_fails, node);
 return rc;
@@ -453,6 +477,7 @@ Arguments:
 Returns:    DNS_SUCCEED   successful lookup
             DNS_NOMATCH   name not found (NXDOMAIN)
                           or name contains illegal characters (if checking)
 Returns:    DNS_SUCCEED   successful lookup
             DNS_NOMATCH   name not found (NXDOMAIN)
                           or name contains illegal characters (if checking)
+                          or name is an IP address (for IP address lookup)
             DNS_NODATA    domain exists, but no data for this type (NODATA)
             DNS_AGAIN     soft failure, try again later
             DNS_FAIL      DNS failure
             DNS_NODATA    domain exists, but no data for this type (NODATA)
             DNS_AGAIN     soft failure, try again later
             DNS_FAIL      DNS failure
@@ -461,10 +486,11 @@ Returns:    DNS_SUCCEED   successful lookup
 int
 dns_basic_lookup(dns_answer *dnsa, uschar *name, int type)
 {
 int
 dns_basic_lookup(dns_answer *dnsa, uschar *name, int type)
 {
-int rc = -1;
 #ifndef STAND_ALONE
 #ifndef STAND_ALONE
+int rc = -1;
 uschar *save;
 #endif
 uschar *save;
 #endif
+res_state resp = os_get_dns_resolver_res();
 
 tree_node *previous;
 uschar node_name[290];
 
 tree_node *previous;
 uschar node_name[290];
@@ -475,7 +501,7 @@ have many addresses in the same domain. We rely on the resolver and name server
 caching for successful lookups. */
 
 sprintf(CS node_name, "%.255s-%s-%lx", name, dns_text_type(type),
 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)
   {
 previous = tree_search(tree_dns_fails, node_name);
 if (previous != NULL)
   {
@@ -504,7 +530,7 @@ For SRV records, we omit the initial _smtp._tcp. components at the start. */
 
 #ifndef STAND_ALONE   /* Omit this for stand-alone tests */
 
 
 #ifndef STAND_ALONE   /* Omit this for stand-alone tests */
 
-if (check_dns_names_pattern[0] != 0 && type != T_PTR)
+if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT)
   {
   uschar *checkname = name;
   int ovector[3*(EXPAND_MAXN+1)];
   {
   uschar *checkname = name;
   int ovector[3*(EXPAND_MAXN+1)];
@@ -539,7 +565,20 @@ if (check_dns_names_pattern[0] != 0 && type != T_PTR)
 number of bytes the message would need, so we need to check for this case. The
 effect is to truncate overlong data.
 
 number of bytes the message would need, so we need to check for this case. The
 effect is to truncate overlong data.
 
-If we are running in the test harness, instead of calling the normal resolver
+On some systems, res_search() will recognize "A-for-A" queries and return
+the IP address instead of returning -1 with h_error=HOST_NOT_FOUND. Some
+nameservers are also believed to do this. It is, of course, contrary to the
+specification of the DNS, so we lock it out. */
+
+if ((
+    #ifdef SUPPORT_A6
+    type == T_A6 ||
+    #endif
+    type == T_A || type == T_AAAA) &&
+    string_is_ip_address(name, NULL) != 0)
+  return DNS_NOMATCH;
+
+/* If we are running in the test harness, instead of calling the normal resolver
 (res_search), we call fakens_search(), which recognizes certain special
 domains, and interfaces to a fake nameserver for certain special zones. */
 
 (res_search), we call fakens_search(), which recognizes certain special
 domains, and interfaces to a fake nameserver for certain special zones. */
 
@@ -548,7 +587,12 @@ if (running_in_test_harness)
 else
   dnsa->answerlen = res_search(CS name, C_IN, type, dnsa->answer, MAXPACKET);
 
 else
   dnsa->answerlen = res_search(CS name, C_IN, type, dnsa->answer, MAXPACKET);
 
-if (dnsa->answerlen > MAXPACKET) dnsa->answerlen = MAXPACKET;
+if (dnsa->answerlen > MAXPACKET)
+  {
+  DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) resulted in overlong packet (size %d), truncating to %d.\n",
+    name, dns_text_type(type), dnsa->answerlen, MAXPACKET);
+  dnsa->answerlen = MAXPACKET;
+  }
 
 if (dnsa->answerlen < 0) switch (h_errno)
   {
 
 if (dnsa->answerlen < 0) switch (h_errno)
   {
@@ -677,12 +721,10 @@ for (i = 0; i < 10; i++)
     else if (rr->type == T_CNAME) cname_rr = *rr;
     }
 
     else if (rr->type == T_CNAME) cname_rr = *rr;
     }
 
-  /* If a CNAME was found, take the fully qualified name from it; otherwise
-  from the first data record, if present. For testing, there is a magic name
-  that gets its casing adjusted, because my resolver doesn't seem to pass back
-  upper case letters in domain names. */
+  /* For the first time round this loop, if a CNAME was found, take the fully
+  qualified name from it; otherwise from the first data record, if present. */
 
 
-  if (fully_qualified_name != NULL)
+  if (i == 0 && fully_qualified_name != NULL)
     {
     if (cname_rr.data != NULL)
       {
     {
     if (cname_rr.data != NULL)
       {
@@ -712,6 +754,8 @@ for (i = 0; i < 10; i++)
     cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256);
   if (datalen < 0) return DNS_FAIL;
   name = data;
     cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256);
   if (datalen < 0) return DNS_FAIL;
   name = data;
+
+  DEBUG(D_dns) debug_printf("CNAME found: change to %s\n", name);
   }       /* Loop back to do another lookup */
 
 /*Control reaches here after 10 times round the CNAME loop. Something isn't
   }       /* Loop back to do another lookup */
 
 /*Control reaches here after 10 times round the CNAME loop. Something isn't