* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2016 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for finding hosts, either by gethostbyname(), gethostbyaddr(), or
return 0;
if (random_seed == 0)
{
- if (running_in_test_harness) random_seed = 42; else
+ if (f.running_in_test_harness) random_seed = 42; else
{
int p = (int)getpid();
random_seed = (int)time(NULL) ^ ((p << 16) | p);
struct hostent *yield;
dns_answer dnsa;
dns_scan dnss;
-dns_record *rr;
DEBUG(D_host_lookup)
debug_printf("using host_fake_gethostbyname for %s (%s)\n", name,
/* Handle a literal IP address */
-ipa = string_is_ip_address(lname, NULL);
-if (ipa != 0)
+if ((ipa = string_is_ip_address(lname, NULL)) != 0)
{
if ((ipa == 4 && af == AF_INET) ||
(ipa == 6 && af == AF_INET6))
{
- int i, n;
int x[4];
yield = store_get(sizeof(struct hostent));
alist = store_get(2 * sizeof(char *));
yield->h_length = alen;
yield->h_addr_list = CSS alist;
*alist++ = adds;
- n = host_aton(lname, x);
- for (i = 0; i < n; i++)
+ for (int n = host_aton(lname, x), i = 0; i < n; i++)
{
int y = x[i];
*adds++ = (y >> 24) & 255;
case DNS_FAIL: *error_num = NO_RECOVERY; return NULL;
}
- for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+ for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
rr;
- rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
- if (rr->type == type)
- count++;
+ rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == type)
+ count++;
yield = store_get(sizeof(struct hostent));
alist = store_get((count + 1) * sizeof(char *));
yield->h_length = alen;
yield->h_addr_list = CSS alist;
- for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+ for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
rr;
- rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+ rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == type)
{
- int i, n;
int x[4];
dns_address *da;
- if (rr->type != type) continue;
if (!(da = dns_address_from_rr(&dnsa, rr))) break;
*alist++ = adds;
- n = host_aton(da->address, x);
- for (i = 0; i < n; i++)
+ for (int n = host_aton(da->address, x), i = 0; i < n; i++)
{
int y = x[i];
*adds++ = (y >> 24) & 255;
int fake_mx = MX_NONE; /* This value is actually -1 */
uschar *name;
-if (list == NULL) return;
+if (!list) return;
if (randomize) fake_mx--; /* Start at -2 for randomizing */
*anchor = NULL;
-while ((name = string_nextinlist(&list, &sep, NULL, 0)) != NULL)
+while ((name = string_nextinlist(&list, &sep, NULL, 0)))
{
host_item *h;
h->why = hwhy_unknown;
h->last_try = 0;
- if (*anchor == NULL)
+ if (!*anchor)
{
h->next = NULL;
*anchor = h;
}
else
{
- while (hh->next != NULL && h->sort_key >= (hh->next)->sort_key)
+ while (hh->next && h->sort_key >= hh->next->sort_key)
hh = hh->next;
h->next = hh->next;
hh->next = h;
first place.
Because this data may survive over more than one incoming SMTP message, it has
-to be in permanent store.
+to be in permanent store. However, STARTTLS has to be forgotten and redone
+on a multi-message conn, so this will be called once per message then. Hence
+we use malloc, so we can free.
Arguments: none
Returns: nothing
host_build_sender_fullhost(void)
{
BOOL show_helo = TRUE;
-uschar *address;
+uschar * address, * fullhost, * rcvhost, * reset_point;
int len;
-int old_pool = store_pool;
-if (sender_host_address == NULL) return;
+if (!sender_host_address) return;
-store_pool = POOL_PERM;
+reset_point = store_get(0);
/* Set up address, with or without the port. After discussion, it seems that
the only format that doesn't cause trouble is [aaaa]:pppp. However, we can't
/* If there's no EHLO/HELO data, we can't show it. */
-if (sender_helo_name == NULL) show_helo = FALSE;
+if (!sender_helo_name) show_helo = FALSE;
/* 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
/* Host name is not verified */
-if (sender_host_name == NULL)
+if (!sender_host_name)
{
uschar *portptr = Ustrstr(address, "]:");
- int size = 0;
- int ptr = 0;
+ gstring * g;
int adlen; /* Sun compiler doesn't like ++ in initializers */
- adlen = (portptr == NULL)? Ustrlen(address) : (++portptr - address);
- sender_fullhost = (sender_helo_name == NULL)? address :
- string_sprintf("(%s) %s", sender_helo_name, address);
+ adlen = portptr ? (++portptr - address) : Ustrlen(address);
+ fullhost = sender_helo_name
+ ? string_sprintf("(%s) %s", sender_helo_name, address)
+ : address;
- sender_rcvhost = string_catn(NULL, &size, &ptr, address, adlen);
+ g = string_catn(NULL, address, adlen);
- if (sender_ident != NULL || show_helo || portptr != NULL)
+ if (sender_ident || show_helo || portptr)
{
int firstptr;
- sender_rcvhost = string_catn(sender_rcvhost, &size, &ptr, US" (", 2);
- firstptr = ptr;
+ g = string_catn(g, US" (", 2);
+ firstptr = g->ptr;
- if (portptr != NULL)
- sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2, US"port=",
- portptr + 1);
+ if (portptr)
+ g = string_append(g, 2, US"port=", portptr + 1);
if (show_helo)
- sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2,
- (firstptr == ptr)? US"helo=" : US" helo=", sender_helo_name);
+ g = string_append(g, 2,
+ firstptr == g->ptr ? US"helo=" : US" helo=", sender_helo_name);
- if (sender_ident != NULL)
- sender_rcvhost = string_append(sender_rcvhost, &size, &ptr, 2,
- (firstptr == ptr)? US"ident=" : US" ident=", sender_ident);
+ if (sender_ident)
+ g = string_append(g, 2,
+ firstptr == g->ptr ? US"ident=" : US" ident=", sender_ident);
- sender_rcvhost = string_catn(sender_rcvhost, &size, &ptr, US")", 1);
+ g = string_catn(g, US")", 1);
}
- sender_rcvhost[ptr] = 0; /* string_cat() always leaves room */
-
- /* Release store, because string_cat allocated a minimum of 100 bytes that
- are rarely completely used. */
-
- store_reset(sender_rcvhost + ptr + 1);
+ rcvhost = string_from_gstring(g);
}
/* Host name is known and verified. Unless we've already found that the HELO
if (show_helo)
{
- sender_fullhost = string_sprintf("%s (%s) %s", sender_host_name,
+ fullhost = string_sprintf("%s (%s) %s", sender_host_name,
sender_helo_name, address);
- sender_rcvhost = (sender_ident == NULL)?
- string_sprintf("%s (%s helo=%s)", sender_host_name,
- address, sender_helo_name) :
- string_sprintf("%s\n\t(%s helo=%s ident=%s)", sender_host_name,
- address, sender_helo_name, sender_ident);
+ rcvhost = sender_ident
+ ? string_sprintf("%s\n\t(%s helo=%s ident=%s)", sender_host_name,
+ address, sender_helo_name, sender_ident)
+ : string_sprintf("%s (%s helo=%s)", sender_host_name,
+ address, sender_helo_name);
}
else
{
- sender_fullhost = string_sprintf("%s %s", sender_host_name, address);
- sender_rcvhost = (sender_ident == NULL)?
- string_sprintf("%s (%s)", sender_host_name, address) :
- string_sprintf("%s (%s ident=%s)", sender_host_name, address,
- sender_ident);
+ fullhost = string_sprintf("%s %s", sender_host_name, address);
+ rcvhost = sender_ident
+ ? string_sprintf("%s (%s ident=%s)", sender_host_name, address,
+ sender_ident)
+ : string_sprintf("%s (%s)", sender_host_name, address);
}
}
-store_pool = old_pool;
+if (sender_fullhost) store_free(sender_fullhost);
+sender_fullhost = string_copy_malloc(fullhost);
+if (sender_rcvhost) store_free(sender_rcvhost);
+sender_rcvhost = string_copy_malloc(rcvhost);
+
+store_reset(reset_point);
DEBUG(D_host_lookup) debug_printf("sender_fullhost = %s\n", sender_fullhost);
DEBUG(D_host_lookup) debug_printf("sender_rcvhost = %s\n", sender_rcvhost);
uschar *
host_and_ident(BOOL useflag)
{
-if (sender_fullhost == NULL)
- {
- (void)string_format(big_buffer, big_buffer_size, "%s%s", useflag? "U=" : "",
- (sender_ident == NULL)? US"unknown" : sender_ident);
- }
+if (!sender_fullhost)
+ (void)string_format(big_buffer, big_buffer_size, "%s%s", useflag ? "U=" : "",
+ sender_ident ? sender_ident : US"unknown");
else
{
- uschar *flag = useflag? US"H=" : US"";
- uschar *iface = US"";
- if (LOGGING(incoming_interface) && interface_address != NULL)
+ uschar * flag = useflag ? US"H=" : US"";
+ uschar * iface = US"";
+ if (LOGGING(incoming_interface) && interface_address)
iface = string_sprintf(" I=[%s]:%d", interface_address, interface_port);
- if (sender_ident == NULL)
- (void)string_format(big_buffer, big_buffer_size, "%s%s%s",
- flag, sender_fullhost, iface);
- else
+ if (sender_ident)
(void)string_format(big_buffer, big_buffer_size, "%s%s%s U=%s",
flag, sender_fullhost, iface, sender_ident);
+ else
+ (void)string_format(big_buffer, big_buffer_size, "%s%s%s",
+ flag, sender_fullhost, iface);
}
return big_buffer;
}
add_unique_interface(ip_address_item *list, ip_address_item *ipa)
{
ip_address_item *ipa2;
-for (ipa2 = list; ipa2 != NULL; ipa2 = ipa2->next)
+for (ipa2 = list; ipa2; ipa2 = ipa2->next)
if (Ustrcmp(ipa2->address, ipa->address) == 0) return list;
ipa2 = store_get_perm(sizeof(ip_address_item));
*ipa2 = *ipa;
US"extra_local_interfaces");
ip_address_item *ipa;
- if (dlist == NULL) dlist = xlist; else
+ if (!dlist) dlist = xlist;
+ else
{
- for (ipa = dlist; ipa->next != NULL; ipa = ipa->next);
+ for (ipa = dlist; ipa->next; ipa = ipa->next) ;
ipa->next = xlist;
}
- for (ipa = dlist; ipa != NULL; ipa = ipa->next)
+ for (ipa = dlist; ipa; ipa = ipa->next)
{
if (Ustrcmp(ipa->address, "0.0.0.0") == 0 ||
Ustrcmp(ipa->address, "::0") == 0)
{
- ip_address_item *ipa2;
BOOL ipv6 = ipa->address[0] == ':';
- if (running_interfaces == NULL)
+ if (!running_interfaces)
running_interfaces = os_find_running_interfaces();
- for (ipa2 = running_interfaces; ipa2 != NULL; ipa2 = ipa2->next)
- {
+ for (ip_address_item * ipa2 = running_interfaces; ipa2; ipa2 = ipa2->next)
if ((Ustrchr(ipa2->address, ':') != NULL) == ipv6)
local_interface_data = add_unique_interface(local_interface_data,
- ipa2);
- }
+ ipa2);
}
else
{
if (family == AF_INET6)
{
struct sockaddr_in6 *sk = (struct sockaddr_in6 *)arg;
- yield = (uschar *)inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
+ yield = US inet_ntop(family, &(sk->sin6_addr), CS addr_buffer,
sizeof(addr_buffer));
if (portptr != NULL) *portptr = ntohs(sk->sin6_port);
}
else
{
struct sockaddr_in *sk = (struct sockaddr_in *)arg;
- yield = (uschar *)inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
+ yield = US inet_ntop(family, &(sk->sin_addr), CS addr_buffer,
sizeof(addr_buffer));
if (portptr != NULL) *portptr = ntohs(sk->sin_port);
}
}
else
{
- yield = (uschar *)inet_ntop(type, arg, CS addr_buffer, sizeof(addr_buffer));
+ yield = US inet_ntop(type, arg, CS addr_buffer, sizeof(addr_buffer));
}
/* If the result is a mapped IPv4 address, show it in V4 format. */
void
host_mask(int count, int *binary, int mask)
{
-int i;
if (mask < 0) mask = 99999;
-for (i = 0; i < count; i++)
+for (int i = 0; i < count; i++)
{
int wordmask;
if (mask == 0) wordmask = 0;
int
host_nmtoa(int count, int *binary, int mask, uschar *buffer, int sep)
{
-int i, j;
+int j;
uschar *tt = buffer;
if (count == 1)
{
j = binary[0];
- for (i = 24; i >= 0; i -= 8)
+ for (int i = 24; i >= 0; i -= 8)
tt += sprintf(CS tt, "%d.", (j >> i) & 255);
}
else
- for (i = 0; i < 4; i++)
+ for (int i = 0; i < 4; i++)
{
j = binary[i];
tt += sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep);
BOOL
host_is_in_net(const uschar *host, const uschar *net, int maskoffset)
{
-int i;
int address[4];
int incoming[4];
int mlen;
/* Else do the masked comparison. */
-for (i = 0; i < size; i++)
+for (int i = 0; i < size; i++)
{
int mask;
if (mlen == 0) mask = 0;
if (h->address != NULL)
{
- ip_address_item *ip;
if (Ustrcmp(h->address, "0.0.0.0") == 0) goto FOUND_LOCAL;
- for (ip = local_interface_data; ip != NULL; ip = ip->next)
+ for (ip_address_item * ip = local_interface_data; ip; ip = ip->next)
if (Ustrcmp(h->address, ip->address) == 0) goto FOUND_LOCAL;
yield = HOST_FOUND; /* At least one remote address has been found */
}
/* Copy and lowercase the name, which is in static storage in many systems.
Put it in permanent memory. */
-s = (uschar *)hosts->h_name;
+s = US hosts->h_name;
len = Ustrlen(s) + 1;
t = sender_host_name = store_get_perm(len);
while (*s != 0) *t++ = tolower(*s++);
/* If the host has aliases, build a copy of the alias list */
-if (hosts->h_aliases != NULL)
+if (hosts->h_aliases)
{
int count = 1;
- uschar **aliases, **ptr;
- for (aliases = USS hosts->h_aliases; *aliases != NULL; aliases++) count++;
+ uschar **ptr;
+ for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++) count++;
ptr = sender_host_aliases = store_get_perm(count * sizeof(uschar *));
- for (aliases = USS hosts->h_aliases; *aliases != NULL; aliases++)
+ for (uschar ** aliases = USS hosts->h_aliases; *aliases; aliases++)
{
uschar *s = *aliases;
int len = Ustrlen(s) + 1;
{
int old_pool, rc;
int sep = 0;
-uschar *hname, *save_hostname;
+uschar *save_hostname;
uschar **aliases;
uschar buffer[256];
uschar *ordername;
const uschar *list = host_lookup_order;
-dns_record *rr;
dns_answer dnsa;
dns_scan dnss;
/* For testing the case when a lookup does not complete, we have a special
reserved IP address. */
-if (running_in_test_harness &&
+if (f.running_in_test_harness &&
Ustrcmp(sender_host_address, "99.99.99.99") == 0)
{
HDEBUG(D_host_lookup)
store_pool = POOL_PERM; /* Save names in permanent storage */
- for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+ for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
rr;
- rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
- if (rr->type == T_PTR)
- count++;
+ rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR)
+ count++;
/* Get store for the list of aliases. For compatibility with
gethostbyaddr, we make an empty list if there are none. */
/* Re-scan and extract the names */
- for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+ for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
rr;
- rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+ rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == T_PTR)
{
- uschar *s = NULL;
- if (rr->type != T_PTR) continue;
- s = store_get(ssize);
+ uschar * s = store_get(ssize);
/* If an overlong response was received, the data will have been
truncated and dn_expand may fail. */
if (dn_expand(dnsa.answer, dnsa.answer + dnsa.answerlen,
- (uschar *)(rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0)
+ US (rr->data), (DN_EXPAND_ARG4_TYPE)(s), ssize) < 0)
{
log_write(0, LOG_MAIN, "host name alias list truncated for %s",
sender_host_address);
/* If we have failed to find a name, return FAIL and log when required.
NB host_lookup_msg must be in permanent store. */
-if (sender_host_name == NULL)
+if (!sender_host_name)
{
- if (host_checking || !log_testing_mode)
+ if (host_checking || !f.log_testing_mode)
log_write(L_host_lookup_failed, LOG_MAIN, "no host name found for IP "
"address %s", sender_host_address);
host_lookup_msg = US" (failed to find host name from IP address)";
save_hostname = sender_host_name; /* Save for error messages */
aliases = sender_host_aliases;
-for (hname = sender_host_name; hname; hname = *aliases++)
+for (uschar * hname = sender_host_name; hname; hname = *aliases++)
{
int rc;
BOOL ok = FALSE;
- host_item h;
- dnssec_domains d;
+ host_item h = { .next = NULL, .name = hname, .mx = MX_NONE, .address = NULL };
+ dnssec_domains d =
+ { .request = sender_host_dnssec ? US"*" : NULL, .require = NULL };
- h.next = NULL;
- h.name = hname;
- h.mx = MX_NONE;
- h.address = NULL;
- d.request = sender_host_dnssec ? US"*" : NULL;;
- d.require = NULL;
-
- if ( (rc = host_find_bydns(&h, NULL, HOST_FIND_BY_A,
+ if ( (rc = host_find_bydns(&h, NULL, HOST_FIND_BY_A | HOST_FIND_BY_AAAA,
NULL, NULL, NULL, &d, NULL, NULL)) == HOST_FOUND
|| rc == HOST_FOUND_LOCAL
)
{
- host_item *hh;
HDEBUG(D_host_lookup) debug_printf("checking addresses for %s\n", hname);
/* If the forward lookup was not secure we cancel the is-secure variable */
h.dnssec == DS_YES ? "DNSSEC verified (AD)" : "unverified");
if (h.dnssec != DS_YES) sender_host_dnssec = FALSE;
- for (hh = &h; hh; hh = hh->next)
+ for (host_item * 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);
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;
+int yield, times;
host_item *last = NULL;
BOOL temp_error = FALSE;
#if HAVE_IPV6
/* Initialize the flag that gets set for DNS syntax check errors, so that the
interface to this function can be similar to host_find_bydns. */
-host_find_failed_syntax = FALSE;
+f.host_find_failed_syntax = FALSE;
/* Loop to look up both kinds of address in an IPv6 world */
-for (i = 1; i <= times;
+for (int i = 1; i <= times;
#if HAVE_IPV6
af = AF_INET, /* If 2 passes, IPv4 on the second */
#endif
if (slow_lookup_log) time_msec = get_time_in_ms();
#if HAVE_IPV6
- if (running_in_test_harness)
+ if (f.running_in_test_harness)
hostdata = host_fake_gethostbyname(host->name, af, &error_num);
else
{
}
#else /* not HAVE_IPV6 */
- if (running_in_test_harness)
+ if (f.running_in_test_harness)
hostdata = host_fake_gethostbyname(host->name, AF_INET, &error_num);
else
{
if (hostdata->h_name[0] != 0 &&
Ustrcmp(host->name, hostdata->h_name) != 0)
- host->name = string_copy_dnsdomain((uschar *)hostdata->h_name);
+ host->name = string_copy_dnsdomain(US hostdata->h_name);
if (fully_qualified_name != NULL) *fully_qualified_name = host->name;
/* Get the list of addresses. IPv4 and IPv6 addresses can be distinguished
ipv4_addr = hostdata->h_length == sizeof(struct in_addr);
- for (addrlist = USS hostdata->h_addr_list; *addrlist != NULL; addrlist++)
+ for (uschar ** addrlist = USS hostdata->h_addr_list; *addrlist; addrlist++)
{
uschar *text_address =
host_ntoa(ipv4_addr? AF_INET:AF_INET6, *addrlist, NULL, NULL);
HDEBUG(D_host_lookup) debug_printf("%s\n", msg);
if (temp_error) goto RETURN_AGAIN;
- if (host_checking || !log_testing_mode)
+ if (host_checking || !f.log_testing_mode)
log_write(L_host_lookup_failed, LOG_MAIN, "%s", msg);
return HOST_FIND_FAILED;
}
HDEBUG(D_host_lookup)
{
- const host_item *h;
- if (fully_qualified_name != NULL)
+ if (fully_qualified_name)
debug_printf("fully qualified name = %s\n", *fully_qualified_name);
debug_printf("%s looked up these IP addresses:\n",
#if HAVE_IPV6
"gethostbyname"
#endif
);
- for (h = host; h != last->next; h = h->next)
+ for (const host_item * h = host; h != last->next; h = h->next)
debug_printf(" name=%s address=%s\n", h->name,
- (h->address == NULL)? US"<null>" : h->address);
+ h->address ? h->address : US"<null>");
}
/* Return the found status. */
create additional host items for the additional addresses, copying all the
other fields, and randomizing the order.
-On IPv6 systems, A6 records are sought first (but only if support for A6 is
-configured - they may never become mainstream), then AAAA records are sought,
-and finally A records are sought as well.
+On IPv6 systems, AAAA records are sought first, then A records.
The host name may be changed if the DNS returns a different name - e.g. fully
qualified or changed via CNAME. If fully_qualified_name is not NULL, dns_lookup
to something)
dnssec_request if TRUE request the AD bit
dnssec_require if TRUE require the AD bit
+ whichrrs select ipv4, ipv6 results
Returns: HOST_FIND_FAILED couldn't find A record
HOST_FIND_AGAIN try again later
set_address_from_dns(host_item *host, host_item **lastptr,
const uschar *ignore_target_hosts, BOOL allow_ip,
const uschar **fully_qualified_name,
- BOOL dnssec_request, BOOL dnssec_require)
+ BOOL dnssec_request, BOOL dnssec_require, int whichrrs)
{
-dns_record *rr;
host_item *thishostlast = NULL; /* Indicates not yet filled in anything */
BOOL v6_find_again = FALSE;
BOOL dnssec_fail = FALSE;
if (allow_ip && string_is_ip_address(host->name, NULL) != 0)
{
#ifndef STAND_ALONE
- if (ignore_target_hosts != NULL &&
- verify_check_this_host(&ignore_target_hosts, NULL, host->name,
+ if ( ignore_target_hosts
+ && verify_check_this_host(&ignore_target_hosts, NULL, host->name,
host->name, NULL) == OK)
return HOST_IGNORED;
#endif
}
/* On an IPv6 system, unless IPv6 is disabled, go round the loop up to twice,
-looking for AAAA records the first time. However, unless
-doing standalone testing, we force an IPv4 lookup if the domain matches
-dns_ipv4_lookup is set. On an IPv4 system, go round the
-loop once only, looking only for A records. */
+looking for AAAA records the first time. However, unless doing standalone
+testing, we force an IPv4 lookup if the domain matches dns_ipv4_lookup global.
+On an IPv4 system, go round the 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, CUSS &dns_ipv4_lookup, 0, NULL, NULL,
- MCL_DOMAIN, TRUE, NULL) == OK))
+ if ( disable_ipv6
+ || !(whichrrs & HOST_FIND_BY_AAAA)
+ || (dns_ipv4_lookup
+ && 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 */
{
static int types[] = { T_A, T_AAAA };
int type = types[i];
- int randoffset = (i == 0)? 500 : 0; /* Ensures v6 sorts before v4 */
+ int randoffset = i == (whichrrs & HOST_FIND_IPV4_FIRST ? 1 : 0)
+ ? 500 : 0; /* Ensures v6/4 sort order */
dns_answer dnsa;
dns_scan dnss;
fully_qualified_name = NULL;
- for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+ for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
rr;
- rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT))
+ rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == type)
{
- if (rr->type == type)
- {
- dns_address *da = dns_address_from_rr(&dnsa, rr);
+ dns_address * da = dns_address_from_rr(&dnsa, rr);
- DEBUG(D_host_lookup)
- if (!da) debug_printf("no addresses extracted from A6 RR for %s\n",
- host->name);
+ DEBUG(D_host_lookup)
+ 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. */
+ /* 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; da = da->next)
- {
- #ifndef STAND_ALONE
- if (ignore_target_hosts != NULL &&
- verify_check_this_host(&ignore_target_hosts, NULL,
- host->name, da->address, NULL) == OK)
- {
- DEBUG(D_host_lookup)
- debug_printf("ignored host %s [%s]\n", host->name, da->address);
- continue;
- }
- #endif
+ for (; da; da = da->next)
+ {
+ #ifndef STAND_ALONE
+ if (ignore_target_hosts != NULL &&
+ verify_check_this_host(&ignore_target_hosts, NULL,
+ host->name, da->address, NULL) == OK)
+ {
+ DEBUG(D_host_lookup)
+ debug_printf("ignored host %s [%s]\n", host->name, da->address);
+ continue;
+ }
+ #endif
- /* If this is the first address, stick it in the given host block,
- and change the name if the returned RR has a different name. */
+ /* If this is the first address, stick it in the given host block,
+ and change the name if the returned RR has a different name. */
- if (thishostlast == NULL)
- {
- if (strcmpic(host->name, rr->name) != 0)
- host->name = string_copy_dnsdomain(rr->name);
- host->address = da->address;
- host->sort_key = host->mx * 1000 + random_number(500) + randoffset;
- host->status = hstatus_unknown;
- host->why = hwhy_unknown;
- thishostlast = host;
- }
+ if (thishostlast == NULL)
+ {
+ if (strcmpic(host->name, rr->name) != 0)
+ host->name = string_copy_dnsdomain(rr->name);
+ host->address = da->address;
+ host->sort_key = host->mx * 1000 + random_number(500) + randoffset;
+ host->status = hstatus_unknown;
+ host->why = hwhy_unknown;
+ thishostlast = host;
+ }
- /* Not the first address. Check for, and ignore, duplicates. Then
- insert in the chain at a random point. */
+ /* Not the first address. Check for, and ignore, duplicates. Then
+ insert in the chain at a random point. */
- else
- {
- int new_sort_key;
- host_item *next;
-
- /* End of our local chain is specified by "thishostlast". */
-
- for (next = host;; next = next->next)
- {
- if (Ustrcmp(CS da->address, next->address) == 0) break;
- if (next == thishostlast) { next = NULL; break; }
- }
- if (next != NULL) continue; /* With loop for next address */
-
- /* Not a duplicate */
-
- new_sort_key = host->mx * 1000 + random_number(500) + randoffset;
- next = store_get(sizeof(host_item));
-
- /* New address goes first: insert the new block after the first one
- (so as not to disturb the original pointer) but put the new address
- in the original block. */
-
- if (new_sort_key < host->sort_key)
- {
- *next = *host; /* Copies port */
- host->next = next;
- host->address = da->address;
- host->sort_key = new_sort_key;
- if (thishostlast == host) thishostlast = next; /* Local last */
- if (*lastptr == host) *lastptr = next; /* Global last */
- }
-
- /* Otherwise scan down the addresses for this host to find the
- one to insert after. */
-
- else
- {
- host_item *h = host;
- while (h != thishostlast)
- {
- if (new_sort_key < h->next->sort_key) break;
- h = h->next;
- }
- *next = *h; /* Copies port */
- h->next = next;
- next->address = da->address;
- next->sort_key = new_sort_key;
- if (h == thishostlast) thishostlast = next; /* Local last */
- if (h == *lastptr) *lastptr = next; /* Global last */
- }
- }
- }
+ else
+ {
+ int new_sort_key;
+ host_item *next;
+
+ /* End of our local chain is specified by "thishostlast". */
+
+ for (next = host;; next = next->next)
+ {
+ if (Ustrcmp(CS da->address, next->address) == 0) break;
+ if (next == thishostlast) { next = NULL; break; }
+ }
+ if (next != NULL) continue; /* With loop for next address */
+
+ /* Not a duplicate */
+
+ new_sort_key = host->mx * 1000 + random_number(500) + randoffset;
+ next = store_get(sizeof(host_item));
+
+ /* New address goes first: insert the new block after the first one
+ (so as not to disturb the original pointer) but put the new address
+ in the original block. */
+
+ if (new_sort_key < host->sort_key)
+ {
+ *next = *host; /* Copies port */
+ host->next = next;
+ host->address = da->address;
+ host->sort_key = new_sort_key;
+ if (thishostlast == host) thishostlast = next; /* Local last */
+ if (*lastptr == host) *lastptr = next; /* Global last */
+ }
+
+ /* Otherwise scan down the addresses for this host to find the
+ one to insert after. */
+
+ else
+ {
+ host_item *h = host;
+ while (h != thishostlast)
+ {
+ if (new_sort_key < h->next->sort_key) break;
+ h = h->next;
+ }
+ *next = *h; /* Copies port */
+ h->next = next;
+ next->address = da->address;
+ next->sort_key = new_sort_key;
+ if (h == thishostlast) thishostlast = next; /* Local last */
+ if (h == *lastptr) *lastptr = next; /* Global last */
+ }
+ }
}
}
}
whichrrs flags indicating which RRs to look for:
HOST_FIND_BY_SRV => look for SRV
HOST_FIND_BY_MX => look for MX
- HOST_FIND_BY_A => look for A or AAAA
+ HOST_FIND_BY_A => look for A
+ HOST_FIND_BY_AAAA => look for AAAA
also flags indicating how the lookup is done
HOST_FIND_QUALIFY_SINGLE ) passed to the
HOST_FIND_SEARCH_PARENTS ) resolver
+ HOST_FIND_IPV4_FIRST => reverse usual result ordering
+ HOST_FIND_IPV4_ONLY => MX results elide ipv6
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
const uschar **fully_qualified_name, BOOL *removed)
{
host_item *h, *last;
-dns_record *rr;
int rc = DNS_FAIL;
int ind_type = 0;
int yield;
dns_init((whichrrs & HOST_FIND_QUALIFY_SINGLE) != 0,
(whichrrs & HOST_FIND_SEARCH_PARENTS) != 0,
dnssec_request);
-host_find_failed_syntax = FALSE;
+f.host_find_failed_syntax = FALSE;
/* First, if requested, look for SRV records. The service name is given; we
assume TCP protocol. DNS domain names are constrained to a maximum of 256
characters, so the code below should be safe. */
-if ((whichrrs & HOST_FIND_BY_SRV) != 0)
+if (whichrrs & HOST_FIND_BY_SRV)
{
- uschar buffer[300];
- uschar *temp_fully_qualified_name = buffer;
+ gstring * g;
+ uschar * temp_fully_qualified_name;
int prefix_length;
- (void)sprintf(CS buffer, "_%s._tcp.%n%.256s", srv_service, &prefix_length,
- host->name);
+ g = string_fmt_append(NULL, "_%s._tcp.%n%.256s",
+ srv_service, &prefix_length, host->name);
+ temp_fully_qualified_name = string_from_gstring(g);
ind_type = T_SRV;
/* Search for SRV records. If the fully qualified name is different to
dnssec = DS_UNK;
lookup_dnssec_authenticated = NULL;
- rc = dns_lookup_timerwrap(&dnsa, buffer, ind_type, CUSS &temp_fully_qualified_name);
+ rc = dns_lookup_timerwrap(&dnsa, temp_fully_qualified_name, ind_type,
+ CUSS &temp_fully_qualified_name);
DEBUG(D_dns)
if ((dnssec_request || dnssec_require)
- & !dns_is_secure(&dnsa)
- & dns_is_aa(&dnsa))
+ && !dns_is_secure(&dnsa)
+ && dns_is_aa(&dnsa))
debug_printf("DNS lookup of %.256s (SRV) requested AD, but got AA\n", host->name);
if (dnssec_request)
{ dnssec = DS_NO; lookup_dnssec_authenticated = US"no"; }
}
- if (temp_fully_qualified_name != buffer && fully_qualified_name != NULL)
+ if (temp_fully_qualified_name != g->s && fully_qualified_name != NULL)
*fully_qualified_name = temp_fully_qualified_name + prefix_length;
/* On DNS failures, we give the "try again" error unless the domain is
if (rc != DNS_SUCCEED)
{
- if ((whichrrs & HOST_FIND_BY_A) == 0)
+ if (!(whichrrs & (HOST_FIND_BY_A | HOST_FIND_BY_AAAA)))
{
DEBUG(D_host_lookup) debug_printf("Address records are not being sought\n");
yield = HOST_FIND_FAILED;
host->dnssec = DS_UNK;
lookup_dnssec_authenticated = NULL;
rc = set_address_from_dns(host, &last, ignore_target_hosts, FALSE,
- fully_qualified_name, dnssec_request, dnssec_require);
+ fully_qualified_name, dnssec_request, dnssec_require, whichrrs);
/* If one or more address records have been found, check that none of them
are local. Since we know the host items all have their IP addresses
if (rc == HOST_IGNORED) rc = HOST_FIND_FAILED; /* No special action */
DEBUG(D_host_lookup)
- {
- host_item *h;
- if (host->address != NULL)
+ if (host->address)
{
- if (fully_qualified_name != NULL)
+ if (fully_qualified_name)
debug_printf("fully qualified name = %s\n", *fully_qualified_name);
- for (h = host; h != last->next; h = h->next)
+ for (host_item * h = host; h != last->next; h = h->next)
debug_printf("%s %s mx=%d sort=%d %s\n", h->name,
- (h->address == NULL)? US"<null>" : h->address, h->mx, h->sort_key,
- (h->status >= hstatus_unusable)? US"*" : US"");
+ h->address ? h->address : US"<null>", h->mx, h->sort_key,
+ h->status >= hstatus_unusable ? US"*" : US"");
}
- }
yield = rc;
goto out;
last = NULL; /* Indicates that not even the first item is filled yet */
-for (rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
+for (dns_record * rr = dns_next_rr(&dnsa, &dnss, RESET_ANSWERS);
rr;
rr = dns_next_rr(&dnsa, &dnss, RESET_NEXT)) if (rr->type == ind_type)
{
- int precedence;
- int weight = 0; /* For SRV records */
+ int precedence, weight;
int port = PORT_NONE;
const uschar * s = rr->data; /* MUST be unsigned for GETSHORT */
uschar data[256];
if (ind_type == T_MX)
weight = random_number(500);
-
- /* SRV records are specified with a port and a weight. The weight is used
- in a special algorithm. However, to start with, we just use it to order the
- records of equal priority (precedence). */
-
else
{
+ /* SRV records are specified with a port and a weight. The weight is used
+ in a special algorithm. However, to start with, we just use it to order the
+ records of equal priority (precedence). */
GETSHORT(weight, s);
GETSHORT(port, s);
}
never know what junk might get into the DNS (and this case has been seen on
more than one occasion). */
- if (last != NULL) /* This is not the first record */
+ if (last) /* This is not the first record */
{
host_item *prev = NULL;
for (h = host; h != last->next; prev = h, h = h->next)
- {
if (strcmpic(h->name, data) == 0)
{
DEBUG(D_host_lookup)
debug_printf("discarded duplicate host %s (MX=%d)\n", data,
- (precedence > h->mx)? precedence : h->mx);
+ precedence > h->mx ? precedence : h->mx);
if (precedence >= h->mx) goto NEXT_MX_RR; /* Skip greater precedence */
if (h == host) /* Override first item */
{
if (h == last) last = prev;
break;
}
- }
}
/* If this is the first MX or SRV record, put the data into the existing host
block. Otherwise, add a new block in the correct place; if it has to be
before the first block, copy the first block's data to a new second block. */
- if (last == NULL)
+ if (!last)
{
host->name = string_copy_dnsdomain(data);
host->address = NULL;
host->dnssec = dnssec;
last = host;
}
+ else
/* Make a new host item and seek the correct insertion place */
-
- else
{
int sort_key = precedence * 1000 + weight;
host_item *next = store_get(sizeof(host_item));
host->next = next;
if (last == host) last = next;
}
+ else
/* Else scan down the items we have inserted as part of this exercise;
don't go further. */
-
- else
{
for (h = host; h != last; h = h->next)
- {
if (sort_key < h->next->sort_key)
{
next->next = h->next;
h->next = next;
break;
}
- }
/* Join on after the last host item that's part of this
processing if we haven't stopped sooner. */
if (ind_type == T_SRV)
{
- host_item **pptr;
+ host_item ** pptr;
if (host == last && host->name[0] == 0)
{
for (ppptr = pptr, hhh = h;
hhh != hh;
- ppptr = &(hhh->next), hhh = hhh->next)
- {
- if (hhh->sort_key >= randomizer) break;
- }
+ ppptr = &hhh->next, hhh = hhh->next)
+ if (hhh->sort_key >= randomizer)
+ break;
/* hhh now points to the host that should go first; ppptr points to the
place that points to it. Unfortunately, if the start of the minilist is
hhh->next = temp.next;
h->next = hhh;
}
-
else
{
hhh->next = h; /* The rest of the chain follows it */
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);
+ NULL, dnssec_request, dnssec_require,
+ whichrrs & HOST_FIND_IPV4_ONLY
+ ? HOST_FIND_BY_A : HOST_FIND_BY_A | HOST_FIND_BY_AAAA);
if (rc != HOST_FOUND)
{
h->status = hstatus_unusable;
switch (rc)
{
- 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;
+ 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;
}
}
}
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 */
+ if ( h->mx != next->mx /* If next is different MX */
+ || !h->address /* OR this one is unset */
+ )
+ continue; /* move on to next */
+
+ if ( whichrrs & HOST_FIND_IPV4_FIRST
+ ? !Ustrchr(h->address, ':') /* OR this one is IPv4 */
+ || next->address
+ && Ustrchr(next->address, ':') /* OR next is IPv6 */
+
+ : Ustrchr(h->address, ':') /* OR this one is IPv6 */
+ || next->address
+ && !Ustrchr(next->address, ':') /* OR next is IPv4 */
+ )
continue; /* move on to next */
+
temp = *h; /* otherwise, swap */
temp.next = next->next;
*h = *next;
DEBUG(D_host_lookup)
{
- if (fully_qualified_name != NULL)
+ if (fully_qualified_name)
debug_printf("fully qualified name = %s\n", *fully_qualified_name);
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 == 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);
for (h = host; h != last->next; h = h->next)
{
int main(int argc, char **cargv)
{
host_item h;
-int whichrrs = HOST_FIND_BY_MX | HOST_FIND_BY_A;
+int whichrrs = HOST_FIND_BY_MX | HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
BOOL byname = FALSE;
BOOL qualify_single = TRUE;
BOOL search_parents = FALSE;
if (Ustrcmp(buffer, "byname") == 0) byname = TRUE;
else if (Ustrcmp(buffer, "no_byname") == 0) byname = FALSE;
- else if (Ustrcmp(buffer, "a_only") == 0) whichrrs = HOST_FIND_BY_A;
+ else if (Ustrcmp(buffer, "a_only") == 0) whichrrs = HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
else if (Ustrcmp(buffer, "mx_only") == 0) whichrrs = HOST_FIND_BY_MX;
else if (Ustrcmp(buffer, "srv_only") == 0) whichrrs = HOST_FIND_BY_SRV;
else if (Ustrcmp(buffer, "srv+a") == 0)
- whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_A;
+ whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
else if (Ustrcmp(buffer, "srv+mx") == 0)
whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_MX;
else if (Ustrcmp(buffer, "srv+mx+a") == 0)
- whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_MX | HOST_FIND_BY_A;
+ whichrrs = HOST_FIND_BY_SRV | HOST_FIND_BY_MX | HOST_FIND_BY_A | HOST_FIND_BY_AAAA;
else if (Ustrcmp(buffer, "qualify_single") == 0) qualify_single = TRUE;
else if (Ustrcmp(buffer, "no_qualify_single") == 0) qualify_single = FALSE;
else if (Ustrcmp(buffer, "search_parents") == 0) search_parents = TRUE;
else if (Ustrcmp(buffer, "require_dnssec") == 0) require_dnssec = TRUE;
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;
+ f.running_in_test_harness = !f.running_in_test_harness;
else if (Ustrcmp(buffer, "ipv6") == 0) disable_ipv6 = !disable_ipv6;
else if (Ustrcmp(buffer, "res_debug") == 0)
{
printf("> ");
while (Ufgets(buffer, 256, stdin) != NULL)
{
- int i;
int x[4];
int len = Ustrlen(buffer);
len = host_aton(buffer, x);
printf("length = %d ", len);
- for (i = 0; i < len; i++)
+ for (int i = 0; i < len; i++)
{
printf("%04x ", (x[i] >> 16) & 0xffff);
printf("%04x ", x[i] & 0xffff);