DNS resolver init changes for NetBSD compatibility.
authorPhil Pennock <pdp@exim.org>
Sun, 6 May 2012 04:38:18 +0000 (21:38 -0700)
committerPhil Pennock <pdp@exim.org>
Sun, 6 May 2012 04:38:18 +0000 (21:38 -0700)
doc/doc-txt/ChangeLog
src/OS/os.h-NetBSD
src/src/dns.c
src/src/exim.h
src/src/exim_lock.c
src/src/os.c

index 80e8edf97a51b2dca6392b5f5f921047c3f664fc..ed226b7564f9d687a4f34bbd9fd68d62e095963a 100644 (file)
@@ -81,6 +81,11 @@ PP/17 OpenSSL: new expansion var $tls_sni, which if used in tls_certificate
 PP/18 Bugzilla 1122 - check localhost_number expansion for failure, avoid
       NULL dereference.  Report and patch from Alun Jones.
 
 PP/18 Bugzilla 1122 - check localhost_number expansion for failure, avoid
       NULL dereference.  Report and patch from Alun Jones.
 
+PP/19 DNS resolver init changes for NetBSD compatibility.  (Risk of breakage
+      on less well tested platforms).  Obviates NetBSD pkgsrc patch-ac.
+      Not seeing resolver debug output on NetBSD, but suspect this is a
+      resolver implementation change.
+
 
 Exim version 4.77
 -----------------
 
 Exim version 4.77
 -----------------
index 0f3a3d8fc9f7070e71d4103ab8b1259b1feeed0f..19a8ac0c7028de2eeaa514acf2f0190b78e54637 100644 (file)
@@ -12,6 +12,10 @@ typedef struct flock flock_t;
 #define os_strsignal strsignal
 #define OS_STRSIGNAL
 
 #define os_strsignal strsignal
 #define OS_STRSIGNAL
 
+#define os_get_dns_resolver_res __res_get_state
+#define os_put_dns_resolver_res(RP) __res_put_state(RP)
+#define OS_GET_DNS_RESOLVER_RES
+
 #include <sys/param.h>
 
 #if __NetBSD_Version__ >= 299000900
 #include <sys/param.h>
 
 #if __NetBSD_Version__ >= 299000900
index f5e8ab7384ab306ad7acea13a495a416f7ec1e15..c903d0ba9840e1fccddc88120611afac1c205db9 100644 (file)
@@ -166,26 +166,30 @@ 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)
 
 #ifdef RES_USE_EDNS0
 if (dns_use_edns0 >= 0)
   {
   if (dns_use_edns0)
-    _res.options |= RES_USE_EDNS0;
+    resp->options |= RES_USE_EDNS0;
   else
   else
-    _res.options &= ~RES_USE_EDNS0;
+    resp->options &= ~RES_USE_EDNS0;
   DEBUG(D_resolver)
     debug_printf("Coerced resolver EDNS0 support %s.\n",
         dns_use_edns0 ? "on" : "off");
   DEBUG(D_resolver)
     debug_printf("Coerced resolver EDNS0 support %s.\n",
         dns_use_edns0 ? "on" : "off");
@@ -196,6 +200,8 @@ if (dns_use_edns0 >= 0)
     debug_printf("Unable to %sset EDNS0 without resolver support.\n",
         dns_use_edns0 ? "" : "un");
 #endif
     debug_printf("Unable to %sset EDNS0 without resolver support.\n",
         dns_use_edns0 ? "" : "un");
 #endif
+
+os_put_dns_resolver_res(resp);
 }
 
 
 }
 
 
@@ -440,9 +446,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;
@@ -482,6 +489,7 @@ dns_basic_lookup(dns_answer *dnsa, uschar *name, int type)
 int rc = -1;
 uschar *save;
 #endif
 int rc = -1;
 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];
@@ -492,7 +500,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)
   {
index 626d33dae08a3da4efcaa3e1a9248085fd84be75..e6e72facc9574a3e0b40c981ad072d72e55e154d 100644 (file)
@@ -353,6 +353,17 @@ to undefine it if resolv.h defines it. */
 #undef __P
 #endif
 
 #undef __P
 #endif
 
+/* If not defined by os.h, we do nothing special to push DNS resolver state
+back to be available by the classic resolver routines.  Also, provide
+prototype for our get routine, unless defined away. */
+
+#ifndef os_put_dns_resolver_res
+# define os_put_dns_resolver_res(R) do {/**/} while(0)
+#endif
+#ifndef os_get_dns_resolver_res
+res_state os_get_dns_resolver_res(void);
+#endif
+
 /* These three are to support the IP option logging code. Linux is
 different to everyone else and there are also other systems which don't
 have netinet/ip_var.h, so there's a general macro to control its inclusion. */
 /* These three are to support the IP option logging code. Linux is
 different to everyone else and there are also other systems which don't
 have netinet/ip_var.h, so there's a general macro to control its inclusion. */
index 027a55831d1e106d09ad336ed51e5fe7b395e6e5..0a9dfde2da7f6cbcf96c6350d9af248da9441868 100644 (file)
@@ -70,6 +70,10 @@ the other stuff in os.c, so force the other macros to omit it. */
   #define FIND_RUNNING_INTERFACES
 #endif
 
   #define FIND_RUNNING_INTERFACES
 #endif
 
+#ifndef OS_GET_DNS_RESOLVER_RES
+  #define OS_GET_DNS_RESOLVER_RES
+#endif
+
 #include "../src/os.c"
 
 
 #include "../src/os.c"
 
 
index 07514b5cf04fa785ff9db6f53e4a77c46d767fea..a70bc61158a34e08a2fa1e8cd3540529b3b1ec76 100644 (file)
@@ -795,6 +795,50 @@ return yield;
 
 
 
 
 
 
+/* ----------------------------------------------------------------------- */
+
+/***********************************************************
+*                 DNS Resolver Base Finder                 *
+***********************************************************/
+
+/* We need to be able to set options for the system resolver(5), historically
+made available as _res.  At least one OS (NetBSD) now no longer provides this
+directly, instead making you call a function per thread to get a handle.
+Other OSs handle thread-safe resolver differently, in ways which fail if the
+programmer creates their own structs. */
+
+#ifndef OS_GET_DNS_RESOLVER_RES
+
+#include <resolv.h>
+
+/* confirmed that res_state is typedef'd as a struct* on BSD and Linux, will
+find out how unportable it is on other OSes, but most resolver implementations
+should be descended from ISC's bind.
+
+Linux and BSD do:
+  define _res (*__res_state())
+identically.  We just can't rely on __foo functions.  It's surprising that use
+of _res has been as portable as it has, for so long.
+
+So, since _res works everywhere, and everything can decode the struct, I'm
+going to gamble that res_state is a typedef everywhere and use that as the
+return type.
+*/
+
+res_state
+os_get_dns_resolver_res(void)
+{
+  return &_res;
+}
+
+#endif /* OS_GET_DNS_RESOLVER_RES */
+
+
+/* ----------------------------------------------------------------------- */
+
+
+
+
 
 /*************************************************
 **************************************************
 
 /*************************************************
 **************************************************