and the domain is not found. It converts the the result to PASS_ON instead of
HOST_NOT_FOUND.
+Any DNS record line in a zone file can be prefixed with "DELAY=" and
+a number of milliseconds (followed by whitespace).
+
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>
+#include <signal.h>
#include <arpa/nameser.h>
#include <sys/types.h>
+#include <sys/time.h>
#include <dirent.h>
#define FALSE 0
{ US"A", ns_t_a },
{ US"NS", ns_t_ns },
{ US"CNAME", ns_t_cname },
-/* { US"SOA", ns_t_soa }, Not currently in use */
+ { US"SOA", ns_t_soa },
{ US"PTR", ns_t_ptr },
{ US"MX", ns_t_mx },
{ US"TXT", ns_t_txt },
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 *
+longfield(uschar ** pp, uschar * pk)
+{
+unsigned long value = 0;
+uschar * p = *pp;
+
+while (isdigit(*p)) value = value*10 + *p++ - '0';
+while (isspace(*p)) p++;
+*pp = p;
+*pk++ = (value >> 24) & 255;
+*pk++ = (value >> 16) & 255;
+*pk++ = (value >> 8) & 255;
+*pk++ = value & 255;
+return pk;
+}
+
+
+
+/*************************************************/
+
+static void
+milliwait(struct itimerval *itval)
+{
+sigset_t sigmask;
+sigset_t old_sigmask;
+
+if (itval->it_value.tv_usec < 100 && itval->it_value.tv_sec == 0)
+ return;
+(void)sigemptyset(&sigmask); /* Empty mask */
+(void)sigaddset(&sigmask, SIGALRM); /* Add SIGALRM */
+(void)sigprocmask(SIG_BLOCK, &sigmask, &old_sigmask); /* Block SIGALRM */
+(void)setitimer(ITIMER_REAL, itval, NULL); /* Start timer */
+(void)sigfillset(&sigmask); /* All signals */
+(void)sigdelset(&sigmask, SIGALRM); /* Remove SIGALRM */
+(void)sigsuspend(&sigmask); /* Until SIGALRM */
+(void)sigprocmask(SIG_SETMASK, &old_sigmask, NULL); /* Restore mask */
+}
+
+static void
+millisleep(int msec)
+{
+struct itimerval itval;
+itval.it_interval.tv_sec = 0;
+itval.it_interval.tv_usec = 0;
+itval.it_value.tv_sec = msec/1000;
+itval.it_value.tv_usec = (msec % 1000) * 1000;
+milliwait(&itval);
+}
/*************************************************
uschar *rdlptr;
uschar *p, *ep, *pp;
BOOL found_cname = FALSE;
- int i, plen, value;
+ int i, value;
int tvalue = typeptr->value;
int qtlen = qtypelen;
BOOL rr_sec = FALSE;
+ int delay = 0;
p = buffer;
while (isspace(*p)) p++;
*ep = 0;
p = buffer;
- if (Ustrncmp(p, US"DNSSEC ", 7) == 0) /* tagged as secure */
- {
- rr_sec = TRUE;
- p += 7;
- }
+ for (;;)
+ {
+ if (Ustrncmp(p, US"DNSSEC ", 7) == 0) /* tagged as secure */
+ {
+ rr_sec = TRUE;
+ p += 7;
+ }
+ else if (Ustrncmp(p, US"DELAY=", 6) == 0) /* delay beforee response */
+ {
+ for (p += 6; *p >= '0' && *p <= '9'; p++)
+ delay = delay*10 + *p - '0';
+ while (isspace(*p)) p++;
+ }
+ else
+ break;
+ }
if (!isspace(*p))
{
/* Found a relevant record */
+ if (delay)
+ millisleep(delay);
+
if (!rr_sec)
*dnssec = FALSE; /* cancel AD return */
switch (tvalue)
{
- case ns_t_soa: /* Not currently used */
- break;
+ case ns_t_soa:
+ p = strtok(p, " ");
+ ep = p + strlen(p);
+ if (ep[-1] != '.') sprintf(CS ep, "%s.", zone);
+ pk = packname(p, pk); /* primary ns */
+ p = strtok(NULL, " ");
+ pk = packname(p , pk); /* responsible mailbox */
+ *(p += strlen(p)) = ' ';
+ while (isspace(*p)) p++;
+ pk = longfield(&p, pk); /* serial */
+ pk = longfield(&p, pk); /* refresh */
+ pk = longfield(&p, pk); /* retry */
+ pk = longfield(&p, pk); /* expire */
+ pk = longfield(&p, pk); /* minimum */
+ break;
case ns_t_a:
- for (i = 0; i < 4; i++)
- {
- value = 0;
- while (isdigit(*p)) value = value*10 + *p++ - '0';
- *pk++ = value;
- p++;
- }
- break;
+ for (i = 0; i < 4; i++)
+ {
+ value = 0;
+ while (isdigit(*p)) value = value*10 + *p++ - '0';
+ *pk++ = value;
+ p++;
+ }
+ break;
/* The only occurrence of a double colon is for ::1 */
case ns_t_aaaa:
- if (Ustrcmp(p, "::1") == 0)
- {
- memset(pk, 0, 15);
- pk += 15;
- *pk++ = 1;
- }
- else for (i = 0; i < 8; i++)
- {
- value = 0;
- while (isxdigit(*p))
- {
- value = value * 16 + toupper(*p) - (isdigit(*p)? '0' : '7');
- p++;
- }
- *pk++ = (value >> 8) & 255;
- *pk++ = value & 255;
- p++;
- }
- break;
+ if (Ustrcmp(p, "::1") == 0)
+ {
+ memset(pk, 0, 15);
+ pk += 15;
+ *pk++ = 1;
+ }
+ else for (i = 0; i < 8; i++)
+ {
+ value = 0;
+ while (isxdigit(*p))
+ {
+ value = value * 16 + toupper(*p) - (isdigit(*p)? '0' : '7');
+ p++;
+ }
+ *pk++ = (value >> 8) & 255;
+ *pk++ = value & 255;
+ p++;
+ }
+ break;
case ns_t_mx:
- pk = shortfield(&p, pk);
- if (ep[-1] != '.') sprintf(ep, "%s.", zone);
- pk = packname(p, pk);
- plen = Ustrlen(p);
- break;
+ pk = shortfield(&p, pk);
+ if (ep[-1] != '.') sprintf(CS ep, "%s.", zone);
+ pk = packname(p, pk);
+ 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;
- break;
+ pp = pk++;
+ if (*p == '"') p++; /* Should always be the case */
+ while (*p != 0 && *p != '"') *pk++ = *p++;
+ *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))
+ 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))
*pk++ = value & 255;
}
- break;
+ break;
case ns_t_srv:
- for (i = 0; i < 3; i++)
- {
- value = 0;
- while (isdigit(*p)) value = value*10 + *p++ - '0';
- while (isspace(*p)) p++;
- *pk++ = (value >> 8) & 255;
- *pk++ = value & 255;
- }
+ for (i = 0; i < 3; i++)
+ {
+ value = 0;
+ while (isdigit(*p)) value = value*10 + *p++ - '0';
+ while (isspace(*p)) p++;
+ *pk++ = (value >> 8) & 255;
+ *pk++ = value & 255;
+ }
/* Fall through */
case ns_t_cname:
case ns_t_ns:
case ns_t_ptr:
- if (ep[-1] != '.') sprintf(ep, "%s.", zone);
- pk = packname(p, pk);
- plen = Ustrlen(p);
- break;
+ if (ep[-1] != '.') sprintf(CS ep, "%s.", zone);
+ pk = packname(p, pk);
+ break;
}
/* Fill in the length, and we are done with this RR */
}
+static void
+alarmfn(int sig)
+{
+}
/*************************************************
* Entry point and main program *
uschar *pk = packet;
BOOL dnssec;
+signal(SIGALRM, alarmfn);
+
if (argc != 4)
{
fprintf(stderr, "fakens: expected 3 arguments, received %d\n", argc-1);
/* 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));