summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--doc/dnsfunneld.html10
-rw-r--r--src/dnsfunnel/dnsfunneld.c35
-rw-r--r--src/dnsfunnel/dnsfunneld_answer.c15
3 files changed, 36 insertions, 24 deletions
diff --git a/doc/dnsfunneld.html b/doc/dnsfunneld.html
index 5181db1..7fde21f 100644
--- a/doc/dnsfunneld.html
+++ b/doc/dnsfunneld.html
@@ -29,7 +29,7 @@ queries, the responses, or both.
 <h2> Interface </h2>
 
 <pre>
-     dnsfunneld [ -v <em>verbosity</em> ] [ -1 ] [ -U | -u <em>uid</em> -g <em>gid</em> ] [ -i <em>ip</em>:<em>port</em> ] [ -R <em>root</em> ] [ -b <em>bufsize</em> ] [ -T | -t ] [ -N | -n ]
+     dnsfunneld [ -v <em>verbosity</em> ] [ -1 ] [ -U | -u <em>uid</em> -g <em>gid</em> ] [ -i <em>ip</em>:<em>port</em> ] [ -R <em>root</em> ] [ -b <em>bufsize</em> ] [ -t <em>globaltimeout</em> ] [ -X | -x ] [ -N | -n ]
 </pre>
 
 <ul>
@@ -97,6 +97,10 @@ to <tt>-R</tt>. </li>
  <li> <tt>-b&nbsp;<em>bufsize</em></tt>&nbsp;: try and reserve a kernel buffer
 size of <em>bufsize</em> bytes for the socket. The default is whatever the
 default is for your kernel. </li>
+ <li> <tt>-t&nbsp;<em>globaltimeout</em></tt>&nbsp;: maximum resolution time.
+If a query takes more than <em>globaltimeout</em> milliseconds to resolve,
+abandon it and return a SERVFAIL to the client. Default is 0, meaning infinite:
+no global timeout is set. </li>
 </ul>
 
 <p>
@@ -105,9 +109,9 @@ features. See below for the detail of operations.
 </p>
 
 <ul>
- <li> <tt>-T</tt>&nbsp;: Do not activate truncation of responses. This is
+ <li> <tt>-X</tt>&nbsp;: Do not activate truncation of responses. This is
 the default. </li>
- <li> <tt>-t</tt>&nbsp;: If a DNS response is bigger than 510 bytes,
+ <li> <tt>-x</tt>&nbsp;: If a DNS response is bigger than 510 bytes,
 truncate its last resource records until it fits into 510 bytes and can
 be sent in a UDP packet. </li>
  <li> <tt>-N</tt>&nbsp;: Do not activate NXDOMAIN workaround. This is the
diff --git a/src/dnsfunnel/dnsfunneld.c b/src/dnsfunnel/dnsfunneld.c
index d65cb7c..48965f1 100644
--- a/src/dnsfunnel/dnsfunneld.c
+++ b/src/dnsfunnel/dnsfunneld.c
@@ -36,13 +36,13 @@
 
 #include "dnsfunneld.h"
 
-#define USAGE "dnsfunneld [ -v verbosity ] [ -1 ] [ -U | -u uid -g gid ] [ -i ip:port ] [ -R root ] [ -b bufsize ] [ -T | -t ] [ -N | -n ]"
+#define USAGE "dnsfunneld [ -v verbosity ] [ -1 ] [ -U | -u uid -g gid ] [ -i ip:port ] [ -R root ] [ -b bufsize ] [ -t globaltimeout ] [ -X | -x ] [ -N | -n ]"
 #define dieusage() strerr_dieusage(100, USAGE)
 
 #define DNSFUNNELD_INPUT_MAX 64
 
 unsigned int verbosity = 1 ;
-static tain_t globaltto = TAIN_INFINITE_RELATIVE ;
+static tain_t globaltto ;
 static int cont = 1 ;
 static s6dns_ip46list_t cachelist ;
 static uint32_t ops = 0 ;
@@ -169,12 +169,13 @@ int main (int argc, char const *const *argv)
     int fd ;
     char ip[4] ;
     size_t pos ;
+    unsigned int t = 0 ;
     uint16_t port ;
     subgetopt_t l = SUBGETOPT_ZERO ;
 
     for (;;)
     {
-      int opt = subgetopt_r(argc, argv, "v:1Uu:g:i:R:b:TtNn", &l) ;
+      int opt = subgetopt_r(argc, argv, "v:1Uu:g:i:R:b:t:XxNn", &l) ;
       if (opt == -1) break ;
       switch (opt)
       {
@@ -186,8 +187,9 @@ int main (int argc, char const *const *argv)
         case 'i' : ipport = l.arg ; break ;
         case 'R' : root = l.arg ; break ;
         case 'b' : if (!uint0_scan(l.arg, &bufsize)) dieusage() ; break ;
-        case 'T' : ops &= ~1 ; break ;
-        case 't' : ops |= 1 ; break ;
+        case 't' : if (!uint0_scan(l.arg, &t)) dieusage() ; break ;
+        case 'X' : ops &= ~1 ; break ;
+        case 'x' : ops |= 1 ; break ;
         case 'N' : ops &= ~2 ; break ;
         case 'n' : ops |= 2 ; break ;
         default : dieusage() ;
@@ -195,6 +197,8 @@ int main (int argc, char const *const *argv)
     }
     argc -= l.ind ; argv += l.ind ;
 
+    if (t) tain_from_millisecs(&globaltto, t) ;
+    else globaltto = tain_infinite_relative ;
     pos = ip4_scan(ipport, ip) ;
     if (!pos) dieusage() ;
     if (ipport[pos] != ':') dieusage() ;
@@ -352,17 +356,20 @@ int main (int argc, char const *const *argv)
     {
       dfquery_t *q = QUERY(i) ;
       uint32_t k = q->next ;
-      int r = s6dns_engine_event_g(&q->dt) ;
-      if (r)
+      if (x[q->xindex].events && x[q->xindex].revents)
       {
-        if (r > 0) query_process_response_success(ops, q) ;
-        else query_process_response_failure(ops, q) ;
-        QUERY(j)->next = k ;
-        if (r > 0) s6dns_engine_free(&q->dt) ;
-        else stralloc_free(&q->dt.sa) ;
-        gensetdyn_delete(&queries, i) ;
+        int r = s6dns_engine_event_g(&q->dt) ;
+        if (r)
+        {
+          if (r > 0) query_process_response_success(ops, q) ;
+          else query_process_response_failure(ops, q) ;
+          QUERY(j)->next = k ;
+          if (r > 0) s6dns_engine_free(&q->dt) ;
+          else stralloc_free(&q->dt.sa) ;
+          gensetdyn_delete(&queries, i) ;
+        }
+        else j = i ;
       }
-      else j = i ;
       i = k ;
     }
 
diff --git a/src/dnsfunnel/dnsfunneld_answer.c b/src/dnsfunnel/dnsfunneld_answer.c
index a6ee526..c06637f 100644
--- a/src/dnsfunnel/dnsfunneld_answer.c
+++ b/src/dnsfunnel/dnsfunneld_answer.c
@@ -20,16 +20,15 @@ struct dfanswer_s
 {
   char buf[512] ;
   char ip[4] ;
-  uint16_t len ;
   uint16_t port ;
 } ;
-#define DFANSWER_ZERO { .buf = { 0 }, .ip = "\0\0\0", .len = 0, .port = 0 }
+#define DFANSWER_ZERO { .buf = { 0 }, .ip = "\0\0\0", .port = 0 }
 
 static genqdyn dfanswers = GENQDYN_INIT(dfanswer_t, 1, 8) ;
 
 size_t dfanswer_pending ()
 {
-  return genqdyn_n(&dfanswers) ;
+  return (dfanswers.queue.len - dfanswers.head) / dfanswers.esize ;
 }
 
 static void dfanswer_push (char const *s, size_t len, uint32_t ip, uint16_t port)
@@ -41,9 +40,9 @@ static void dfanswer_push (char const *s, size_t len, uint32_t ip, uint16_t port
   }
   else
   {
-    dfanswer_t ans = { .len = len, .port = port } ;
-    uint16_pack_big(ans.buf, ans.len) ;
-    memcpy(ans.buf, s+2, len) ;
+    dfanswer_t ans = { .port = port } ;
+    uint16_pack_big(ans.buf, len) ;
+    memcpy(ans.buf + 2, s+2, len) ;
     uint32_pack_big(ans.ip, ip) ;
     if (!genqdyn_push(&dfanswers, &ans))
       strerr_diefu1sys(111, "queue answer to client") ;
@@ -55,7 +54,9 @@ int dfanswer_flush ()
   while (dfanswer_pending())
   {
     dfanswer_t *ans = GENQDYN_PEEK(dfanswer_t, &dfanswers) ;
-    if (socket_send4(0, ans->buf, ans->len, ans->ip, ans->port) < 0)
+    uint16_t len ;
+    uint16_unpack_big(ans->buf, &len) ;
+    if (socket_send4(0, ans->buf, len, ans->ip, ans->port) < 0)
       return error_isagain(errno) ? (errno = 0, 0) : -1 ;
     genqdyn_pop(&dfanswers) ;
   }