X-Git-Url: https://git.exim.org/exim.git/blobdiff_plain/8743d3acaaa2262007aa2862ffecd6b19125e38d..1e1ddfac79fbcd052f199500a6493c7f79cb8462:/src/src/host.c diff --git a/src/src/host.c b/src/src/host.c index d84347cb1..0e0e0130b 100644 --- a/src/src/host.c +++ b/src/src/host.c @@ -3,6 +3,7 @@ *************************************************/ /* Copyright (c) University of Cambridge 1995 - 2018 */ +/* Copyright (c) The Exim Maintainers 2020 */ /* See the file NOTICE for conditions of use and distribution. */ /* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or @@ -138,7 +139,7 @@ if (!slow_lookup_log) 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); + log_long_lookup(dns_text_type(type), name, time_msec); return retval; } @@ -182,19 +183,18 @@ dns_scan dnss; DEBUG(D_host_lookup) debug_printf("using host_fake_gethostbyname for %s (%s)\n", name, - (af == AF_INET)? "IPv4" : "IPv6"); + af == AF_INET ? "IPv4" : "IPv6"); /* Handle unqualified "localhost" */ if (Ustrcmp(name, "localhost") == 0) - lname = (af == AF_INET)? US"127.0.0.1" : US"::1"; + lname = af == AF_INET ? US"127.0.0.1" : US"::1"; /* Handle a literal IP address */ if ((ipa = string_is_ip_address(lname, NULL)) != 0) - { - if ((ipa == 4 && af == AF_INET) || - (ipa == 6 && af == AF_INET6)) + if ( ipa == 4 && af == AF_INET + || ipa == 6 && af == AF_INET6) { int x[4]; yield = store_get(sizeof(struct hostent), FALSE); @@ -224,13 +224,12 @@ if ((ipa = string_is_ip_address(lname, NULL)) != 0) *error_num = HOST_NOT_FOUND; return NULL; } - } /* Handle a host name */ else { - int type = (af == AF_INET)? T_A:T_AAAA; + int type = af == AF_INET ? T_A:T_AAAA; int rc = dns_lookup_timerwrap(dnsa, lname, type, NULL); int count = 0; @@ -729,6 +728,7 @@ host_build_ifacelist(const uschar *list, uschar *name) int sep = 0; uschar *s; ip_address_item * yield = NULL, * last = NULL, * next; +BOOL taint = is_tainted(list); while ((s = string_nextinlist(&list, &sep, NULL, 0))) { @@ -747,7 +747,7 @@ while ((s = string_nextinlist(&list, &sep, NULL, 0))) address above. The field in the ip_address_item is large enough to hold an IPv6 address. */ - next = store_get(sizeof(ip_address_item), FALSE); + next = store_get(sizeof(ip_address_item), taint); next->next = NULL; Ustrcpy(next->address, s); next->port = port; @@ -1503,9 +1503,7 @@ Returns: OK, DEFER, FAIL static int host_name_lookup_byaddr(void) { -int len; -uschar *s, *t; -struct hostent *hosts; +struct hostent * hosts; struct in_addr addr; unsigned long time_msec = 0; /* init to quieten dumb static analysis */ @@ -1548,7 +1546,7 @@ hosts = gethostbyaddr(CS(&addr), sizeof(addr), AF_INET); 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); + log_long_lookup(US"gethostbyaddr", sender_host_address, time_msec); /* Failed to look up the host. */ @@ -1648,7 +1646,6 @@ int old_pool, rc; int sep = 0; uschar *save_hostname; uschar **aliases; -uschar buffer[256]; uschar *ordername; const uschar *list = host_lookup_order; dns_answer * dnsa = store_get_dns_answer(); @@ -1674,13 +1671,14 @@ if (f.running_in_test_harness && /* Do lookups directly in the DNS or via gethostbyaddr() (or equivalent), in the order specified by the host_lookup_order option. */ -while ((ordername = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) +while ((ordername = string_nextinlist(&list, &sep, NULL, 0))) { if (strcmpic(ordername, US"bydns") == 0) { + uschar * name = dns_build_reverse(sender_host_address); + dns_init(FALSE, FALSE, FALSE); /* dnssec ctrl by dns_dnssec_ok glbl */ - dns_build_reverse(sender_host_address, buffer); - rc = dns_lookup_timerwrap(dnsa, buffer, T_PTR, NULL); + rc = dns_lookup_timerwrap(dnsa, name, 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 @@ -2034,9 +2032,9 @@ for (int i = 1; i <= times; if ( slow_lookup_log && (time_msec = get_time_in_ms() - time_msec) > slow_lookup_log) - log_long_lookup(US"name", host->name, time_msec); + log_long_lookup(US"gethostbyname", host->name, time_msec); - if (hostdata == NULL) + if (!hostdata) { uschar *error; switch (error_num) @@ -2045,18 +2043,19 @@ for (int i = 1; i <= times; 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 + #if NO_DATA != NO_ADDRESS case NO_ADDRESS: error = US"NO_ADDRESS"; break; - #endif + #endif default: error = US"?"; break; } DEBUG(D_host_lookup) debug_printf("%s returned %d (%s)\n", + f.running_in_test_harness ? "host_fake_gethostbyname" : #if HAVE_IPV6 #if HAVE_GETIPNODEBYNAME - (af == AF_INET6)? "getipnodebyname(af=inet6)" : "getipnodebyname(af=inet)", + af == AF_INET6 ? "getipnodebyname(af=inet6)" : "getipnodebyname(af=inet)", #else - (af == AF_INET6)? "gethostbyname2(af=inet6)" : "gethostbyname2(af=inet)", + af == AF_INET6 ? "gethostbyname2(af=inet6)" : "gethostbyname2(af=inet)", #endif #else "gethostbyname", @@ -2650,7 +2649,7 @@ if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX) if (dnssec_request) if (dns_is_secure(dnsa)) { - DEBUG(D_host_lookup) debug_printf("%s MX DNSSEC\n", host->name); + DEBUG(D_host_lookup) debug_printf("%s (MX resp) DNSSEC\n", host->name); dnssec = DS_YES; lookup_dnssec_authenticated = US"yes"; } else @@ -3156,6 +3155,79 @@ dns_init(FALSE, FALSE, FALSE); /* clear the dnssec bit for getaddrbyname */ return yield; } + + + +#ifdef SUPPORT_DANE +/* Lookup TLSA record for host/port. +Return: OK success with dnssec; DANE mode + DEFER Do not use this host now, may retry later + FAIL_FORCED No TLSA record; DANE not usable + FAIL Do not use this connection +*/ + +int +tlsa_lookup(const host_item * host, dns_answer * dnsa, BOOL dane_required) +{ +uschar buffer[300]; +const uschar * fullname = buffer; +int rc; +BOOL sec; + +/* TLSA lookup string */ +(void)sprintf(CS buffer, "_%d._tcp.%.256s", host->port, host->name); + +rc = dns_lookup_timerwrap(dnsa, buffer, T_TLSA, &fullname); +sec = dns_is_secure(dnsa); +DEBUG(D_transport) + debug_printf("TLSA lookup ret %d %sDNSSEC\n", rc, sec ? "" : "not "); + +switch (rc) + { + case DNS_AGAIN: + return DEFER; /* just defer this TLS'd conn */ + + case DNS_SUCCEED: + if (sec) + { + DEBUG(D_transport) + { + dns_scan dnss; + for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_ANSWERS); rr; + rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)) + if (rr->type == T_TLSA && rr->size > 3) + { + uint16_t payload_length = rr->size - 3; + uschar s[MAX_TLSA_EXPANDED_SIZE], * sp = s, * p = US rr->data; + + sp += sprintf(CS sp, "%d ", *p++); /* usage */ + sp += sprintf(CS sp, "%d ", *p++); /* selector */ + sp += sprintf(CS sp, "%d ", *p++); /* matchtype */ + while (payload_length-- > 0 && sp-s < (MAX_TLSA_EXPANDED_SIZE - 4)) + sp += sprintf(CS sp, "%02x", *p++); + + debug_printf(" %s\n", s); + } + } + return OK; + } + log_write(0, LOG_MAIN, + "DANE error: TLSA lookup for %s not DNSSEC", host->name); + /*FALLTRHOUGH*/ + + case DNS_NODATA: /* no TLSA RR for this lookup */ + case DNS_NOMATCH: /* no records at all for this lookup */ + return dane_required ? FAIL : FAIL_FORCED; + + default: + case DNS_FAIL: + return dane_required ? FAIL : DEFER; + } +} +#endif /*SUPPORT_DANE*/ + + + /************************************************* ************************************************** * Stand-alone test program *