Support TTL from SOA for NXDOMAIN & NODATA cache entries. Bug 1395
[exim.git] / test / src / fakens.c
index 0806136cc99a87ba437e6e8c173ade1c2a03d413..6d8a99df553405c8076f1ef6fe7353b0739c2ae9 100644 (file)
@@ -53,11 +53,15 @@ HOST_NOT_FOUND.
 Any DNS record line in a zone file can be prefixed with "DELAY=" and
 a number of milliseconds (followed by one space).
 
-Any DNS record line in a zone file can be prefixed with "DNSSEC ";
+Any DNS record line can be prefixed with "DNSSEC ";
 if all the records found by a lookup are marked
 as such then the response will have the "AD" bit set.
 
-Any DNS record line in a zone file can be prefixed with "AA "
+Any DNS record line can be prefixed with "NXDOMAIN ";
+The record will be ignored (but the prefix set still applied);
+This lets us return a DNSSEC NXDOMAIN (=> HOST_NOT_FOUND).
+
+Any DNS record line can be prefixed with "AA "
 if all the records found by a lookup are marked
 as such then the response will have the "AA" bit set.
 
@@ -342,9 +346,6 @@ if (typeptr->name == NULL)
 rrdomain[0] = 0;                 /* No previous domain */
 (void)fseek(f, 0, SEEK_SET);     /* Start again at the beginning */
 
-if (dnssec) *dnssec = TRUE;     /* cancelled by first nonsecure rec found */
-if (aa) *aa = TRUE;             /* cancelled by first non-aa rec found */
-
 /* Scan for RRs */
 
 while (fgets(CS buffer, sizeof(buffer), f) != NULL)
@@ -357,6 +358,7 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
   int qtlen = qtypelen;
   BOOL rr_sec = FALSE;
   BOOL rr_aa = FALSE;
+  BOOL rr_ignore = FALSE;
   int delay = 0;
   uint ttl = DEFAULT_TTL;
 
@@ -382,6 +384,11 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
       rr_sec = TRUE;
       p += 7;
       }
+    if (Ustrncmp(p, US"NXDOMAIN ", 9) == 0)     /* ignore record content */
+      {
+      rr_ignore = TRUE;
+      p += 9;
+      }
     else if (Ustrncmp(p, US"AA ", 3) == 0)      /* tagged as authoritative */
       {
       rr_aa = TRUE;
@@ -438,7 +445,12 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
 
   /* The domain matches */
 
-  if (yield == HOST_NOT_FOUND) yield = NO_DATA;
+  if (yield == HOST_NOT_FOUND)
+    {
+    yield = NO_DATA;
+    if (dnssec) *dnssec = TRUE;     /* cancelled by first nonsecure rec found */
+    if (aa) *aa = TRUE;             /* cancelled by first non-aa rec found */
+    }
 
   /* Compare RR types; a CNAME record is always returned */
 
@@ -462,6 +474,8 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
   if (aa && !rr_aa)
     *aa = FALSE;                        /* cancel AA return */
 
+  if (rr_ignore) continue;
+
   yield = 0;
   *countptr = *countptr + 1;
 
@@ -749,22 +763,23 @@ if (zonefile == NULL)
 
 (void)sprintf(CS buffer, "%s/dnszones/%s", argv[1], zonefile);
 
-/* Initialize the start of the response packet. We don't have to fake up
-everything, because we know that Exim will look only at the answer and
-additional section parts. */
+/* Initialize the start of the response packet. */
 
 memset(packet, 0, 12);
 pk += 12;
 
 /* Open the zone file. */
 
-f = fopen(CS buffer, "r");
-if (f == NULL)
+if (!(f = fopen(CS buffer, "r")))
   {
   fprintf(stderr, "fakens: failed to open %s: %s\n", buffer, strerror(errno));
   return NO_RECOVERY;
   }
 
+header->qr = 1;     /* query */
+header->opcode = QUERY; /* standard query */
+header->tc = 0;     /* no trucation */
+
 /* Find the records we want, and add them to the result. */
 
 count = 0;
@@ -775,12 +790,14 @@ header->ancount = htons(count);
 /* If the AA bit should be set (as indicated by the AA prefix in the zone file),
 we are expected to return some records in the authoritative section. Bind9: If
 there is data in the answer section, the authoritative section contains the NS
-records, otherwise it contains the SOA record.  Currently we mimic this
-behaviour for the first case (there is some answer record).
+records, otherwise it contains the SOA record.  Mimic that.
 */
 
-if (aa)
-  find_records(f, zone, zone[0] == '.' ? zone+1 : zone, US"NS", 2, &pk, &count, NULL, NULL);
+if (strcmp(qtype, "SOA") != 0 && strcmp(qtype, "NS") != 0)
+  if (count)
+    find_records(f, zone, zone[0] == '.' ? zone+1 : zone, US"NS", 2, &pk, &count, NULL, NULL);
+  else
+    find_records(f, zone, zone[0] == '.' ? zone+1 : zone, US"SOA", 3, &pk, &count, NULL, NULL);
 header->nscount = htons(count - ntohs(header->ancount));
 
 /* There is no need to return any additional records because Exim no longer