From e7726cbf334d1782435662c2d209ad82ec602c5c Mon Sep 17 00:00:00 2001 From: Philip Hazel Date: Fri, 16 Sep 2005 14:44:11 +0000 Subject: [PATCH] Further changes for the benefit of the new test suite. --- doc/doc-txt/ChangeLog | 6 +- src/OS/Makefile-Base | 13 +-- src/src/child.c | 6 +- src/src/dns.c | 33 ++++--- src/src/host.c | 199 +++++++++++++++++++++++++++++++++++++----- 5 files changed, 211 insertions(+), 46 deletions(-) diff --git a/doc/doc-txt/ChangeLog b/doc/doc-txt/ChangeLog index a11fba9d6..6c39998b5 100644 --- a/doc/doc-txt/ChangeLog +++ b/doc/doc-txt/ChangeLog @@ -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 ----------------- diff --git a/src/OS/Makefile-Base b/src/OS/Makefile-Base index 2b805d870..e1f6ee6cb 100644 --- a/src/OS/Makefile-Base +++ b/src/OS/Makefile-Base @@ -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 diff --git a/src/src/child.c b/src/src/child.c index 2cd5e6fb9..8445bf5ad 100644 --- a/src/src/child.c +++ b/src/src/child.c @@ -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 diff --git a/src/src/dns.c b/src/src/dns.c index 83daf50f3..7395854ff 100644 --- a/src/src/dns.c +++ b/src/src/dns.c @@ -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); } diff --git a/src/src/host.c b/src/src/host.c index 58e18a757..ee4461bc8 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -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 @@ -135,6 +142,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; -- 2.25.1