X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~ianmdlvl/git?p=adns.git;a=blobdiff_plain;f=client%2Fadnsresfilter.c;h=7632ee3f59b83c34bc9f24786226678909b40cfd;hp=d091def4323124ae6c1c400d56205e3e68812058;hb=75884a1571b83afd1bf1ba0e9546521594280254;hpb=2953d358511ac5d196362f6b339c010d4e9cae3e diff --git a/client/adnsresfilter.c b/client/adnsresfilter.c index d091def..7632ee3 100644 --- a/client/adnsresfilter.c +++ b/client/adnsresfilter.c @@ -3,12 +3,11 @@ * - filter which does resolving, not part of the library */ /* - * This file is - * Copyright (C) 1999 Ian Jackson - * - * It is part of adns, which is - * Copyright (C) 1997-1999 Ian Jackson - * Copyright (C) 1999 Tony Finch + * 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 @@ -33,24 +32,33 @@ #include #include -#include +#include +#include +#include -#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 []\n" - " adnsresfilter -h|--help\n" - "options: -b|--brackets\n" - " -w|--wait\n" - " -t|--timeout \n" - " -u|--unchecked\n") + " adnsresfilter -h|--help | --version\n" + "options: -t|--timeout \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 (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); }