* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2016 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or
count++;
yield = store_get(sizeof(struct hostent));
- alist = store_get((count + 1) * sizeof(char **));
+ alist = store_get((count + 1) * sizeof(char *));
adds = store_get(count *alen);
yield->h_name = CS name;
/* If HELO/EHLO was followed by an IP literal, it's messy because of two
features of IPv6. Firstly, there's the "IPv6:" prefix (Exim is liberal and
doesn't require this, for historical reasons). Secondly, IPv6 addresses may not
-be given in canonical form, so we have to canonicize them before comparing. As
+be given in canonical form, so we have to canonicalize them before comparing. As
it happens, the code works for both IPv4 and IPv6. */
else if (sender_helo_name[0] == '[' &&
sender_fullhost = (sender_helo_name == NULL)? address :
string_sprintf("(%s) %s", sender_helo_name, address);
- sender_rcvhost = string_cat(NULL, &size, &ptr, address, adlen);
+ sender_rcvhost = string_catn(NULL, &size, &ptr, address, adlen);
if (sender_ident != NULL || show_helo || portptr != NULL)
{
int firstptr;
- sender_rcvhost = string_cat(sender_rcvhost, &size, &ptr, US" (", 2);
+ sender_rcvhost = string_catn(sender_rcvhost, &size, &ptr, US" (", 2);
firstptr = ptr;
if (portptr != NULL)
sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2,
(firstptr == ptr)? US"ident=" : US" ident=", sender_ident);
- sender_rcvhost = string_cat(sender_rcvhost, &size, &ptr, US")", 1);
+ sender_rcvhost = string_catn(sender_rcvhost, &size, &ptr, US")", 1);
}
sender_rcvhost[ptr] = 0; /* string_cat() always leaves room */
/* Handle IPv4 address */
(void)sscanf(CS address, "%d.%d.%d.%d", x, x+1, x+2, x+3);
-bin[v4offset] = (x[0] << 24) + (x[1] << 16) + (x[2] << 8) + x[3];
+bin[v4offset] = ((uint)x[0] << 24) + (x[1] << 16) + (x[2] << 8) + x[3];
return v4offset+1;
}
if (mask == 0) wordmask = 0;
else if (mask < 32)
{
- wordmask = (-1) << (32 - mask);
+ wordmask = (uint)(-1) << (32 - mask);
mask = 0;
}
else
if (mlen == 0) mask = 0;
else if (mlen < 32)
{
- mask = (-1) << (32 - mlen);
+ mask = (uint)(-1) << (32 - mlen);
mlen = 0;
}
else
uschar *s, *t;
struct hostent *hosts;
struct in_addr addr;
-unsigned long time_msec;
+unsigned long time_msec = 0; /* init to quieten dumb static analysis */
if (slow_lookup_log) time_msec = get_time_in_ms();
FAIL if no host name can be found
DEFER if a temporary error was encountered
-The variable host_lookup_msg is set to an empty string on sucess, or to a
+The variable host_lookup_msg is set to an empty string on success, or to a
reason for the failure otherwise, in a form suitable for tagging onto an error
message, and also host_lookup_failed is set TRUE if the lookup failed. If there
was a defer, host_lookup_deferred is set TRUE.
save_hostname = sender_host_name; /* Save for error messages */
aliases = sender_host_aliases;
-for (hname = sender_host_name; hname != NULL; hname = *aliases++)
+for (hname = sender_host_name; hname; hname = *aliases++)
{
int rc;
BOOL ok = FALSE;
h.dnssec == DS_YES ? "DNSSEC verified (AD)" : "unverified");
if (h.dnssec != DS_YES) sender_host_dnssec = FALSE;
- for (hh = &h; hh != NULL; hh = hh->next)
+ for (hh = &h; hh; hh = hh->next)
if (host_is_in_net(hh->address, sender_host_address, 0))
{
HDEBUG(D_host_lookup) debug_printf(" %s OK\n", hh->address);
Returns: HOST_FIND_FAILED couldn't find A record
HOST_FIND_AGAIN try again later
+ HOST_FIND_SECURITY dnssec required but not acheived
HOST_FOUND found AAAA and/or A record(s)
HOST_IGNORED found, but all IPs ignored
*/
dns_record *rr;
host_item *thishostlast = NULL; /* Indicates not yet filled in anything */
BOOL v6_find_again = FALSE;
+BOOL dnssec_fail = FALSE;
int i;
/* If allow_ip is set, a name which is an IP address returns that value
{
if (dnssec_require)
{
- log_write(L_host_lookup_failed, LOG_MAIN,
- "dnssec fail on %s for %.256s",
+ dnssec_fail = TRUE;
+ DEBUG(D_host_lookup) debug_printf("dnssec fail on %s for %.256s",
i>0 ? "AAAA" : "A", host->name);
continue;
}
}
}
-/* Control gets here only if the econdookup (the A record) succeeded.
+/* Control gets here only if the second lookup (the A record) succeeded.
However, the address may not be filled in if it was ignored. */
-return host->address ? HOST_FOUND : HOST_IGNORED;
+return host->address
+ ? HOST_FOUND
+ : dnssec_fail
+ ? HOST_FIND_SECURITY
+ : HOST_IGNORED;
}
if there was a syntax error,
host_find_failed_syntax is set.
HOST_FIND_AGAIN Could not resolve at this time
+ HOST_FIND_SECURITY dnsssec required but not acheived
HOST_FOUND Host found
HOST_FOUND_LOCAL The lowest MX record points to this
machine, if MX records were found, or
records. On DNS failures, we give the "try again" error unless the domain is
listed as one for which we continue. */
-if (rc != DNS_SUCCEED && (whichrrs & HOST_FIND_BY_MX) != 0)
+if (rc != DNS_SUCCEED && whichrrs & HOST_FIND_BY_MX)
{
ind_type = T_MX;
dnssec = DS_UNK;
rc = dns_lookup_timerwrap(&dnsa, host->name, ind_type, fully_qualified_name);
DEBUG(D_dns)
- if ((dnssec_request || dnssec_require)
- & !dns_is_secure(&dnsa)
- & dns_is_aa(&dnsa))
+ if ( (dnssec_request || dnssec_require)
+ && !dns_is_secure(&dnsa)
+ && dns_is_aa(&dnsa))
debug_printf("DNS lookup of %.256s (MX) requested AD, but got AA\n", host->name);
if (dnssec_request)
- {
if (dns_is_secure(&dnsa))
{
DEBUG(D_host_lookup) debug_printf("%s MX DNSSEC\n", host->name);
{
dnssec = DS_NO; lookup_dnssec_authenticated = US"no";
}
- }
switch (rc)
{
case DNS_SUCCEED:
if (!dnssec_require || dns_is_secure(&dnsa))
break;
- log_write(L_host_lookup_failed, LOG_MAIN,
- "dnssec fail on MX for %.256s", host->name);
+ DEBUG(D_host_lookup)
+ debug_printf("dnssec fail on MX for %.256s", host->name);
+#ifndef STAND_ALONE
+ if (match_isinlist(host->name, CUSS &mx_fail_domains, 0, NULL, NULL,
+ MCL_DOMAIN, TRUE, NULL) != OK)
+ { yield = HOST_FIND_SECURITY; goto out; }
+#endif
rc = DNS_FAIL;
/*FALLTHROUGH*/
case DNS_FAIL:
case DNS_AGAIN:
- #ifndef STAND_ALONE
+#ifndef STAND_ALONE
if (match_isinlist(host->name, CUSS &mx_fail_domains, 0, NULL, NULL,
MCL_DOMAIN, TRUE, NULL) != OK)
- #endif
+#endif
{ yield = HOST_FIND_AGAIN; goto out; }
DEBUG(D_host_lookup) debug_printf("DNS_%s treated as DNS_NODATA "
"(domain in mx_fail_domains)\n", (rc == DNS_FAIL)? "FAIL":"AGAIN");
last = NULL; /* Indicates that not even the first item is filled yet */
for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
- rr != NULL;
- rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+ rr;
+ rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == ind_type)
{
int precedence;
int weight = 0; /* For SRV records */
int port = PORT_NONE;
- uschar *s; /* MUST be unsigned for GETSHORT */
+ const uschar * s = rr->data; /* MUST be unsigned for GETSHORT */
uschar data[256];
- if (rr->type != ind_type) continue;
- s = rr->data;
GETSHORT(precedence, s); /* Pointer s is advanced */
/* For MX records, we use a random "weight" which causes multiple records of
NEXT_MX_RR: continue;
}
+if (!last) /* No rr of correct type; give up */
+ {
+ yield = HOST_FIND_FAILED;
+ goto out;
+ }
+
/* If the list of hosts was obtained from SRV records, there are two things to
do. First, if there is only one host, and it's name is ".", it means there is
no SMTP service at this domain. Otherwise, we have to sort the hosts of equal
debug_printf(" %s P=%d W=%d\n", h->name, h->mx, h->sort_key % 1000);
}
- for (pptr = &host, h = host; h != last; pptr = &(h->next), h = h->next)
+ for (pptr = &host, h = host; h != last; pptr = &h->next, h = h->next)
{
int sum = 0;
host_item *hh;
for (h = host; h != last->next; h = h->next)
{
- if (h->address != NULL) continue; /* Inserted by a multihomed host */
+ if (h->address) continue; /* Inserted by a multihomed host */
+
rc = set_address_from_dns(h, &last, ignore_target_hosts, allow_mx_to_ip,
NULL, dnssec_request, dnssec_require);
if (rc != HOST_FOUND)
{
h->status = hstatus_unusable;
- if (rc == HOST_FIND_AGAIN)
+ switch (rc)
{
- yield = rc;
- h->why = hwhy_deferred;
+ case HOST_FIND_AGAIN:
+ yield = rc; h->why = hwhy_deferred; break;
+ case HOST_FIND_SECURITY:
+ yield = rc; h->why = hwhy_insecure; break;
+ case HOST_IGNORED:
+ h->why = hwhy_ignored; break;
+ default:
+ h->why = hwhy_failed; break;
}
- else
- h->why = (rc == HOST_IGNORED)? hwhy_ignored : hwhy_failed;
}
}
exist. If we end up with just a single, ignored host, flatten its fields as if
nothing was found. */
-if (ignore_target_hosts != NULL)
+if (ignore_target_hosts)
{
host_item *prev = NULL;
for (h = host; h != last->next; h = h->next)
addresses of a multihomed host, but that should not matter. */
#if HAVE_IPV6
-if (h != last && !disable_ipv6)
+if (h != last && !disable_ipv6) for (h = host; h != last; h = h->next)
{
- for (h = host; h != last; h = h->next)
- {
- host_item temp;
- host_item *next = h->next;
- if (h->mx != next->mx || /* If next is different MX */
- h->address == NULL || /* OR this one is unset */
- Ustrchr(h->address, ':') != NULL || /* OR this one is IPv6 */
- (next->address != NULL &&
- Ustrchr(next->address, ':') == NULL)) /* OR next is IPv4 */
- continue; /* move on to next */
- temp = *h; /* otherwise, swap */
- temp.next = next->next;
- *h = *next;
- h->next = next;
- *next = temp;
- }
+ host_item temp;
+ host_item *next = h->next;
+
+ if (h->mx != next->mx || /* If next is different MX */
+ h->address == NULL || /* OR this one is unset */
+ Ustrchr(h->address, ':') != NULL || /* OR this one is IPv6 */
+ (next->address != NULL &&
+ Ustrchr(next->address, ':') == NULL)) /* OR next is IPv4 */
+ continue; /* move on to next */
+ temp = *h; /* otherwise, swap */
+ temp.next = next->next;
+ *h = *next;
+ h->next = next;
+ *next = temp;
}
#endif
debug_printf("host_find_bydns yield = %s (%d); returned hosts:\n",
(yield == HOST_FOUND)? "HOST_FOUND" :
(yield == HOST_FOUND_LOCAL)? "HOST_FOUND_LOCAL" :
+ (yield == HOST_FIND_SECURITY)? "HOST_FIND_SECURITY" :
(yield == HOST_FIND_AGAIN)? "HOST_FIND_AGAIN" :
(yield == HOST_FIND_FAILED)? "HOST_FIND_FAILED" : "?",
yield);
else if (Ustrcmp(buffer, "request_dnssec") == 0) request_dnssec = TRUE;
else if (Ustrcmp(buffer, "no_request_dnssec") == 0) request_dnssec = FALSE;
else if (Ustrcmp(buffer, "require_dnssec") == 0) require_dnssec = TRUE;
- else if (Ustrcmp(buffer, "no_reqiret_dnssec") == 0) require_dnssec = FALSE;
+ else if (Ustrcmp(buffer, "no_require_dnssec") == 0) require_dnssec = FALSE;
else if (Ustrcmp(buffer, "test_harness") == 0)
running_in_test_harness = !running_in_test_harness;
else if (Ustrcmp(buffer, "ipv6") == 0) disable_ipv6 = !disable_ipv6;
: host_find_bydns(&h, NULL, flags, US"smtp", NULL, NULL,
&d, &fully_qualified_name, NULL);
- if (rc == HOST_FIND_FAILED) printf("Failed\n");
- else if (rc == HOST_FIND_AGAIN) printf("Again\n");
- else if (rc == HOST_FOUND_LOCAL) printf("Local\n");
+ switch (rc)
+ {
+ case HOST_FIND_FAILED: printf("Failed\n"); break;
+ case HOST_FIND_AGAIN: printf("Again\n"); break;
+ case HOST_FIND_SECURITY: printf("Security\n"); break;
+ case HOST_FOUND_LOCAL: printf("Local\n"); break;
+ }
}
printf("\n> ");