X-Git-Url: https://git.netwichtig.de/gitweb/?a=blobdiff_plain;f=src%2Fsrc%2Fhost.c;h=a31c09b659f15bee1740e210d49dd004634db492;hb=38a522bdfc23e9a221b475891f954b0dd6f82eee;hp=d84347cb1329b8c2712a240bd8692bda8fe36197;hpb=8743d3acaaa2262007aa2862ffecd6b19125e38d;p=user%2Fhenk%2Fcode%2Fexim.git diff --git a/src/src/host.c b/src/src/host.c index d84347cb1..a31c09b65 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; @@ -1232,14 +1232,11 @@ BOOL host_is_tls_on_connect_port(int port) { int sep = 0; -uschar buffer[32]; -const uschar *list = tls_in.on_connect_ports; -uschar *s; -uschar *end; +const uschar * list = tls_in.on_connect_ports; if (tls_in.on_connect) return TRUE; -while ((s = string_nextinlist(&list, &sep, buffer, sizeof(buffer)))) +for (uschar * s, * end; s = string_nextinlist(&list, &sep, NULL, 0); ) if (Ustrtol(s, &end, 10) == port) return TRUE; @@ -1503,9 +1500,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 +1543,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 +1643,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 +1668,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 @@ -1948,8 +1943,13 @@ host_find_byname(host_item *host, const uschar *ignore_target_hosts, int flags, int yield, times; host_item *last = NULL; BOOL temp_error = FALSE; -#if HAVE_IPV6 int af; + +#ifndef DISABLE_TLS +/* Copy the host name at this point to the value which is used for +TLS certificate name checking, before anything modifies it. */ + +host->certname = host->name; #endif /* Make sure DNS options are set as required. This appears to be necessary in @@ -1969,10 +1969,10 @@ lookups here (except when testing standalone). */ #ifdef STAND_ALONE if (disable_ipv6) #else - if (disable_ipv6 || - (dns_ipv4_lookup != NULL && - match_isinlist(host->name, CUSS &dns_ipv4_lookup, 0, NULL, NULL, - MCL_DOMAIN, TRUE, NULL) == OK)) + if ( disable_ipv6 + || dns_ipv4_lookup + && match_isinlist(host->name, CUSS &dns_ipv4_lookup, 0, NULL, NULL, + MCL_DOMAIN, TRUE, NULL) == OK) #endif { af = AF_INET; times = 1; } @@ -1982,7 +1982,7 @@ lookups here (except when testing standalone). */ /* No IPv6 support */ #else /* HAVE_IPV6 */ - times = 1; + af = AF_INET; times = 1; #endif /* HAVE_IPV6 */ /* Initialize the flag that gets set for DNS syntax check errors, so that the @@ -2024,7 +2024,7 @@ for (int i = 1; i <= times; #else /* not HAVE_IPV6 */ if (f.running_in_test_harness) - hostdata = host_fake_gethostbyname(host->name, AF_INET, &error_num); + hostdata = host_fake_gethostbyname(host->name, af, &error_num); else { hostdata = gethostbyname(CS host->name); @@ -2034,47 +2034,46 @@ 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; + 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; - #if NO_DATA != NO_ADDRESS - case NO_ADDRESS: error = US"NO_ADDRESS"; break; - #endif + case HOST_NOT_FOUND: error = US"HOST_NOT_FOUND"; break; + case TRY_AGAIN: error = US"TRY_AGAIN"; temp_error = TRUE; break; + case NO_RECOVERY: error = US"NO_RECOVERY"; temp_error = TRUE; break; + case NO_DATA: error = US"NO_DATA"; break; + #if NO_DATA != NO_ADDRESS + case NO_ADDRESS: error = US"NO_ADDRESS"; break; + #endif default: error = US"?"; break; } - DEBUG(D_host_lookup) debug_printf("%s returned %d (%s)\n", - #if HAVE_IPV6 - #if HAVE_GETIPNODEBYNAME - (af == AF_INET6)? "getipnodebyname(af=inet6)" : "getipnodebyname(af=inet)", - #else - (af == AF_INET6)? "gethostbyname2(af=inet6)" : "gethostbyname2(af=inet)", - #endif - #else - "gethostbyname", - #endif - error_num, error); + DEBUG(D_host_lookup) debug_printf("%s(af=%s) returned %d (%s)\n", + f.running_in_test_harness ? "host_fake_gethostbyname" : +#if HAVE_IPV6 +# if HAVE_GETIPNODEBYNAME + "getipnodebyname", +# else + "gethostbyname2", +# endif +#else + "gethostbyname", +#endif + af == AF_INET ? "inet" : "inet6", error_num, error); - if (error_num == TRY_AGAIN || error_num == NO_RECOVERY) temp_error = TRUE; continue; } - if ((hostdata->h_addr_list)[0] == NULL) continue; + if (!(hostdata->h_addr_list)[0]) continue; /* Replace the name with the fully qualified one if necessary, and fill in the fully_qualified_name pointer. */ - if (hostdata->h_name[0] != 0 && - Ustrcmp(host->name, hostdata->h_name) != 0) + if (hostdata->h_name[0] && Ustrcmp(host->name, hostdata->h_name) != 0) host->name = string_copy_dnsdomain(US hostdata->h_name); - if (fully_qualified_name != NULL) *fully_qualified_name = host->name; + if (fully_qualified_name) *fully_qualified_name = host->name; /* Get the list of addresses. IPv4 and IPv6 addresses can be distinguished by their different lengths. Scan the list, ignoring any that are to be @@ -2088,9 +2087,9 @@ for (int i = 1; i <= times; host_ntoa(ipv4_addr? AF_INET:AF_INET6, *addrlist, NULL, NULL); #ifndef STAND_ALONE - if (ignore_target_hosts != NULL && - verify_check_this_host(&ignore_target_hosts, NULL, host->name, - text_address, NULL) == OK) + if ( ignore_target_hosts + && verify_check_this_host(&ignore_target_hosts, NULL, host->name, + text_address, NULL) == OK) { DEBUG(D_host_lookup) debug_printf("ignored host %s [%s]\n", host->name, text_address); @@ -2098,10 +2097,10 @@ for (int i = 1; i <= times; } #endif - /* If this is the first address, last == NULL and we put the data in the + /* If this is the first address, last is NULL and we put the data in the original block. */ - if (last == NULL) + if (!last) { host->address = text_address; host->port = PORT_NONE; @@ -2118,6 +2117,9 @@ for (int i = 1; i <= times; { host_item *next = store_get(sizeof(host_item), FALSE); next->name = host->name; +#ifndef DISABLE_TLS + next->certname = host->certname; +#endif next->mx = host->mx; next->address = text_address; next->port = PORT_NONE; @@ -2136,12 +2138,12 @@ for (int i = 1; i <= times; NULL. If temp_error is set, at least one of the lookups gave a temporary error, so we pass that back. */ -if (host->address == NULL) +if (!host->address) { uschar *msg = #ifndef STAND_ALONE - (message_id[0] == 0 && smtp_in != NULL)? - string_sprintf("no IP address found for host %s (during %s)", host->name, + !message_id[0] && smtp_in + ? string_sprintf("no IP address found for host %s (during %s)", host->name, smtp_get_connection_info()) : #endif string_sprintf("no IP address found for host %s", host->name); @@ -2261,6 +2263,13 @@ BOOL v6_find_again = FALSE; BOOL dnssec_fail = FALSE; int i; +#ifndef DISABLE_TLS +/* Copy the host name at this point to the value which is used for +TLS certificate name checking, before any CNAME-following modifies it. */ + +host->certname = host->name; +#endif + /* If allow_ip is set, a name which is an IP address returns that value as its address. This is used for MX records when allow_mx_to_ip is set, for those sites that feel they have to flaunt the RFC rules. */ @@ -2650,7 +2659,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 +3165,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 %s %sDNSSEC\n", dns_rc_names[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 *