Log lengthy DNS lookups. Bug 514
[exim.git] / test / src / fakens.c
index fd3604a3c6c5e2e50617db08b1178a536066fce2..1228c70f9ab16ccec003f994681e03caa7dc3624 100644 (file)
@@ -50,6 +50,9 @@ line in the zone file contains exactly this:
 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. */
@@ -57,11 +60,13 @@ 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 <arpa/nameser.h>
 #include <sys/types.h>
+#include <sys/time.h>
 #include <dirent.h>
 
 #define FALSE         0
@@ -156,7 +161,7 @@ uschar *yield;
 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);
@@ -223,6 +228,38 @@ 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);
+}
+
+
 /*************************************************
 *              Scan file for RRs                 *
 *************************************************/
@@ -282,6 +319,7 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
   int tvalue = typeptr->value;
   int qtlen = qtypelen;
   BOOL rr_sec = FALSE;
+  int delay = 0;
 
   p = buffer;
   while (isspace(*p)) p++;
@@ -298,11 +336,22 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
   *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))
     {
@@ -356,6 +405,9 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
 
   /* Found a relevant record */
 
+  if (delay)
+    millisleep(delay);
+
   if (!rr_sec)
     *dnssec = FALSE;                   /* cancel AD return */
 
@@ -420,7 +472,7 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
 
     case ns_t_mx:
     pk = shortfield(&p, pk);
-    if (ep[-1] != '.') sprintf(ep, "%s.", zone);
+    if (ep[-1] != '.') sprintf(CS ep, "%s.", zone);
     pk = packname(p, pk);
     plen = Ustrlen(p);
     break;
@@ -464,7 +516,7 @@ while (fgets(CS buffer, sizeof(buffer), f) != NULL)
     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;
@@ -481,6 +533,10 @@ return (yield == HOST_NOT_FOUND && pass_on_not_found)? PASS_ON : yield;
 }
 
 
+static  void
+alarmfn(int sig)
+{
+}
 
 /*************************************************
 *           Entry point and main program         *
@@ -507,6 +563,8 @@ uschar packet[512];
 uschar *pk = packet;
 BOOL dnssec;
 
+signal(SIGALRM, alarmfn);
+
 if (argc != 4)
   {
   fprintf(stderr, "fakens: expected 3 arguments, received %d\n", argc-1);
@@ -515,7 +573,7 @@ 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)
@@ -527,20 +585,20 @@ 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);
 
@@ -586,7 +644,7 @@ if (zonefile == NULL)
   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
@@ -597,7 +655,7 @@ pk += 12;
 
 /* 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));