-/* $Cambridge: exim/test/src/fakens.c,v 1.3 2006/11/07 14:13:19 ph10 Exp $ */
-
/*************************************************
* fakens - A Fake Nameserver Program *
*************************************************/
PASS ON NOT FOUND
and the domain is not found. It converts the the result to PASS_ON instead of
-HOST_NOT_FOUND. */
+HOST_NOT_FOUND.
+
+Any DNS record line in a zone file can be prefixed with "DNSSEC" and
+at least one space; if all the records found by a lookup are marked
+as such then the response will have the "AD" bit set. */
#include <ctype.h>
#include <stdarg.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <errno.h>
know about AAAA and SRV at all. */
#ifndef ns_t_a
-#define ns_t_a T_A
-#define ns_t_ns T_NS
-#define ns_t_cname T_CNAME
-#define ns_t_soa T_SOA
-#define ns_t_ptr T_PTR
-#define ns_t_mx T_MX
-#define ns_t_txt T_TXT
-#define ns_t_aaaa T_AAAA
-#define ns_t_srv T_SRV
-#ifndef T_AAAA
-#define T_AAAA 28
-#endif
-#ifndef T_SRV
-#define T_SRV 33
-#endif
+# define ns_t_a T_A
+# define ns_t_ns T_NS
+# define ns_t_cname T_CNAME
+# define ns_t_soa T_SOA
+# define ns_t_ptr T_PTR
+# define ns_t_mx T_MX
+# define ns_t_txt T_TXT
+# define ns_t_aaaa T_AAAA
+# define ns_t_srv T_SRV
+# define ns_t_tlsa T_TLSA
+# ifndef T_AAAA
+# define T_AAAA 28
+# endif
+# ifndef T_SRV
+# define T_SRV 33
+# endif
+# ifndef T_TLSA
+# define T_TLSA 52
+# endif
#endif
static tlist type_list[] = {
{ US"TXT", ns_t_txt },
{ US"AAAA", ns_t_aaaa },
{ US"SRV", ns_t_srv },
+ { US"TLSA", ns_t_tlsa },
{ NULL, 0 }
};
char buffer[256];
va_list ap;
va_start(ap, format);
-vsprintf(buffer, format, ap);
+vsprintf(buffer, CS format, ap);
va_end(ap);
yield = (uschar *)malloc(Ustrlen(buffer) + 1);
Ustrcpy(yield, buffer);
return pk;
}
+uschar *
+bytefield(uschar ** pp, uschar * pk)
+{
+unsigned value = 0;
+uschar * p = *pp;
+
+while (isdigit(*p)) value = value*10 + *p++ - '0';
+while (isspace(*p)) p++;
+*pp = p;
+*pk++ = value & 255;
+return pk;
+}
+
+uschar *
+shortfield(uschar ** pp, uschar * pk)
+{
+unsigned value = 0;
+uschar * p = *pp;
+
+while (isdigit(*p)) value = value*10 + *p++ - '0';
+while (isspace(*p)) p++;
+*pp = p;
+*pk++ = (value >> 8) & 255;
+*pk++ = value & 255;
+return pk;
+}
+
/*************************************************
static int
find_records(FILE *f, uschar *zone, uschar *domain, uschar *qtype,
- int qtypelen, uschar **pkptr, int *countptr)
+ int qtypelen, uschar **pkptr, int *countptr, BOOL * dnssec)
{
int yield = HOST_NOT_FOUND;
int domainlen = Ustrlen(domain);
rrdomain[0] = 0; /* No previous domain */
(void)fseek(f, 0, SEEK_SET); /* Start again at the beginning */
+*dnssec = TRUE; /* cancelled by first nonsecure rec found */
+
/* Scan for RRs */
while (fgets(CS buffer, sizeof(buffer), f) != NULL)
int i, plen, value;
int tvalue = typeptr->value;
int qtlen = qtypelen;
+ BOOL rr_sec = FALSE;
p = buffer;
while (isspace(*p)) p++;
if (*p == 0 || *p == ';') continue;
- if (Ustrncmp(p, "PASS ON NOT FOUND", 17) == 0)
+ if (Ustrncmp(p, US"PASS ON NOT FOUND", 17) == 0)
{
pass_on_not_found = TRUE;
continue;
*ep = 0;
p = buffer;
+ if (Ustrncmp(p, US"DNSSEC ", 7) == 0) /* tagged as secure */
+ {
+ rr_sec = TRUE;
+ p += 7;
+ }
+
if (!isspace(*p))
{
uschar *pp = rrdomain;
/* Found a relevant record */
+ if (!rr_sec)
+ *dnssec = FALSE; /* cancel AD return */
+
yield = 0;
*countptr = *countptr + 1;
break;
case ns_t_mx:
- value = 0;
- while (isdigit(*p)) value = value*10 + *p++ - '0';
- while (isspace(*p)) p++;
- *pk++ = (value >> 8) & 255;
- *pk++ = value & 255;
- if (ep[-1] != '.') sprintf(ep, "%s.", zone);
+ pk = shortfield(&p, pk);
+ if (ep[-1] != '.') sprintf(CS ep, "%s.", zone);
pk = packname(p, pk);
plen = Ustrlen(p);
break;
*pp = pk - pp - 1;
break;
+ case ns_t_tlsa:
+ pk = bytefield(&p, pk); /* usage */
+ pk = bytefield(&p, pk); /* selector */
+ pk = bytefield(&p, pk); /* match type */
+ while (isxdigit(*p))
+ {
+ value = toupper(*p) - (isdigit(*p) ? '0' : '7') << 4;
+ if (isxdigit(*++p))
+ {
+ value |= toupper(*p) - (isdigit(*p) ? '0' : '7');
+ p++;
+ }
+ *pk++ = value & 255;
+ }
+
+ break;
+
case ns_t_srv:
for (i = 0; i < 3; i++)
{
case ns_t_cname:
case ns_t_ns:
case ns_t_ptr:
- if (ep[-1] != '.') sprintf(ep, "%s.", zone);
+ if (ep[-1] != '.') sprintf(CS ep, "%s.", zone);
pk = packname(p, pk);
plen = Ustrlen(p);
break;
uschar qtype[12];
uschar packet[512];
uschar *pk = packet;
+BOOL dnssec;
if (argc != 4)
{
/* Find the zones */
-(void)sprintf(buffer, "%s/../dnszones", argv[1]);
+(void)sprintf(CS buffer, "%s/../dnszones", argv[1]);
d = opendir(CCS buffer);
if (d == NULL)
while ((de = readdir(d)) != NULL)
{
- uschar *name = de->d_name;
+ uschar *name = US de->d_name;
if (Ustrncmp(name, "qualify.", 8) == 0)
{
- qualify = fcopystring("%s", name + 7);
+ qualify = fcopystring(US "%s", name + 7);
continue;
}
if (Ustrncmp(name, "db.", 3) != 0) continue;
if (Ustrncmp(name + 3, "ip4.", 4) == 0)
- zones[zonecount].zone = fcopystring("%s.in-addr.arpa", name + 6);
+ zones[zonecount].zone = fcopystring(US "%s.in-addr.arpa", name + 6);
else if (Ustrncmp(name + 3, "ip6.", 4) == 0)
- zones[zonecount].zone = fcopystring("%s.ip6.arpa", name + 6);
+ zones[zonecount].zone = fcopystring(US "%s.ip6.arpa", name + 6);
else
- zones[zonecount].zone = fcopystring("%s", name + 2);
- zones[zonecount++].zonefile = fcopystring("%s", name);
+ zones[zonecount].zone = fcopystring(US "%s", name + 2);
+ zones[zonecount++].zonefile = fcopystring(US "%s", name);
}
(void)closedir(d);
return PASS_ON;
}
-(void)sprintf(buffer, "%s/../dnszones/%s", argv[1], zonefile);
+(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
/* Open the zone file. */
-f = fopen(buffer, "r");
+f = fopen(CS buffer, "r");
if (f == NULL)
{
fprintf(stderr, "fakens: failed to open %s: %s\n", buffer, strerror(errno));
/* Find the records we want, and add them to the result. */
count = 0;
-yield = find_records(f, zone, domain, qtype, qtypelen, &pk, &count);
+yield = find_records(f, zone, domain, qtype, qtypelen, &pk, &count, &dnssec);
if (yield == NO_RECOVERY) goto END_OFF;
packet[6] = (count >> 8) & 255;
packet[10] = 0;
packet[11] = 0;
+if (dnssec)
+ ((HEADER *)packet)->ad = 1;
+
/* Close the zone file, write the result, and return. */
END_OFF:
return yield;
}
+/* vi: aw ai sw=2
+*/
/* End of fakens.c */