Fix crash from SRV lookup hitting a CNAME
[exim.git] / src / src / dns.c
index 1da7feb38366363bc41406f72f63250172f36ba9..6ef6b7784b03343bff3a2b3fae635577d8300d37 100644 (file)
@@ -240,8 +240,7 @@ uschar *pp = buffer;
 if (Ustrchr(string, ':') == NULL)
 #endif
   {
-  int i;
-  for (i = 0; i < 4; i++)
+  for (int i = 0; i < 4; i++)
     {
     const uschar *ppp = p;
     while (ppp > string && ppp[-1] != '.') ppp--;
@@ -259,7 +258,6 @@ abbreviation in the textual form. */
 #if HAVE_IPV6
 else
   {
-  int i;
   int v6[4];
   (void)host_aton(string, v6);
 
@@ -267,12 +265,9 @@ else
   nibble, and look in the ip6.int domain. The domain was subsequently
   changed to ip6.arpa. */
 
-  for (i = 3; i >= 0; i--)
-    {
-    int j;
-    for (j = 0; j < 32; j += 4)
+  for (int i = 3; i >= 0; i--)
+    for (int j = 0; j < 32; j += 4)
       pp += sprintf(CS pp, "%x.", (v6[i] >> j) & 15);
-    }
   Ustrcpy(pp, "ip6.arpa.");
 
   /* Another way of doing IPv6 reverse lookups was proposed in conjunction
@@ -287,7 +282,7 @@ else
   Ustrcpy(pp, "\\[x");
   pp += 3;
 
-  for (i = 0; i < 4; i++)
+  for (int i = 0; i < 4; i++)
     {
     sprintf(pp, "%08X", v6[i]);
     pp += 8;
@@ -467,11 +462,10 @@ static const uschar *
 dns_extract_auth_name(const dns_answer * dnsa) /* FIXME: const dns_answer */
 {
 dns_scan dnss;
-dns_record * rr;
 const HEADER * h = (const HEADER *) dnsa->answer;
 
 if (h->nscount && h->aa)
-  for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
+  for (dns_record * rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
        rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT))
     if (rr->type == (h->ancount ? T_NS : T_SOA))
       return string_copy(rr->name);
@@ -639,6 +633,10 @@ up nameservers that produce this error continually, so there is the option of
 providing a list of domains for which this is treated as a non-existent
 host.
 
+The dns_answer structure is pretty big; enough to hold a max-sized DNS message
+- so best allocated from fast-release memory.  As of writing, all our callers
+use a stack-auto variable.
+
 Arguments:
   dnsa      pointer to dns_answer structure
   name      name to look up
@@ -712,7 +710,11 @@ lookup, which constructs the names itself, so they should be OK. Besides,
 bitstring labels don't conform to normal name syntax. (But the aren't used any
 more.)
 
-For SRV records, we omit the initial _smtp._tcp. components at the start. */
+For SRV records, we omit the initial _smtp._tcp. components at the start.
+The check has been seen to bite on the destination of a SRV lookup that
+initiall hit a CNAME, for which the next name had only two components.
+RFC2782 makes no mention of the possibiility of CNAMES, but the Wikipedia
+article on SRV says they are not a valid configuration. */
 
 #ifndef STAND_ALONE   /* Omit this for stand-alone tests */
 
@@ -728,8 +730,8 @@ if (check_dns_names_pattern[0] != 0 && type != T_PTR && type != T_TXT)
 
   if (type == T_SRV || type == T_TLSA)
     {
-    while (*checkname++ != '.');
-    while (*checkname++ != '.');
+    while (*checkname && *checkname++ != '.') ;
+    while (*checkname && *checkname++ != '.') ;
     }
 
   if (pcre_exec(regex_check_dns_names, NULL, CCS checkname, Ustrlen(checkname),
@@ -869,7 +871,6 @@ int
 dns_lookup(dns_answer *dnsa, const uschar *name, int type,
   const uschar **fully_qualified_name)
 {
-int i;
 const uschar *orig_name = name;
 BOOL secure_so_far = TRUE;
 
@@ -880,12 +881,12 @@ resolvers hiding behind a config variable. Loop to follow CNAME chains so far,
 but no further...  The testsuite tests the latter case, mostly assuming that the
 former will work. */
 
-for (i = 0; i <= dns_cname_loops; i++)
+for (int i = 0; i <= dns_cname_loops; i++)
   {
   uschar * data;
-  dns_record *rr, cname_rr, type_rr;
+  dns_record cname_rr, type_rr;
   dns_scan dnss;
-  int datalen, rc;
+  int rc;
 
   /* DNS lookup failures get passed straight back. */
 
@@ -899,7 +900,7 @@ for (i = 0; i <= dns_cname_loops; i++)
   area in the dnsa block. */
 
   cname_rr.data = type_rr.data = 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)
       {
@@ -947,8 +948,8 @@ for (i = 0; i <= dns_cname_loops; i++)
     return DNS_FAIL;
 
   data = store_get(256);
-  if ((datalen = dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
-    cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256)) < 0)
+  if (dn_expand(dnsa->answer, dnsa->answer + dnsa->answerlen,
+      cname_rr.data, (DN_EXPAND_ARG4_TYPE)data, 256) < 0)
     return DNS_FAIL;
   name = data;
 
@@ -1101,7 +1102,7 @@ switch (type)
          && (h->rcode == NOERROR || h->rcode == NXDOMAIN)
          && ntohs(h->qdcount) == 1 && ntohs(h->ancount) == 0
          && ntohs(h->nscount) >= 1)
-           dnsa->answerlen = MAXPACKET;
+           dnsa->answerlen = sizeof(dnsa->answer);
 
       for (rr = dns_next_rr(dnsa, &dnss, RESET_AUTHORITY);
           rr; rr = dns_next_rr(dnsa, &dnss, RESET_NEXT)
@@ -1213,8 +1214,7 @@ else
   if (rr->data + 16 <= dnsa_lim)
     {
     struct in6_addr in6;
-    int i;
-    for (i = 0; i < 16; i++) in6.s6_addr[i] = rr->data[i];
+    for (int i = 0; i < 16; i++) in6.s6_addr[i] = rr->data[i];
     yield = store_get(sizeof(dns_address) + 50);
     inet_ntop(AF_INET6, &in6, CS yield->address, 50);
     yield->next = NULL;