#include "exim.h"
-/* Function declaration needed for mutual recursion when A6 records
-are supported. */
-
-#if HAVE_IPV6
-#ifdef SUPPORT_A6
-static void dns_complete_a6(dns_address ***, dns_answer *, dns_record *,
- int, uschar *);
-#endif
-#endif
-
/*************************************************
* Fake DNS resolver *
*/
static int
-fakens_search(uschar *domain, int type, uschar *answerptr, int size)
+fakens_search(const uschar *domain, int type, uschar *answerptr, int size)
{
int len = Ustrlen(domain);
int asize = size; /* Locally modified */
*/
void
-dns_build_reverse(uschar *string, uschar *buffer)
+dns_build_reverse(const uschar *string, uschar *buffer)
{
-uschar *p = string + Ustrlen(string);
+const uschar *p = string + Ustrlen(string);
uschar *pp = buffer;
/* Handle IPv4 address */
int i;
for (i = 0; i < 4; i++)
{
- uschar *ppp = p;
+ const uschar *ppp = p;
while (ppp > string && ppp[-1] != '.') ppp--;
Ustrncpy(pp, ppp, p - ppp);
pp += p - ppp;
*/
BOOL
-dns_is_secure(dns_answer *dnsa)
+dns_is_secure(const dns_answer * dnsa)
{
#ifdef DISABLE_DNSSEC
DEBUG(D_dns)
#endif
}
+static void
+dns_set_insecure(dns_answer * dnsa)
+{
+HEADER * h = (HEADER *)dnsa->answer;
+h->ad = 0;
+}
+
*/
static int
-dns_return(uschar *name, int type, int rc)
+dns_return(const uschar * name, int type, int rc)
{
res_state resp = os_get_dns_resolver_res();
tree_node *node = store_get_perm(sizeof(tree_node) + 290);
*/
int
-dns_basic_lookup(dns_answer *dnsa, uschar *name, int type)
+dns_basic_lookup(dns_answer *dnsa, const uschar *name, int type)
{
#ifndef STAND_ALONE
int rc = -1;
-uschar *save;
+const uschar *save_domain;
#endif
res_state resp = os_get_dns_resolver_res();
return previous->data.val;
}
+#ifdef EXPERIMENTAL_INTERNATIONAL
+/* Convert all names to a-label form before doing lookup */
+ {
+ uschar * alabel;
+ uschar * errstr = NULL;
+ if ((alabel = string_domain_utf8_to_alabel(name, &errstr)), errstr)
+ {
+ DEBUG(D_dns)
+ debug_printf("DNS name '%s' utf8 conversion to alabel failed: %s", name,
+ errstr);
+ host_find_failed_syntax = TRUE;
+ return DNS_NOMATCH;
+ }
+ name = alabel;
+ }
+#endif
+
/* If configured, check the hygene of the name passed to lookup. Otherwise,
although DNS lookups may give REFUSED at the lower level, some resolvers
turn this into TRY_AGAIN, which is silly. Give a NOMATCH return, since such
if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT)
{
- uschar *checkname = name;
+ const uschar *checkname = name;
int ovector[3*(EXPAND_MAXN+1)];
- if (regex_check_dns_names == NULL)
- regex_check_dns_names =
- regex_must_compile(check_dns_names_pattern, FALSE, TRUE);
+ dns_pattern_init();
/* For an SRV lookup, skip over the first two components (the service and
protocol names, which both start with an underscore). */
while (*checkname++ != '.');
}
- if (pcre_exec(regex_check_dns_names, NULL, CS checkname, Ustrlen(checkname),
+ if (pcre_exec(regex_check_dns_names, NULL, CCS checkname, Ustrlen(checkname),
0, PCRE_EOPT, ovector, sizeof(ovector)/sizeof(int)) < 0)
{
DEBUG(D_dns)
nameservers are also believed to do this. It is, of course, contrary to the
specification of the DNS, so we lock it out. */
-if ((
- #ifdef SUPPORT_A6
- type == T_A6 ||
- #endif
- type == T_A || type == T_AAAA) &&
- string_is_ip_address(name, NULL) != 0)
+if ((type == T_A || type == T_AAAA) && string_is_ip_address(name, NULL) != 0)
return DNS_NOMATCH;
/* If we are running in the test harness, instead of calling the normal resolver
(res_search), we call fakens_search(), which recognizes certain special
domains, and interfaces to a fake nameserver for certain special zones. */
-if (running_in_test_harness)
- dnsa->answerlen = fakens_search(name, type, dnsa->answer, MAXPACKET);
-else
- dnsa->answerlen = res_search(CS name, C_IN, type, dnsa->answer, MAXPACKET);
+dnsa->answerlen = running_in_test_harness
+ ? fakens_search(name, type, dnsa->answer, MAXPACKET)
+ : res_search(CCS name, C_IN, type, dnsa->answer, MAXPACKET);
if (dnsa->answerlen > MAXPACKET)
{
name, dns_text_type(type));
/* Cut this out for various test programs */
- #ifndef STAND_ALONE
- save = deliver_domain;
- deliver_domain = name; /* set $domain */
- rc = match_isinlist(name, &dns_again_means_nonexist, 0, NULL, NULL,
+#ifndef STAND_ALONE
+ save_domain = deliver_domain;
+ deliver_domain = string_copy(name); /* set $domain */
+ rc = match_isinlist(name, (const uschar **)&dns_again_means_nonexist, 0, NULL, NULL,
MCL_DOMAIN, TRUE, NULL);
- deliver_domain = save;
+ deliver_domain = save_domain;
if (rc != OK)
{
DEBUG(D_dns) debug_printf("returning DNS_AGAIN\n");
"DNS_NOMATCH\n", name);
return dns_return(name, type, DNS_NOMATCH);
- #else /* For stand-alone tests */
+#else /* For stand-alone tests */
return dns_return(name, type, DNS_AGAIN);
- #endif
+#endif
case NO_RECOVERY:
DEBUG(D_dns) debug_printf("DNS lookup of %s (%s) gave NO_RECOVERY\n"
*/
int
-dns_lookup(dns_answer *dnsa, uschar *name, int type, uschar **fully_qualified_name)
+dns_lookup(dns_answer *dnsa, const uschar *name, int type,
+ const uschar **fully_qualified_name)
{
int i;
-uschar *orig_name = name;
+const uschar *orig_name = name;
+BOOL secure_so_far = TRUE;
/* Loop to follow CNAME chains so far, but no further... */
/* If any data records of the correct type were found, we are done. */
- if (type_rr.data != NULL) return DNS_SUCCEED;
+ if (type_rr.data != NULL)
+ {
+ if (!secure_so_far) /* mark insecure if any element of CNAME chain was */
+ dns_set_insecure(dnsa);
+ return DNS_SUCCEED;
+ }
/* If there are no data records, we need to re-scan the DNS using the
domain given in the CNAME record, which should exist (otherwise we should
if (cname_rr.data == NULL) return DNS_FAIL;
datalen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
- cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256);
+ cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, sizeof(data));
if (datalen < 0) return DNS_FAIL;
name = data;
+ if (!dns_is_secure(dnsa))
+ secure_so_far = FALSE;
+
DEBUG(D_dns) debug_printf("CNAME found: change to %s\n", name);
} /* Loop back to do another lookup */
*/
int
-dns_special_lookup(dns_answer *dnsa, uschar *name, int type,
- uschar **fully_qualified_name)
+dns_special_lookup(dns_answer *dnsa, const uschar *name, int type,
+ const uschar **fully_qualified_name)
{
if (type >= 0) return dns_lookup(dnsa, name, type, fully_qualified_name);
if (type == T_ZNS)
{
- uschar *d = name;
+ const uschar *d = name;
while (d != 0)
{
int rc = dns_lookup(dnsa, d, T_NS, fully_qualified_name);
rc = dns_lookup(dnsa, srvname, T_SRV, NULL);
if (rc == DNS_SUCCEED || rc == DNS_AGAIN)
{
- if (rc == DNS_SUCCEED) *fully_qualified_name = name;
+ if (rc == DNS_SUCCEED) *fully_qualified_name = string_copy(name);
return rc;
}
/* Extract the numerical SRV fields (p is incremented) */
p = rr->data;
GETSHORT(priority, p);
- GETSHORT(weight, p);
+ GETSHORT(weight, p); weight = weight; /* compiler quietening */
GETSHORT(port, p);
/* Check the CSA version number */
-/* Support for A6 records has been commented out since they were demoted to
-experimental status at IETF 51. */
-
-#if HAVE_IPV6 && defined(SUPPORT_A6)
-
-/*************************************************
-* Search DNS block for prefix RRs *
-*************************************************/
-
-/* Called from dns_complete_a6() to search an additional section or a main
-answer section for required prefix records to complete an IPv6 address obtained
-from an A6 record. For each prefix record, a recursive call to dns_complete_a6
-is made, with a new copy of the address so far.
-
-Arguments:
- dnsa the DNS answer block
- which RESET_ADDITIONAL or RESET_ANSWERS
- name name of prefix record
- yptrptr pointer to the pointer that points to where to hang the next
- dns_address structure
- bits number of bits we have already got
- bitvec the bits we have already got
-
-Returns: TRUE if any records were found
-*/
-
-static BOOL
-dns_find_prefix(dns_answer *dnsa, int which, uschar *name, dns_address
- ***yptrptr, int bits, uschar *bitvec)
-{
-BOOL yield = FALSE;
-dns_record *rr;
-dns_scan dnss;
-
-for (rr = dns_next_rr(dnsa, &dnss, which);
- rr != NULL;
- rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
- {
- uschar cbitvec[16];
- if (rr->type != T_A6 || strcmpic(rr->name, name) != 0) continue;
- yield = TRUE;
- memcpy(cbitvec, bitvec, sizeof(cbitvec));
- dns_complete_a6(yptrptr, dnsa, rr, bits, cbitvec);
- }
-
-return yield;
-}
-
-
-
-/*************************************************
-* Follow chains of A6 records *
-*************************************************/
-
-/* A6 records may be incomplete, with pointers to other records containing more
-bits of the address. There can be a tree structure, leading to a number of
-addresses originating from a single initial A6 record.
-
-Arguments:
- yptrptr pointer to the pointer that points to where to hang the next
- dns_address structure
- dnsa the current DNS answer block
- rr the RR we have at present
- bits number of bits we have already got
- bitvec the bits we have already got
-
-Returns: nothing
-*/
-
-static void
-dns_complete_a6(dns_address ***yptrptr, dns_answer *dnsa, dns_record *rr,
- int bits, uschar *bitvec)
-{
-static uschar bitmask[] = { 0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80 };
-uschar *p = (uschar *)(rr->data);
-int prefix_len, suffix_len;
-int i, j, k;
-uschar *chainptr;
-uschar chain[264];
-dns_answer cdnsa;
-
-/* The prefix length is the first byte. It defines the prefix which is missing
-from the data in this record as a number of bits. Zero means this is the end of
-a chain. The suffix is the data in this record; only sufficient bytes to hold
-it are supplied. There may be zero bytes. We have to ignore trailing bits that
-we have already obtained from earlier RRs in the chain. */
-
-prefix_len = *p++; /* bits */
-suffix_len = (128 - prefix_len + 7)/8; /* bytes */
-
-/* If the prefix in this record is greater than the prefix in the previous
-record in the chain, we have to ignore the record (RFC 2874). */
-
-if (prefix_len > 128 - bits) return;
-
-/* In this little loop, the number of bits up to and including the current byte
-is held in k. If we have none of the bits in this byte, we can just or it into
-the current data. If we have all of the bits in this byte, we skip it.
-Otherwise, some masking has to be done. */
-
-for (i = suffix_len - 1, j = 15, k = 8; i >= 0; i--)
- {
- int required = k - bits;
- if (required >= 8) bitvec[j] |= p[i];
- else if (required > 0) bitvec[j] |= p[i] & bitmask[required];
- j--; /* I tried putting these in the "for" statement, but gcc muttered */
- k += 8; /* about computed values not being used. */
- }
-
-/* If the prefix_length is zero, we are at the end of a chain. Build a
-dns_address item with the current data, hang it onto the end of the chain,
-adjust the hanging pointer, and we are done. */
-
-if (prefix_len == 0)
- {
- dns_address *new = store_get(sizeof(dns_address) + 50);
- inet_ntop(AF_INET6, bitvec, CS new->address, 50);
- new->next = NULL;
- **yptrptr = new;
- *yptrptr = &(new->next);
- return;
- }
-
-/* Prefix length is not zero. Reset the number of bits that we have collected
-so far, and extract the chain name. */
-
-bits = 128 - prefix_len;
-p += suffix_len;
-
-chainptr = chain;
-while ((i = *p++) != 0)
- {
- if (chainptr != chain) *chainptr++ = '.';
- memcpy(chainptr, p, i);
- chainptr += i;
- p += i;
- }
-*chainptr = 0;
-chainptr = chain;
-
-/* Now scan the current DNS response record to see if the additional section
-contains the records we want. This processing can be cut out for testing
-purposes. */
-
-if (dns_find_prefix(dnsa, RESET_ADDITIONAL, chainptr, yptrptr, bits, bitvec))
- return;
-
-/* No chain records were found in the current DNS response block. Do a new DNS
-lookup to try to find these records. This opens up the possibility of DNS
-failures. We ignore them at this point; if all branches of the tree fail, there
-will be no addresses at the end. */
-
-if (dns_lookup(&cdnsa, chainptr, T_A6, NULL) == DNS_SUCCEED)
- (void)dns_find_prefix(&cdnsa, RESET_ANSWERS, chainptr, yptrptr, bits, bitvec);
-}
-#endif /* HAVE_IPV6 && defined(SUPPORT_A6) */
-
-
/*************************************************
{
dns_address *yield = NULL;
-#if HAVE_IPV6 && defined(SUPPORT_A6)
-dns_address **yieldptr = &yield;
-uschar bitvec[16];
-#else
dnsa = dnsa; /* Stop picky compilers warning */
-#endif
if (rr->type == T_A)
{
#if HAVE_IPV6
-#ifdef SUPPORT_A6
-else if (rr->type == T_A6)
- {
- memset(bitvec, 0, sizeof(bitvec));
- dns_complete_a6(&yieldptr, dnsa, rr, 0, bitvec);
- }
-#endif /* SUPPORT_A6 */
-
else
{
yield = store_get(sizeof(dns_address) + 50);
return yield;
}
+
+
+void
+dns_pattern_init(void)
+{
+if (check_dns_names_pattern[0] != 0 && !regex_check_dns_names)
+ regex_check_dns_names =
+ regex_must_compile(check_dns_names_pattern, FALSE, TRUE);
+}
+
/* vi: aw ai sw=2
*/
/* End of dns.c */