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.
qtypelen the length of qtype
pkptr points to the output buffer pointer; this is updated
countptr points to the record count; this is updated
- dnssec points to the AD flag indicator; this is updated
- aa points to the AA flag indicator; this is updated
+ dnssec_p points to the AD flag indicator; this is updated
+ aa_p points to the AA flag indicator; this is updated
Returns: 0 on success, else HOST_NOT_FOUND or NO_DATA or NO_RECOVERY or
PASS_ON - the latter if a "PASS ON NOT FOUND" line is seen
static int
find_records(FILE *f, uschar *zone, uschar *domain, uschar *qtype,
- int qtypelen, uschar **pkptr, int *countptr, BOOL * dnssec, BOOL * aa)
+ int qtypelen, uschar **pkptr, int *countptr, BOOL * dnssec_p, BOOL * aa_p)
{
int yield = HOST_NOT_FOUND;
int domainlen = Ustrlen(domain);
BOOL pass_on_not_found = FALSE;
tlist *typeptr;
uschar *pk = *pkptr;
-uschar buffer[256];
+uschar buffer[512];
uschar rrdomain[256];
uschar RRdomain[256];
int qtlen = qtypelen;
BOOL rr_sec = FALSE;
BOOL rr_aa = FALSE;
+ BOOL rr_ignore = FALSE;
int delay = 0;
uint ttl = DEFAULT_TTL;
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;
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 */
+ if (dnssec_p) *dnssec_p = TRUE; /* cancelled by first nonsecure rec found */
+ if (aa_p) *aa_p = TRUE; /* cancelled by first non-aa rec found */
}
/* Compare RR types; a CNAME record is always returned */
if (delay)
millisleep(delay);
- if (dnssec && !rr_sec)
- *dnssec = FALSE; /* cancel AD return */
+ if (dnssec_p && !rr_sec)
+ *dnssec_p = FALSE; /* cancel AD return */
+
+ if (aa_p && !rr_aa)
+ *aa_p = FALSE; /* cancel AA return */
- if (aa && !rr_aa)
- *aa = FALSE; /* cancel AA return */
+ if (rr_ignore) continue;
yield = 0;
*countptr = *countptr + 1;
break;
case ns_t_txt:
- pp = pk++;
- if (*p == '"') p++; /* Should always be the case */
- while (*p != 0 && *p != '"') *pk++ = *p++;
- *pp = pk - pp - 1;
+ while (*p)
+ {
+ pp = pk++; /* Skip the size byte in output */
+ if (*p == '"') p++; /* Should always be the case */
+ while (*p && *p != '"') *pk++ = *p++;
+ *pp = pk - pp - 1; /* fill in the size */
+ p++; /* skip the closing doublequote */
+ while (isspace(*p)) p++; /* next chunk start */
+ }
break;
case ns_t_tlsa:
uschar packet[2048 * 32 + 32];
HEADER *header = (HEADER *)packet;
uschar *pk = packet;
-BOOL dnssec;
-BOOL aa;
+BOOL dnssec = FALSE;
+BOOL aa = FALSE;
signal(SIGALRM, alarmfn);
(void)sprintf(CS buffer, "%s/dnszones", argv[1]);
-d = opendir(CCS buffer);
-if (d == NULL)
+if (!(d = opendir(CCS buffer)))
{
fprintf(stderr, "fakens: failed to opendir %s: %s\n", buffer,
strerror(errno));
return NO_RECOVERY;
}
-while ((de = readdir(d)) != NULL)
+while ((de = readdir(d)))
{
uschar *name = US de->d_name;
if (Ustrncmp(name, "qualify.", 8) == 0)
(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 truncation */
+
/* Find the records we want, and add them to the result. */
count = 0;
/* 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