* - 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;
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);
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) {
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) {
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");
}
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;
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) {
if (errno == EAGAIN) { outblocked= 1; break; }
sysfail("write stdout");
}
- assert(r < entry->textlen);
+ assert(r <= entry->textlen);
entry->textp += r;
entry->textlen -= r;
}
}
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) {
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;
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);
memcpy(entry->textp,addrtextbuf,inbuf);
entry->textlen= inbuf;
entry->addr= foundthing;
+ entry->printbefore= printbefore;
LIST_LINK_TAIL(outqueue,entry);
outqueuelen++;
inbuf= 0;
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();
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;
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;
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;
&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"); }
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);
}