* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2012 */
+/* 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;
domain. Sigh. */
address = string_sprintf("[%s]:%d", sender_host_address, sender_host_port);
-if ((log_extra_selector & LX_incoming_port) == 0 || sender_host_port <= 0)
+if (!LOGGING(incoming_port) || sender_host_port <= 0)
*(Ustrrchr(address, ':')) = 0;
/* If there's no EHLO/HELO data, we can't show it. */
/* 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 */
{
uschar *flag = useflag? US"H=" : US"";
uschar *iface = US"";
- if ((log_extra_selector & LX_incoming_interface) != 0 &&
- interface_address != NULL)
+ if (LOGGING(incoming_interface) && interface_address != NULL)
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",
/* 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
{
j = binary[0];
for (i = 24; i >= 0; i -= 8)
- {
- sprintf(CS tt, "%d.", (j >> i) & 255);
- while (*tt) tt++;
- }
+ tt += sprintf(CS tt, "%d.", (j >> i) & 255);
}
else
- {
for (i = 0; i < 4; i++)
{
j = binary[i];
- sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep);
- while (*tt) tt++;
+ tt += sprintf(CS tt, "%04x%c%04x%c", (j >> 16) & 0xffff, sep, j & 0xffff, sep);
}
- }
tt--; /* lose final separator */
}
+/* Like host_nmtoa() but: ipv6-only, canonical output, no mask
+
+Arguments:
+ binary points to the ints
+ buffer big enough to hold the result
+
+Returns: the number of characters placed in buffer, not counting
+ the final nul.
+*/
+
+int
+ipv6_nmtoa(int * binary, uschar * buffer)
+{
+int i, j, k;
+uschar * c = buffer;
+uschar * d = NULL; /* shut insufficiently "clever" compiler up */
+
+for (i = 0; i < 4; i++)
+ { /* expand to text */
+ j = binary[i];
+ c += sprintf(CS c, "%x:%x:", (j >> 16) & 0xffff, j & 0xffff);
+ }
+
+for (c = buffer, k = -1, i = 0; i < 8; i++)
+ { /* find longest 0-group sequence */
+ if (*c == '0') /* must be "0:" */
+ {
+ uschar * s = c;
+ j = i;
+ while (c[2] == '0') i++, c += 2;
+ if (i-j > k)
+ {
+ k = i-j; /* length of sequence */
+ d = s; /* start of sequence */
+ }
+ }
+ while (*++c != ':') ;
+ c++;
+ }
+
+c[-1] = '\0'; /* drop trailing colon */
+
+/* debug_printf("%s: D k %d <%s> <%s>\n", __FUNCTION__, k, d, d + 2*(k+1)); */
+if (k >= 0)
+ { /* collapse */
+ c = d + 2*(k+1);
+ if (d == buffer) c--; /* need extra colon */
+ *d++ = ':'; /* 1st 0 */
+ while ((*d++ = *c++)) ;
+ }
+else
+ d = c;
+
+return d - buffer;
+}
+
+
/*************************************************
* Check port for tls_on_connect *
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.
int af;
#endif
-/* If we are in the test harness, a name ending in .test.again.dns always
-forces a temporary error response, unless the name is in
-dns_again_means_nonexist. */
-
-if (running_in_test_harness)
- {
- const uschar *endname = host->name + Ustrlen(host->name);
- if (Ustrcmp(endname - 14, "test.again.dns") == 0) goto RETURN_AGAIN;
- }
-
/* Make sure DNS options are set as required. This appears to be necessary in
some circumstances when the get..byname() function actually calls the DNS. */
BOOL ipv4_addr;
int error_num = 0;
struct hostent *hostdata;
- unsigned long time_msec;
+ unsigned long time_msec = 0; /* compiler quietening */
#ifdef STAND_ALONE
printf("Looking up: %s\n", host->name);
}
#endif /* HAVE_IPV6 */
- if (slow_lookup_log
+ if ( slow_lookup_log
&& (time_msec = get_time_in_ms() - time_msec) > slow_lookup_log)
log_long_lookup(US"name", host->name, time_msec);
return HOST_FOUND;
}
-/* On an IPv6 system, unless IPv6 is disabled, go round the loop up to three
-times, looking for A6 and AAAA records the first two times. However, unless
+/* 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. Since A6 records look like being abandoned, support
-them only if explicitly configured to do so. On an IPv4 system, go round the
+dns_ipv4_lookup is set. On an IPv4 system, go round the
loop once only, looking only for A records. */
#if HAVE_IPV6
for (; i >= 0; i--)
{
- static int types[] = { T_A, T_AAAA, T_A6 };
+ static int types[] = { T_A, T_AAAA };
int type = types[i];
int randoffset = (i == 0)? 500 : 0; /* Ensures v6 sorts before v4 */
dns_answer dnsa;
: dns_is_secure(&dnsa) ? US"yes" : US"no";
DEBUG(D_dns)
- if ((dnssec_request || dnssec_require)
- & !dns_is_secure(&dnsa)
- & dns_is_aa(&dnsa))
- debug_printf("DNS lookup of %.256s (A/AAA/A6) requested AD, but got AA\n", host->name);
+ if ( (dnssec_request || dnssec_require)
+ && !dns_is_secure(&dnsa)
+ && dns_is_aa(&dnsa)
+ )
+ debug_printf("DNS lookup of %.256s (A/AAAA) requested AD, but got AA\n", host->name);
- /* We want to return HOST_FIND_AGAIN if one of the A, A6, or AAAA lookups
+ /* We want to return HOST_FIND_AGAIN if one of the A or AAAA lookups
fails or times out, but not if another one succeeds. (In the early
IPv6 days there are name servers that always fail on AAAA, but are happy
to give out an A record. We want to proceed with that A record.) */
{
if (i == 0) /* Just tried for an A record, i.e. end of loop */
{
- if (host->address != NULL) return HOST_FOUND; /* A6 or AAAA was found */
+ if (host->address != NULL) return HOST_FOUND; /* AAAA was found */
if (rc == DNS_AGAIN || rc == DNS_FAIL || v6_find_again)
return HOST_FIND_AGAIN;
return HOST_FIND_FAILED; /* DNS_NOMATCH or DNS_NODATA */
}
- /* Tried for an A6 or AAAA record: remember if this was a temporary
+ /* Tried for an AAAA record: remember if this was a temporary
error, and look for the next record type. */
if (rc != DNS_NOMATCH && rc != DNS_NODATA) v6_find_again = TRUE;
{
log_write(L_host_lookup_failed, LOG_MAIN,
"dnssec fail on %s for %.256s",
- i>1 ? "A6" : i>0 ? "AAAA" : "A", host->name);
+ i>0 ? "AAAA" : "A", host->name);
continue;
}
if (host->dnssec == DS_YES) /* set in host_find_bydns() */
{
if (rr->type == type)
{
- /* dns_address *da = dns_address_from_rr(&dnsa, rr); */
-
- dns_address *da;
- 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);
- }
/* This loop runs only once for A and AAAA records, but may run
several times for an A6 record that generated multiple addresses. */
}
}
-/* Control gets here only if the third lookup (the A record) succeeded.
+/* Control gets here only if the econdookup (the A record) succeeded.
However, the address may not be filled in if it was ignored. */
-return (host->address == NULL)? HOST_IGNORED : HOST_FOUND;
+return host->address ? HOST_FOUND : HOST_IGNORED;
}
if (dnssec_request)
{
if (dns_is_secure(&dnsa))
- {
+ {
DEBUG(D_host_lookup) debug_printf("%s MX DNSSEC\n", host->name);
dnssec = DS_YES; lookup_dnssec_authenticated = US"yes";
}
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->why = hwhy_deferred;
}
else
- h->why = (rc == HOST_IGNORED)? hwhy_ignored : hwhy_failed;
+ h->why = rc == HOST_IGNORED ? hwhy_ignored : hwhy_failed;
}
}
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;
else
{
int flags = whichrrs;
- dnssec d;
+ dnssec_domains d;
h.name = buffer;
h.next = NULL;