chiark / gitweb /
client/adh-query.c: Surprising comma rather than semicolon.
[adns.git] / client / adnsresfilter.c
index d091def..7632ee3 100644 (file)
@@ -3,12 +3,11 @@
  * - filter which does resolving, not part of the library
  */
 /*
- *  This file is
- *    Copyright (C) 1999 Ian Jackson <ian@davenant.greenend.org.uk>
- *
- *  It is part of adns, which is
- *    Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
- *    Copyright (C) 1999 Tony Finch <dot@dotat.at>
+ *  This file is part of adns, which is
+ *    Copyright (C) 1997-2000,2003,2006  Ian Jackson
+ *    Copyright (C) 1999-2000,2003,2006  Tony Finch
+ *    Copyright (C) 1991 Massachusetts Institute of Technology
+ *  (See the file INSTALL for full details.)
  *  
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #include <assert.h>
 #include <ctype.h>
 
-#include <sys/fcntl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
 
-#include "adns.h"
 #include "config.h"
+#include "adns.h"
 #include "dlist.h"
 #include "tvarith.h"
+#include "client.h"
+
+#ifdef ADNS_REGRESS_TEST
+# include "hredirect.h"
+#endif
 
 struct outqueuenode {
   struct outqueuenode *next, *back;
-  void *buffer;
-  char *textp;
+  char *buffer, *textp;
   int textlen;
   struct timeval printbefore;
   struct treething *addr;
 };
 
-static int bracket, forever, timeout=10;
+static int bracket, forever, address;
+static unsigned long timeout= 1000;
 static adns_rrtype rrt= adns_r_ptr;
+static adns_initflags initflags= 0;
+static const char *config_text;
 
 static int outblocked, inputeof;
 static struct { struct outqueuenode *head, *tail; } outqueue;
@@ -83,8 +91,7 @@ static int nonblock(int fd, int isnonblock) {
   return 0;
 }
 
-static void quit(int exitstatus) NONRETURNING;
-static void quit(int exitstatus) {
+void quitnow(int exitstatus) {
   nonblock(0,0);
   nonblock(1,0);
   exit(exitstatus);
@@ -93,7 +100,7 @@ static void quit(int exitstatus) {
 static void sysfail(const char *what) NONRETURNING;
 static void sysfail(const char *what) {
   fprintf(stderr,"adnsresfilter: system call failed: %s: %s\n",what,strerror(errno));
-  quit(2);
+  quitnow(2);
 }
 
 static void *xmalloc(size_t sz) {
@@ -107,29 +114,37 @@ static void outputerr(void) { sysfail("write to stdout"); }
 
 static void usage(void) {
   if (printf("usage: adnsresfilter [<options ...>]\n"
-            "       adnsresfilter  -h|--help\n"
-            "options: -b|--brackets\n"
-            "         -w|--wait\n"
-            "         -t<timeout>|--timeout <timeout>\n"
-            "         -u|--unchecked\n")
+            "       adnsresfilter  -h|--help | --version\n"
+            "options: -t<milliseconds>|--timeout <milliseconds>\n"
+            "         -w|--wait        (always wait for queries to time out or fail)\n"
+            "         -b|--brackets    (require [...] around IP addresses)\n"
+            "         -a|--address     (always include [address] in output)\n"
+            "         -u|--unchecked   (do not forward map for checking)\n"
+            "         --config <text>  (use this instead of resolv.conf)\n"
+            "         --debug          (turn on adns resolver debugging)\n"
+            "Timeout is the maximum amount to delay any particular bit of output for.\n"
+            "Lookups will go on in the background.  Default timeout = 1000 (ms).\n")
       == EOF) outputerr();
+  if (fflush(stdout)) sysfail("flush stdout");
 }
 
 static void usageerr(const char *why) NONRETURNING;
 static void usageerr(const char *why) {
   fprintf(stderr,"adnsresfilter: bad usage: %s\n",why);
   usage();
-  quit(1);
+  quitnow(1);
 }
 
 static void adnsfail(const char *what, int e) NONRETURNING;
 static void adnsfail(const char *what, int e) {
   fprintf(stderr,"adnsresfilter: adns call failed: %s: %s\n",what,strerror(e));
-  quit(2);
+  quitnow(2);
 }
 
-static int comparer(const void *a, const void *b) {
-  return memcmp(a,b,4);
+static void settimeout(const char *arg) {
+  char *ep;
+  timeout= strtoul(arg,&ep,0);
+  if (*ep) usageerr("invalid timeout");
 }
 
 static void parseargs(const char *const *argv) {
@@ -139,31 +154,55 @@ static void parseargs(const char *const *argv) {
   while ((arg= *++argv)) {
     if (arg[0] != '-') usageerr("no non-option arguments are allowed");
     if (arg[1] == '-') {
-      if (!strcmp(arg,"--brackets")) {
+      if (!strcmp(arg,"--timeout")) {
+       if (!(arg= *++argv)) usageerr("--timeout needs a value");
+       settimeout(arg);
+       forever= 0;
+      } else if (!strcmp(arg,"--wait")) {
+       forever= 1;
+      } else if (!strcmp(arg,"--brackets")) {
        bracket= 1;
+      } else if (!strcmp(arg,"--address")) {
+       address= 1;
       } else if (!strcmp(arg,"--unchecked")) {
        rrt= adns_r_ptr_raw;
-      } else if (!strcmp(arg,"--wait")) {
-       forever= 1;
+      } else if (!strcmp(arg,"--config")) {
+       if (!(arg= *++argv)) usageerr("--config needs a value");
+       config_text= arg;
+      } else if (!strcmp(arg,"--debug")) {
+       initflags |= adns_if_debug;
       } else if (!strcmp(arg,"--help")) {
-       usage(); quit(0);
+       usage(); quitnow(0);
+      } else if (!strcmp(arg,"--version")) {
+       VERSION_PRINT_QUIT("adnsresfilter"); quitnow(0);
       } else {
        usageerr("unknown long option");
       }
     } else {
       while ((c= *++arg)) {
        switch (c) {
+       case 't':
+         if (*++arg) settimeout(arg);
+         else if ((arg= *++argv)) settimeout(arg);
+         else usageerr("-t needs a value");
+         forever= 0;
+         arg= "\0";
+         break;
+       case 'w':
+         forever= 1;
+         break;
        case 'b':
          bracket= 1;
          break;
+       case 'a':
+         address= 1;
+         break;
        case 'u':
          rrt= adns_r_ptr_raw;
          break;
-       case 'w':
-         forever= 1;
-         break;
        case 'h':
-         usage(); quit(0);
+         usage();
+         quitnow(0);
        default:
          usageerr("unknown short option");
        }
@@ -176,10 +215,11 @@ static void queueoutchar(int c) {
   struct outqueuenode *entry;
   
   entry= outqueue.tail;
-  if (!entry->back || entry->addr || entry->textlen >= peroutqueuenode) {
+  if (!entry || entry->addr ||
+      entry->textlen >= peroutqueuenode - (entry->textp - entry->buffer)) {
+    peroutqueuenode= !peroutqueuenode || !entry || entry->addr ? 128 : 
+      peroutqueuenode >= 1024 ? 4096 : peroutqueuenode<<2;
     entry= xmalloc(sizeof(*entry));
-    peroutqueuenode= !entry->back || entry->addr ? 32 : 
-      peroutqueuenode >= 1024 ? 2048 : peroutqueuenode<<1;
     entry->buffer= xmalloc(peroutqueuenode);
     entry->textp= entry->buffer;
     entry->textlen= 0;
@@ -187,12 +227,11 @@ static void queueoutchar(int c) {
     LIST_LINK_TAIL(outqueue,entry);
     outqueuelen++;
   }
-  *entry->textp++= c;
-  entry->textlen++;
+  entry->textp[entry->textlen++]= c;
 }
 
 static void queueoutstr(const char *str, int len) {
-  while (len > 0) queueoutchar(*str++);
+  while (len-- > 0) queueoutchar(*str++);
 }
 
 static void writestdout(struct outqueuenode *entry) {
@@ -205,7 +244,7 @@ static void writestdout(struct outqueuenode *entry) {
       if (errno == EAGAIN) { outblocked= 1; break; }
       sysfail("write stdout");
     }
-    assert(r < entry->textlen);
+    assert(r <= entry->textlen);
     entry->textp += r;
     entry->textlen -= r;
   }
@@ -218,10 +257,24 @@ static void writestdout(struct outqueuenode *entry) {
 }
 
 static void replacetextwithname(struct outqueuenode *entry) {
-  free(entry->buffer);
-  entry->buffer= 0;
-  entry->textp= entry->addr->ans->rrs.str[0];
-  entry->textlen= strlen(entry->textp);
+  char *name, *newbuf;
+  int namelen, newlen;
+
+  name= entry->addr->ans->rrs.str[0];
+  namelen= strlen(name);
+  if (!address) {
+    free(entry->buffer);
+    entry->buffer= 0;
+    entry->textp= name;
+    entry->textlen= namelen;
+  } else {
+    newlen= entry->textlen + namelen + (bracket ? 0 : 2);
+    newbuf= xmalloc(newlen + 1);
+    sprintf(newbuf, bracket ? "%s%.*s" : "%s[%.*s]", name, entry->textlen, entry->textp);
+    free(entry->buffer);
+    entry->buffer= entry->textp= newbuf;
+    entry->textlen= newlen;
+  }
 }
 
 static void checkadnsqueries(void) {
@@ -247,6 +300,10 @@ static void restartbuf(void) {
   inbuf= 0;
 }
 
+static int comparer(const void *a, const void *b) {
+  return memcmp(a,b,4);
+}
+
 static void procaddr(void) {
   struct treething *foundthing;
   void **searchfound;
@@ -265,6 +322,7 @@ static void procaddr(void) {
   foundthing= *searchfound;
 
   if (foundthing == newthing) {
+    newthing= 0;
     memcpy(&sa.sin_addr,bytes,4);
     r= adns_submit_reverse(ads, (const struct sockaddr*)&sa,
                           rrt,0,foundthing,&foundthing->qu);
@@ -276,6 +334,7 @@ static void procaddr(void) {
   memcpy(entry->textp,addrtextbuf,inbuf);
   entry->textlen= inbuf;
   entry->addr= foundthing;
+  entry->printbefore= printbefore;
   LIST_LINK_TAIL(outqueue,entry);
   outqueuelen++;
   inbuf= 0;
@@ -297,7 +356,7 @@ static void readstdin(void) {
     if (r != EINTR) sysfail("read stdin");
   }
   for (p=readbuf; r>0; r--,p++) {
-    c= *p++;
+    c= *p;
     if (cbyte==-1 && bracket && c=='[') {
       addrtextbuf[inbuf++]= c;
       startaddr();
@@ -327,18 +386,21 @@ static void readstdin(void) {
       if (!bracket && !isalnum(c)) startaddr();
     }
   }
-  if (cbyte==3 && inbyte>0 && !bracket) procaddr();
 }
 
 static void startup(void) {
   int r;
 
-  if (setvbuf(stdout,0,_IOLBF,0)) sysfail("setvbuf stdout");
   if (nonblock(0,1)) sysfail("set stdin to nonblocking mode");
   if (nonblock(1,1)) sysfail("set stdout to nonblocking mode");
   memset(&sa,0,sizeof(sa));
   sa.sin_family= AF_INET;
-  r= adns_init(&ads,0,0);  if (r) adnsfail("init",r);
+  if (config_text) {
+    r= adns_init_strcfg(&ads,initflags,stderr,config_text);
+  } else {
+    r= adns_init(&ads,initflags,0);
+  }
+  if (r) adnsfail("init",r);
   cbyte= -1;
   inbyte= -1;
   inbuf= 0;
@@ -362,7 +424,8 @@ int main(int argc, const char *const *argv) {
       if (!entry->addr) {
        writestdout(entry);
        continue;
-      } else if (entry->addr->ans) {
+      }
+      if (entry->addr->ans) {
        if (entry->addr->ans->nrrs) 
          replacetextwithname(entry);
        entry->addr= 0;
@@ -375,8 +438,8 @@ int main(int argc, const char *const *argv) {
        entry->addr= 0;
        continue;
       } else {
-       tvbuf.tv_sec= printbefore.tv_sec - now.tv_sec - 1;
-       tvbuf.tv_usec= printbefore.tv_usec - now.tv_usec + 1000000;
+       tvbuf.tv_sec= entry->printbefore.tv_sec - now.tv_sec - 1;
+       tvbuf.tv_usec= entry->printbefore.tv_usec - now.tv_usec + 1000000;
        tvbuf.tv_sec += tvbuf.tv_usec / 1000000;
        tvbuf.tv_usec %= 1000000;
        tv= &tvbuf;
@@ -385,7 +448,7 @@ int main(int argc, const char *const *argv) {
                        &tv,&tvbuf,&now);
     }
     if (outblocked) FD_SET(1,&writefds);
-    if (!inputeof && outqueuelen<1000) FD_SET(0,&readfds);
+    if (!inputeof && outqueuelen<1024) FD_SET(0,&readfds);
     
     r= select(maxfd,&readfds,&writefds,&exceptfds,tv);
     if (r < 0) { if (r == EINTR) continue; else sysfail("select"); }
@@ -404,9 +467,8 @@ int main(int argc, const char *const *argv) {
       outblocked= 0;
     }
   }
-  if (ferror(stdin) || fclose(stdin)) sysfail("read stdin");
-  if (fclose(stdout)) sysfail("close stdout");
   if (nonblock(0,0)) sysfail("un-nonblock stdin");
   if (nonblock(1,0)) sysfail("un-nonblock stdout");
+  adns_finish(ads);
   exit(0);
 }