X-Git-Url: https://vcs.fsf.org/?a=blobdiff_plain;f=src%2Fsrc%2Fhost.c;h=206751757d4775359094e0f5442ab834d35169d4;hb=5f3d09836c17cb80a1953196c98371ed70396903;hp=2eef0ba700ee2e25e993c2555d5a356a138ffce3;hpb=a1bccd48f3956b50a13a34f5aed4b72c658c61af;p=exim.git diff --git a/src/src/host.c b/src/src/host.c index 2eef0ba70..206751757 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -94,6 +94,53 @@ random_seed = 1103515245 * random_seed + 12345; 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; +} /************************************************* @@ -118,7 +165,7 @@ Returns: a hostent structure or NULL for an error */ static struct hostent * -host_fake_gethostbyname(uschar *name, int af, int *error_num) +host_fake_gethostbyname(const uschar *name, int af, int *error_num) { #if HAVE_IPV6 int alen = (af == AF_INET)? sizeof(struct in_addr):sizeof(struct in6_addr); @@ -127,7 +174,7 @@ int alen = sizeof(struct in_addr); #endif int ipa; -uschar *lname = name; +const uschar *lname = name; uschar *adds; uschar **alist; struct hostent *yield; @@ -217,7 +264,7 @@ if (ipa != 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; @@ -295,19 +342,18 @@ Returns: nothing */ void -host_build_hostlist(host_item **anchor, uschar *list, BOOL randomize) +host_build_hostlist(host_item **anchor, const uschar *list, BOOL randomize) { int sep = 0; int fake_mx = MX_NONE; /* This value is actually -1 */ uschar *name; -uschar buffer[1024]; if (list == NULL) return; if (randomize) fake_mx--; /* Start at -2 for randomizing */ *anchor = NULL; -while ((name = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) +while ((name = string_nextinlist(&list, &sep, NULL, 0)) != NULL) { host_item *h; @@ -318,7 +364,7 @@ while ((name = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) != NULL) } h = store_get(sizeof(host_item)); - h->name = string_copy(name); + h->name = name; h->address = NULL; h->port = PORT_NONE; h->mx = fake_mx; @@ -444,7 +490,7 @@ Returns: a port number or PORT_NONE int host_item_get_port(host_item *h) { -uschar *p; +const uschar *p; int port, x; int len = Ustrlen(h->name); @@ -718,7 +764,7 @@ Returns: a chain of ip_address_items, each containing to a textual */ ip_address_item * -host_build_ifacelist(uschar *list, uschar *name) +host_build_ifacelist(const uschar *list, uschar *name) { int sep = 0; uschar *s; @@ -811,9 +857,9 @@ ip_address_item *running_interfaces = NULL; if (local_interface_data == NULL) { void *reset_item = store_get(0); - ip_address_item *dlist = host_build_ifacelist(local_interfaces, + ip_address_item *dlist = host_build_ifacelist(CUS local_interfaces, US"local_interfaces"); - ip_address_item *xlist = host_build_ifacelist(extra_local_interfaces, + ip_address_item *xlist = host_build_ifacelist(CUS extra_local_interfaces, US"extra_local_interfaces"); ip_address_item *ipa; @@ -972,7 +1018,7 @@ Returns: the number of ints used */ int -host_aton(uschar *address, int *bin) +host_aton(const uschar *address, int *bin) { int x[4]; int v4offset = 0; @@ -984,8 +1030,8 @@ supported. */ if (Ustrchr(address, ':') != NULL) { - uschar *p = address; - uschar *component[8]; + const uschar *p = address; + const uschar *component[8]; BOOL ipv4_ends = FALSE; int ci = 0; int nulloffset = 0; @@ -1179,7 +1225,7 @@ host_is_tls_on_connect_port(int port) { int sep = 0; uschar buffer[32]; -uschar *list = tls_in.on_connect_ports; +const uschar *list = tls_in.on_connect_ports; uschar *s; uschar *end; @@ -1214,7 +1260,7 @@ Returns: */ BOOL -host_is_in_net(uschar *host, uschar *net, int maskoffset) +host_is_in_net(const uschar *host, const uschar *net, int maskoffset) { int i; int address[4]; @@ -1329,9 +1375,9 @@ for (h = host; h != last->next; h = h->next) if (hosts_treat_as_local != NULL) { int rc; - uschar *save = deliver_domain; + const uschar *save = deliver_domain; deliver_domain = h->name; /* set $domain */ - rc = match_isinlist(string_copylc(h->name), &hosts_treat_as_local, 0, + rc = match_isinlist(string_copylc(h->name), CUSS &hosts_treat_as_local, 0, &domainlist_anchor, NULL, MCL_DOMAIN, TRUE, NULL); deliver_domain = save; if (rc == OK) goto FOUND_LOCAL; @@ -1455,6 +1501,9 @@ int len; 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 */ @@ -1490,6 +1539,11 @@ addr.s_addr = (S_ADDR_TYPE)inet_addr(CS sender_host_address); 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) @@ -1590,7 +1644,7 @@ uschar *hname, *save_hostname; uschar **aliases; uschar buffer[256]; uschar *ordername; -uschar *list = host_lookup_order; +const uschar *list = host_lookup_order; dns_record *rr; dns_answer dnsa; dns_scan dnss; @@ -1622,7 +1676,7 @@ while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer))) { 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 @@ -1742,8 +1796,8 @@ if (sender_host_name == NULL) HDEBUG(D_host_lookup) { uschar **aliases = sender_host_aliases; - debug_printf("IP address lookup yielded %s\n", sender_host_name); - while (*aliases != NULL) debug_printf(" alias %s\n", *aliases++); + debug_printf("IP address lookup yielded \"%s\"\n", sender_host_name); + while (*aliases != NULL) debug_printf(" alias \"%s\"\n", *aliases++); } /* We need to verify that a forward lookup on the name we found does indeed @@ -1892,8 +1946,8 @@ Returns: HOST_FIND_FAILED Failed to find the host or domain */ int -host_find_byname(host_item *host, uschar *ignore_target_hosts, int flags, - uschar **fully_qualified_name, BOOL local_host_check) +host_find_byname(host_item *host, const uschar *ignore_target_hosts, int flags, + const uschar **fully_qualified_name, BOOL local_host_check) { int i, yield, times; uschar **addrlist; @@ -1909,7 +1963,7 @@ dns_again_means_nonexist. */ if (running_in_test_harness) { - uschar *endname = host->name + Ustrlen(host->name); + const uschar *endname = host->name + Ustrlen(host->name); if (Ustrcmp(endname - 14, "test.again.dns") == 0) goto RETURN_AGAIN; } @@ -1932,8 +1986,8 @@ lookups here (except when testing standalone). */ #else if (disable_ipv6 || (dns_ipv4_lookup != NULL && - match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN, - TRUE, NULL) == OK)) + match_isinlist(host->name, CUSS &dns_ipv4_lookup, 0, NULL, NULL, + MCL_DOMAIN, TRUE, NULL) == OK)) #endif { af = AF_INET; times = 1; } @@ -1962,11 +2016,14 @@ for (i = 1; i <= times; 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); @@ -1990,17 +2047,22 @@ for (i = 1; i <= times; } #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; } @@ -2116,7 +2178,7 @@ yield = local_host_check? HDEBUG(D_host_lookup) { - host_item *h; + const host_item *h; if (fully_qualified_name != NULL) debug_printf("fully qualified name = %s\n", *fully_qualified_name); debug_printf("%s looked up these IP addresses:\n", @@ -2146,9 +2208,9 @@ RETURN_AGAIN: { #ifndef STAND_ALONE int rc; - uschar *save = deliver_domain; + const uschar *save = deliver_domain; deliver_domain = host->name; /* set $domain */ - rc = match_isinlist(host->name, &dns_again_means_nonexist, 0, NULL, NULL, + rc = match_isinlist(host->name, CUSS &dns_again_means_nonexist, 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL); deliver_domain = save; if (rc == OK) @@ -2206,7 +2268,8 @@ Returns: HOST_FIND_FAILED couldn't find A record static int set_address_from_dns(host_item *host, host_item **lastptr, - uschar *ignore_target_hosts, BOOL allow_ip, uschar **fully_qualified_name, + const uschar *ignore_target_hosts, BOOL allow_ip, + const uschar **fully_qualified_name, BOOL dnssec_request, BOOL dnssec_require) { dns_record *rr; @@ -2241,17 +2304,13 @@ loop once only, looking only for A records. */ #if HAVE_IPV6 #ifndef STAND_ALONE if (disable_ipv6 || (dns_ipv4_lookup != NULL && - match_isinlist(host->name, &dns_ipv4_lookup, 0, NULL, NULL, MCL_DOMAIN, - TRUE, NULL) == OK)) + match_isinlist(host->name, CUSS &dns_ipv4_lookup, 0, NULL, NULL, + MCL_DOMAIN, TRUE, NULL) == OK)) i = 0; /* look up A records only */ 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 */ @@ -2267,7 +2326,7 @@ for (; i >= 0; i--) 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"; @@ -2321,7 +2380,10 @@ for (; i >= 0; i--) /* 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; @@ -2481,10 +2543,10 @@ Returns: HOST_FIND_FAILED Failed to find the host or domain; */ int -host_find_bydns(host_item *host, uschar *ignore_target_hosts, int whichrrs, +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, - uschar **fully_qualified_name, BOOL *removed) + const uschar **fully_qualified_name, BOOL *removed) { host_item *h, *last; dns_record *rr; @@ -2493,10 +2555,10 @@ int ind_type = 0; int yield; dns_answer dnsa; dns_scan dnss; -BOOL dnssec_require = match_isinlist(host->name, &dnssec_require_domains, +BOOL dnssec_require = match_isinlist(host->name, CUSS &dnssec_require_domains, 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK; BOOL dnssec_request = dnssec_require - || match_isinlist(host->name, &dnssec_request_domains, + || match_isinlist(host->name, CUSS &dnssec_request_domains, 0, NULL, NULL, MCL_DOMAIN, TRUE, NULL) == OK; dnssec_status_t dnssec; @@ -2531,7 +2593,7 @@ if ((whichrrs & HOST_FIND_BY_SRV) != 0) dnssec = DS_UNK; lookup_dnssec_authenticated = NULL; - rc = dns_lookup(&dnsa, buffer, ind_type, &temp_fully_qualified_name); + rc = dns_lookup_timerwrap(&dnsa, buffer, ind_type, CUSS &temp_fully_qualified_name); if (dnssec_request) { @@ -2556,8 +2618,8 @@ 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) + if (match_isinlist(host->name, CUSS &srv_fail_domains, 0, NULL, NULL, + MCL_DOMAIN, TRUE, NULL) != OK) #endif { yield = HOST_FIND_AGAIN; goto out; } DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA " @@ -2577,7 +2639,7 @@ if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0) 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) { @@ -2608,8 +2670,8 @@ if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0) case DNS_FAIL: case DNS_AGAIN: #ifndef STAND_ALONE - if (match_isinlist(host->name, &mx_fail_domains, 0, NULL, NULL, MCL_DOMAIN, - TRUE, NULL) != OK) + if (match_isinlist(host->name, CUSS &mx_fail_domains, 0, NULL, NULL, + MCL_DOMAIN, TRUE, NULL) != OK) #endif { yield = HOST_FIND_AGAIN; goto out; } DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA " @@ -3068,8 +3130,9 @@ DEBUG(D_host_lookup) yield); for (h = host; h != last->next; h = h->next) { - debug_printf(" %s %s MX=%d ", h->name, - (h->address == NULL)? US"" : h->address, h->mx); + debug_printf(" %s %s MX=%d %s", h->name, + !h->address ? US"" : h->address, h->mx, + h->dnssec == DS_YES ? US"DNSSEC " : US""); if (h->port != PORT_NONE) debug_printf("port=%d ", h->port); if (h->status >= hstatus_unusable) debug_printf("*"); debug_printf("\n"); @@ -3082,9 +3145,6 @@ dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ return yield; } - - - /************************************************* ************************************************** * Stand-alone test program *