return (unsigned int)(random_seed >> 16) % limit;
}
+/*************************************************
+* Wrappers for logging lookup times *
+*************************************************/
+
+/* When the 'slow_lookup_log' variable is enabled, these wrappers will
+write to the log file all (potential) dns lookups that take more than
+slow_lookup_log milliseconds
+*/
+
+static void
+log_long_lookup(const uschar * type, const uschar * data, unsigned long msec)
+{
+log_write(0, LOG_MAIN, "Long %s lookup for '%s': %lu msec",
+ type, data, msec);
+}
+
+
+/* returns the current system epoch time in milliseconds. */
+static unsigned long
+get_time_in_ms()
+{
+struct timeval tmp_time;
+unsigned long seconds, microseconds;
+
+gettimeofday(&tmp_time, NULL);
+seconds = (unsigned long) tmp_time.tv_sec;
+microseconds = (unsigned long) tmp_time.tv_usec;
+return seconds*1000 + microseconds/1000;
+}
+
+
+static int
+dns_lookup_timerwrap(dns_answer *dnsa, const uschar *name, int type,
+ const uschar **fully_qualified_name)
+{
+int retval;
+unsigned long time_msec;
+
+if (!slow_lookup_log)
+ return dns_lookup(dnsa, name, type, fully_qualified_name);
+
+time_msec = get_time_in_ms();
+retval = dns_lookup(dnsa, name, type, fully_qualified_name);
+if ((time_msec = get_time_in_ms() - time_msec) > slow_lookup_log)
+ log_long_lookup(US"name", name, time_msec);
+return retval;
+}
/*************************************************
*************************************************/
/* This function is called instead of gethostbyname(), gethostbyname2(), or
-getipnodebyname() when running in the test harness. It recognizes the name
-"manyhome.test.ex" and generates a humungous number of IP addresses. It also
+getipnodebyname() when running in the test harness. . It also
recognizes an unqualified "localhost" and forces it to the appropriate loopback
address. IP addresses are treated as literals. For other names, it uses the DNS
to find the host name. In the test harness, this means it will access only the
debug_printf("using host_fake_gethostbyname for %s (%s)\n", name,
(af == AF_INET)? "IPv4" : "IPv6");
-/* Handle the name that needs a vast number of IP addresses */
-
-if (Ustrcmp(name, "manyhome.test.ex") == 0 && af == AF_INET)
- {
- int i, j;
- yield = store_get(sizeof(struct hostent));
- alist = store_get(2049 * sizeof(char *));
- adds = store_get(2048 * 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 (i = 104; i <= 111; i++)
- {
- for (j = 0; j <= 255; j++)
- {
- *alist++ = adds;
- *adds++ = 10;
- *adds++ = 250;
- *adds++ = i;
- *adds++ = j;
- }
- }
- *alist = NULL;
- return yield;
- }
-
/* Handle unqualified "localhost" */
if (Ustrcmp(name, "localhost") == 0)
else
{
int type = (af == AF_INET)? T_A:T_AAAA;
- int rc = dns_lookup(&dnsa, lname, type, NULL);
+ int rc = dns_lookup_timerwrap(&dnsa, lname, type, NULL);
int count = 0;
lookup_dnssec_authenticated = NULL;
}
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
+ rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
- {
- if (rr->type == type) count++;
- }
+ if (rr->type == type)
+ count++;
yield = store_get(sizeof(struct hostent));
alist = store_get((count + 1) * sizeof(char **));
yield->h_addr_list = CSS alist;
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
+ rr;
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);
+ if (!(da = dns_address_from_rr(&dnsa, rr))) break;
*alist++ = adds;
n = host_aton(da->address, x);
for (i = 0; i < n; i++)
uschar *s, *t;
struct hostent *hosts;
struct in_addr addr;
+unsigned long time_msec;
+
+if (slow_lookup_log) time_msec = get_time_in_ms();
/* Lookup on IPv6 system */
hosts = gethostbyaddr(CS(&addr), sizeof(addr), AF_INET);
#endif
+if ( slow_lookup_log
+ && (time_msec = get_time_in_ms() - time_msec) > slow_lookup_log
+ )
+ log_long_lookup(US"name", sender_host_address, time_msec);
+
/* Failed to look up the host. */
if (hosts == NULL)
{
dns_init(FALSE, FALSE, FALSE); /* dnssec ctrl by dns_dnssec_ok glbl */
dns_build_reverse(sender_host_address, buffer);
- rc = dns_lookup(&dnsa, buffer, T_PTR, NULL);
+ rc = dns_lookup_timerwrap(&dnsa, buffer, T_PTR, NULL);
/* The first record we come across is used for the name; others are
considered to be aliases. We have to scan twice, in order to find out the
dns_init((flags & HOST_FIND_QUALIFY_SINGLE) != 0,
(flags & HOST_FIND_SEARCH_PARENTS) != 0,
- FALSE); /*XXX dnssec? */
+ FALSE); /* Cannot retrieve dnssec status so do not request */
/* In an IPv6 world, unless IPv6 has been disabled, we need to scan for both
kinds of address, so go round the loop twice. Note that we have ensured that
BOOL ipv4_addr;
int error_num = 0;
struct hostent *hostdata;
+ unsigned long time_msec;
#ifdef STAND_ALONE
printf("Looking up: %s\n", host->name);
#endif
+ if (slow_lookup_log) time_msec = get_time_in_ms();
+
#if HAVE_IPV6
if (running_in_test_harness)
hostdata = host_fake_gethostbyname(host->name, af, &error_num);
}
#endif /* HAVE_IPV6 */
+ if (slow_lookup_log
+ && (time_msec = get_time_in_ms() - time_msec) > slow_lookup_log)
+ log_long_lookup(US"name", host->name, time_msec);
+
if (hostdata == NULL)
{
uschar *error;
switch (error_num)
{
case HOST_NOT_FOUND: error = US"HOST_NOT_FOUND"; break;
- case TRY_AGAIN: error = US"TRY_AGAIN"; break;
- case NO_RECOVERY: error = US"NO_RECOVERY"; break;
- case NO_DATA: error = US"NO_DATA"; break;
+ case TRY_AGAIN: error = US"TRY_AGAIN"; break;
+ case NO_RECOVERY: error = US"NO_RECOVERY"; break;
+ case NO_DATA: error = US"NO_DATA"; break;
#if NO_DATA != NO_ADDRESS
- case NO_ADDRESS: error = US"NO_ADDRESS"; break;
+ case NO_ADDRESS: error = US"NO_ADDRESS"; break;
#endif
default: error = US"?"; break;
}
else
#endif /* STAND_ALONE */
- #ifdef SUPPORT_A6
- i = 2; /* look up A6 and AAAA and A records */
- #else
i = 1; /* look up AAAA and A records */
- #endif /* SUPPORT_A6 */
/* The IPv4 world */
dns_answer dnsa;
dns_scan dnss;
- int rc = dns_lookup(&dnsa, host->name, type, fully_qualified_name);
+ int rc = dns_lookup_timerwrap(&dnsa, host->name, type, fully_qualified_name);
lookup_dnssec_authenticated = !dnssec_request ? NULL
: dns_is_secure(&dnsa) ? US"yes" : US"no";
/* Lookup succeeded: fill in the given host item with the first non-ignored
address found; create additional items for any others. A single A6 record
- may generate more than one address. */
+ may generate more than one address. The lookup had a chance to update the
+ fqdn; we do not want any later times round the loop to do so. */
+
+ fully_qualified_name = NULL;
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
+ rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
{
if (rr->type == type)
DEBUG(D_host_lookup)
{
- if (da == NULL)
- debug_printf("no addresses extracted from A6 RR for %s\n",
+ if (!da) debug_printf("no addresses extracted from A6 RR for %s\n",
host->name);
}
/* This loop runs only once for A and AAAA records, but may run
several times for an A6 record that generated multiple addresses. */
- for (; da != NULL; da = da->next)
+ for (; da; da = da->next)
{
#ifndef STAND_ALONE
if (ignore_target_hosts != NULL &&
srv_service when SRV used, the service name
srv_fail_domains DNS errors for these domains => assume nonexist
mx_fail_domains DNS errors for these domains => assume nonexist
- dnssec_request_domains => make dnssec request
- dnssec_require_domains => ditto and nonexist failures
+ dnssec_d.request => make dnssec request: domainlist
+ dnssec_d.require => ditto and nonexist failures
fully_qualified_name if not NULL, return fully-qualified name
removed set TRUE if local host was removed from the list
int
host_find_bydns(host_item *host, const uschar *ignore_target_hosts, int whichrrs,
uschar *srv_service, uschar *srv_fail_domains, uschar *mx_fail_domains,
- uschar *dnssec_request_domains, uschar *dnssec_require_domains,
+ const dnssec_domains *dnssec_d,
const uschar **fully_qualified_name, BOOL *removed)
{
host_item *h, *last;
int yield;
dns_answer dnsa;
dns_scan dnss;
-BOOL dnssec_require = match_isinlist(host->name, CUSS &dnssec_require_domains,
+BOOL dnssec_require = dnssec_d
+ && match_isinlist(host->name, CUSS &dnssec_d->require,
0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK;
BOOL dnssec_request = dnssec_require
- || match_isinlist(host->name, CUSS &dnssec_request_domains,
- 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK;
+ || ( dnssec_d
+ && match_isinlist(host->name, CUSS &dnssec_d->request,
+ 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK);
dnssec_status_t dnssec;
/* Set the default fully qualified name to the incoming name, initialize the
dnssec = DS_UNK;
lookup_dnssec_authenticated = NULL;
- rc = dns_lookup(&dnsa, buffer, ind_type, CUSS &temp_fully_qualified_name);
+ rc = dns_lookup_timerwrap(&dnsa, buffer, ind_type, CUSS &temp_fully_qualified_name);
if (dnssec_request)
{
ind_type = T_MX;
dnssec = DS_UNK;
lookup_dnssec_authenticated = NULL;
- rc = dns_lookup(&dnsa, host->name, ind_type, fully_qualified_name);
+ rc = dns_lookup_timerwrap(&dnsa, host->name, ind_type, fully_qualified_name);
if (dnssec_request)
{
return yield;
}
-
-
-
/*************************************************
**************************************************
* Stand-alone test program *
else
{
int flags = whichrrs;
+ dnssec d;
h.name = buffer;
h.next = NULL;
if (qualify_single) flags |= HOST_FIND_QUALIFY_SINGLE;
if (search_parents) flags |= HOST_FIND_SEARCH_PARENTS;
+ d.request = request_dnssec ? &h.name : NULL;
+ d.require = require_dnssec ? &h.name : NULL;
+
rc = byname
? host_find_byname(&h, NULL, flags, &fully_qualified_name, TRUE)
: host_find_bydns(&h, NULL, flags, US"smtp", NULL, NULL,
- request_dnssec ? &h.name : NULL,
- require_dnssec ? &h.name : NULL,
- &fully_qualified_name, NULL);
+ &d, &fully_qualified_name, NULL);
if (rc == HOST_FIND_FAILED) printf("Failed\n");
else if (rc == HOST_FIND_AGAIN) printf("Again\n");