Further changes for the benefit of the new test suite.
authorPhilip Hazel <ph10@hermes.cam.ac.uk>
Fri, 16 Sep 2005 14:44:11 +0000 (14:44 +0000)
committerPhilip Hazel <ph10@hermes.cam.ac.uk>
Fri, 16 Sep 2005 14:44:11 +0000 (14:44 +0000)
doc/doc-txt/ChangeLog
src/OS/Makefile-Base
src/src/child.c
src/src/dns.c
src/src/host.c

index a11fba9..6c39998 100644 (file)
@@ -1,4 +1,4 @@
-$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.233 2005/09/15 16:02:07 fanf2 Exp $
+$Cambridge: exim/doc/doc-txt/ChangeLog,v 1.234 2005/09/16 14:44:11 ph10 Exp $
 
 Change log file for Exim from version 4.21
 -------------------------------------------
@@ -199,6 +199,10 @@ TF/04 Fix the ratelimit support in exim_fixdb. Patch provided by Brian
 TF/05 The fix for PH/43 was not completely correct; widen_domains is always
       OK for addresses that are the result of redirections.
 
+PH/48 A number of further additions for the benefit of the new test suite,
+      including a fake gethostbyname() that interfaces to the fake DNS resolver
+      (see PH/47 above).
+
 
 Exim version 4.52
 -----------------
index 2b805d8..e1f6ee6 100644 (file)
@@ -1,4 +1,4 @@
-# $Cambridge: exim/src/OS/Makefile-Base,v 1.8 2005/09/12 13:50:03 ph10 Exp $
+# $Cambridge: exim/src/OS/Makefile-Base,v 1.9 2005/09/16 14:44:11 ph10 Exp $
 
 # This file is the basis of the main makefile for Exim and friends. The
 # makefile at the top level arranges to build the main makefile by calling
@@ -727,15 +727,16 @@ test_dbfn:   config.h dbfn.c dummies.o sa-globals.o sa-os.o store.o \
          tod.o version.o $(LIBS) $(DBMLIB)
        rm -f dbfn.o
 
-test_host:   config.h host.c dns.c dummies.o sa-globals.o sa-os.o store.o \
-              string.o tod.o tree.o
+test_host:   config.h child.c host.c dns.c dummies.c sa-globals.o sa-os.o \
+              store.o string.o tod.o tree.o
+       $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE -DTEST_HOST child.c
        $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE -DTEST_HOST host.c
        $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE -DTEST_HOST dns.c
        $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE -DTEST_HOST dummies.c
        $(LNCC) -o test_host $(LFLAGS) \
-         host.o dns.o dummies.o sa-globals.o os.o store.o string.o tod.o tree.o \
-         $(LIBS) $(LIBRESOLV)
-       rm -f dummies.o  host.o dns.o
+         host.o child.o dns.o dummies.o sa-globals.o os.o store.o string.o \
+         tod.o tree.o $(LIBS) $(LIBRESOLV)
+       rm -f child.o dummies.o host.o dns.o
 
 test_os:     os.h os.c dummies.o sa-globals.o store.o string.o tod.o
        $(CC) -c $(CFLAGS) $(INCLUDE) -DSTAND_ALONE os.c
index 2cd5e6f..8445bf5 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/child.c,v 1.5 2005/06/27 14:29:43 ph10 Exp $ */
+/* $Cambridge: exim/src/src/child.c,v 1.6 2005/09/16 14:44:11 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -38,7 +38,7 @@ if (oldfd == newfd) return;
 }
 
 
-
+#ifndef STAND_ALONE
 /*************************************************
 *   Build argv list and optionally re-exec Exim  *
 *************************************************/
@@ -233,7 +233,7 @@ if (pid > 0)
 errno = save_errno;
 return (pid_t)(-1);
 }
-
+#endif
 
 
 
index 83daf50..7395854 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/dns.c,v 1.10 2005/09/13 15:40:07 ph10 Exp $ */
+/* $Cambridge: exim/src/src/dns.c,v 1.11 2005/09/16 14:44:11 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -30,16 +30,16 @@ static void dns_complete_a6(dns_address ***, dns_answer *, dns_record *,
 /* This function is called instead of res_search() when Exim is running in its
 test harness. It recognizes some special domain names, and uses them to force
 failure and retry responses (optionally with a delay). It also recognises the
-zones test.ex and 10.in-addr.arpa, and for those it calls an external utility
-that mock-up a nameserver, if it can find the utility. Otherwise, it passes its
-arguments on to res_search().
+zones test.ex, 10.in-addr.arpa, and 0.8.e.f.ip6.arpa, and for those it calls an
+external utility that mock-up a nameserver, if it can find the utility.
+Otherwise, it passes its arguments on to res_search().
 
 Background: the original test suite required a real nameserver to carry the
-test.ex and 10.in-addr.arpa zones, whereas the new test suit has the fake
-server for portability. This code supports both.
+test zones, whereas the new test suit has the fake server for portability. This
+code supports both.
 
 Arguments:
-  name        the domain name
+  domain      the domain name
   type        the DNS record type
   answerptr   where to put the answer
   size        size of the answer area
@@ -48,10 +48,16 @@ Returns:      length of returned data, or -1 on error (h_errno set)
 */
 
 static int
-fakens_search(uschar *name, int type, uschar *answerptr, int size)
+fakens_search(uschar *domain, int type, uschar *answerptr, int size)
 {
-int len = Ustrlen(name);
-uschar *endname = name + len;
+int len = Ustrlen(domain);
+uschar *endname;
+uschar name[256];
+
+if (domain[len - 1] == '.') len--;
+Ustrncpy(name, domain, len);
+name[len] = 0;
+endname = name + len;
 
 if (len >= 14 && Ustrcmp(endname - 14, "test.again.dns") == 0)
   {
@@ -77,7 +83,8 @@ if (len >= 13 && Ustrcmp(endname - 13, "test.fail.dns") == 0)
 
 if (Ustrcmp(name, "test.ex") == 0 ||
     (len > 8 && Ustrcmp(endname - 8, ".test.ex") == 0) ||
-    (len >= 16 && Ustrcmp(endname - 16, ".10.in-addr.arpa") == 0))
+    (len >= 16 && Ustrcmp(endname - 16, ".10.in-addr.arpa") == 0) ||
+    (len >= 17 && Ustrcmp(endname - 17, ".0.8.e.f.ip6.arpa") == 0))
   {
   uschar utilname[256];
   struct stat statbuf;
@@ -133,7 +140,9 @@ if (Ustrcmp(name, "test.ex") == 0 ||
 
 /* Not test.ex or 10.in-addr.arpa, or fakens utility not found. */
 
-return res_search(CS name, C_IN, type, answerptr, size);
+DEBUG(D_dns) debug_printf("passing %s on to res_search\n", domain);
+
+return res_search(CS domain, C_IN, type, answerptr, size);
 }
 
 
index 58e18a7..ee4461b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Cambridge: exim/src/src/host.c,v 1.13 2005/08/22 15:28:20 ph10 Exp $ */
+/* $Cambridge: exim/src/src/host.c,v 1.14 2005/09/16 14:44:11 ph10 Exp $ */
 
 /*************************************************
 *     Exim - an Internet mail transport agent    *
@@ -102,6 +102,13 @@ number of multihomed host IP addresses into the order, so as to get
 repeatability. This doesn't have to be efficient. But don't interchange IPv4
 and IPv6 addresses!
 
+NOTE:
+This sorting is not necessary for the new test harness, because it
+doesn't call the real DNS resolver, and its output is repeatable. However,
+until the old test harness is discarded, we need to retain this capability.
+The new harness is being developed towards the end of 2005. It will be some
+time before it can do everything that the old one can do.
+
 Arguments:
   host        -> the first host item
   last        -> the last host item
@@ -136,6 +143,148 @@ while (!done)
 
 
 /*************************************************
+*       Replace gethostbyname() when testing     *
+*************************************************/
+
+/* This function is called instead of gethostbyname(), gethostbyname2(), or
+getipnodebyname() when running in the test harness. It uses only the DNS to
+look up the host name. In the new test harness, this means it will access only
+the fake DNS resolver. In the old harness it will call the real resolver and
+access the test zone.
+
+Arguments:
+  name          the host name or a textual IP address
+  af            AF_INET or AF_INET6
+  error_num     where to put an error code:
+                HOST_NOT_FOUND/TRY_AGAIN/NO_RECOVERY/NO_DATA
+
+Returns:        a hostent structure or NULL for an error
+*/
+
+static struct hostent *
+host_fake_gethostbyname(uschar *name, int af, int *error_num)
+{
+int ipa;
+int alen = (af == AF_INET)? sizeof(struct in_addr):sizeof(struct in6_addr);
+uschar *lname = name;
+uschar *adds;
+uschar **alist;
+struct hostent *yield;
+dns_answer dnsa;
+dns_scan dnss;
+dns_record *rr;
+
+DEBUG(D_host_lookup)
+  debug_printf("using host_fake_gethostbyname for %s (%s)\n", name,
+    (af == AF_INET)? "IPv4" : "IPv6");
+
+if (Ustrcmp(name, "localhost") == 0)
+  lname = (af == AF_INET)? US"127.0.0.1" : US"::1";
+
+/* Handle a literal IP address */
+
+ipa = string_is_ip_address(lname, NULL);
+if (ipa != 0)
+  {
+  if ((ipa == 4 && af == AF_INET) ||
+      (ipa == 6 && af == AF_INET6))
+    {
+    int i, n;
+    int x[4];
+    yield = store_get(sizeof(struct hostent));
+    alist = store_get(2 * sizeof(char *));
+    adds  = store_get(alen);
+    yield->h_name = CS name;
+    yield->h_aliases = NULL;
+    yield->h_addrtype = af;
+    yield->h_length = alen;
+    yield->h_addr_list = CSS alist;
+    *alist++ = adds;
+    n = host_aton(lname, x);
+    for (i = 0; i < n; i++)
+      {
+      int y = x[i];
+      *adds++ = (y >> 24) & 255;
+      *adds++ = (y >> 16) & 255;
+      *adds++ = (y >> 8) & 255;
+      *adds++ = y & 255;
+      }
+    *alist = NULL;
+    }
+
+  /* Wrong kind of literal address */
+
+  else
+    {
+    *error_num = HOST_NOT_FOUND;
+    return NULL;
+    }
+  }
+
+/* Handle a host name */
+
+else
+  {
+  int type = (af == AF_INET)? T_A:T_AAAA;
+  int rc = dns_lookup(&dnsa, lname, type, NULL);
+  int count = 0;
+
+  switch(rc)
+    {
+    case DNS_SUCCEED: break;
+    case DNS_NOMATCH: *error_num = HOST_NOT_FOUND; return NULL;
+    case DNS_NODATA:  *error_num = NO_DATA; return NULL;
+    case DNS_AGAIN:   *error_num = TRY_AGAIN; return NULL;
+    default:
+    case DNS_FAIL:    *error_num = NO_RECOVERY; return NULL;
+    }
+
+  for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+       rr != NULL;
+       rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+    {
+    if (rr->type == type) count++;
+    }
+
+  yield = store_get(sizeof(struct hostent));
+  alist = store_get((count + 1) * sizeof(char **));
+  adds  = store_get(count *alen);
+
+  yield->h_name = CS name;
+  yield->h_aliases = NULL;
+  yield->h_addrtype = af;
+  yield->h_length = alen;
+  yield->h_addr_list = CSS alist;
+
+  for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+       rr != NULL;
+       rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+    {
+    int i, n;
+    int x[4];
+    dns_address *da;
+    if (rr->type != type) continue;
+    da = dns_address_from_rr(&dnsa, rr);
+    *alist++ = adds;
+    n = host_aton(da->address, x);
+    for (i = 0; i < n; i++)
+      {
+      int y = x[i];
+      *adds++ = (y >> 24) & 255;
+      *adds++ = (y >> 16) & 255;
+      *adds++ = (y >> 8) & 255;
+      *adds++ = y & 255;
+      }
+    }
+  *alist = NULL;
+  }
+
+return yield;
+}
+
+
+
+/*************************************************
 *       Build chain of host items from list      *
 *************************************************/
 
@@ -1813,16 +1962,27 @@ for (i = 1; i <= times;
   struct hostent *hostdata;
 
   #if HAVE_IPV6
+  if (running_in_test_harness)
+    hostdata = host_fake_gethostbyname(host->name, af, &error_num);
+  else
+    {
     #if HAVE_GETIPNODEBYNAME
     hostdata = getipnodebyname(CS host->name, af, 0, &error_num);
     #else
     hostdata = gethostbyname2(CS host->name, af);
     error_num = h_errno;
     #endif
-  #else
-  hostdata = gethostbyname(CS host->name);
-  error_num = h_errno;
-  #endif
+    }
+
+  #else    /* not HAVE_IPV6 */
+  if (running_in_test_harness)
+    hostdata = host_fake_gethostbyname(host->name, AF_INET, &error_num);
+  else
+    {
+    hostdata = gethostbyname(CS host->name);
+    error_num = h_errno;
+    }
+  #endif   /* HAVE_IPV6 */
 
   if (hostdata == NULL)
     {
@@ -2053,7 +2213,6 @@ to do so. On an IPv4 system, go round the loop once only, looking only for A
 records. */
 
 #if HAVE_IPV6
-
   #ifndef STAND_ALONE
     if (dns_ipv4_lookup != NULL &&
         match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN,
@@ -2317,8 +2476,10 @@ if ((whichrrs & HOST_FIND_BY_SRV) != 0)
 
   if (rc == DNS_FAIL || rc == DNS_AGAIN)
     {
+    #ifndef STAND_ALONE
     if (match_isinlist(host->name, &srv_fail_domains, 0, NULL, NULL, MCL_DOMAIN,
         TRUE, NULL) != OK)
+    #endif
       return HOST_FIND_AGAIN;
     DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA "
       "(domain in srv_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN");
@@ -2339,8 +2500,10 @@ if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0)
   if (rc == DNS_NOMATCH) return HOST_FIND_FAILED;
   if (rc == DNS_FAIL || rc == DNS_AGAIN)
     {
+    #ifndef STAND_ALONE
     if (match_isinlist(host->name, &mx_fail_domains, 0, NULL, NULL, MCL_DOMAIN,
         TRUE, NULL) != OK)
+    #endif
       return HOST_FIND_AGAIN;
     DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA "
       "(domain in mx_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN");
@@ -2986,18 +3149,6 @@ return yield;
 
 #ifdef STAND_ALONE
 
-BOOL alldigits(uschar *buffer)
-{
-if (!isdigit(*buffer)) return FALSE;
-if (*buffer == '0' && buffer[1] == 'x')
-  {
-  buffer++;
-  while (isxdigit(*(++buffer)));
-  }
-else while (isdigit(*(++buffer)));
-return (*buffer == 0);
-}
-
 int main(int argc, char **cargv)
 {
 host_item h;
@@ -3053,6 +3204,12 @@ while (Ufgets(buffer, 256, stdin) != NULL)
   else if (Ustrcmp(buffer, "no_qualify_single") == 0) qualify_single = FALSE;
   else if (Ustrcmp(buffer, "search_parents") == 0) search_parents = TRUE;
   else if (Ustrcmp(buffer, "no_search_parents") == 0) search_parents = FALSE;
+  else if (Ustrcmp(buffer, "test_harness") == 0)
+    running_in_test_harness = !running_in_test_harness;
+  else if (Ustrcmp(buffer, "res_debug") == 0)
+    {
+    _res.options ^= RES_DEBUG;
+    }
   else if (Ustrncmp(buffer, "retrans", 7) == 0)
     {
     (void)sscanf(CS(buffer+8), "%d", &dns_retrans);
@@ -3063,12 +3220,6 @@ while (Ufgets(buffer, 256, stdin) != NULL)
     (void)sscanf(CS(buffer+6), "%d", &dns_retry);
     _res.retry = dns_retry;
     }
-  else if (alldigits(buffer))
-    {
-    debug_selector = Ustrtol(buffer, NULL, 0);
-    _res.options &= ~RES_DEBUG;
-    DEBUG(D_resolver) _res.options |= RES_DEBUG;
-    }
   else
     {
     int flags = whichrrs;