ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

adnsresfilter.c
Go to the documentation of this file.
00001 /*
00002  * adnsresfilter.c
00003  * - filter which does resolving, not part of the library
00004  */
00005 /*
00006  *  This file is
00007  *    Copyright (C) 1999-2000 Ian Jackson <ian@davenant.greenend.org.uk>
00008  *
00009  *  It is part of adns, which is
00010  *    Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
00011  *    Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
00012  *
00013  *  This program is free software; you can redistribute it and/or modify
00014  *  it under the terms of the GNU General Public License as published by
00015  *  the Free Software Foundation; either version 2, or (at your option)
00016  *  any later version.
00017  *
00018  *  This program is distributed in the hope that it will be useful,
00019  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00020  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00021  *  GNU General Public License for more details.
00022  *
00023  *  You should have received a copy of the GNU General Public License
00024  *  along with this program; if not, write to the Free Software Foundation,
00025  *  Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00026  */
00027 
00028 #include <stdio.h>
00029 #include <stdlib.h>
00030 #include <string.h>
00031 #include <errno.h>
00032 #include <search.h>
00033 #include <assert.h>
00034 #include <ctype.h>
00035 
00036 #include <sys/types.h>
00037 #include <unistd.h>
00038 #include <fcntl.h>
00039 
00040 #include "config.h"
00041 #include "adns.h"
00042 #include "dlist.h"
00043 #include "tvarith.h"
00044 #include "client.h"
00045 
00046 #ifdef ADNS_REGRESS_TEST
00047 # include "hredirect.h"
00048 #endif
00049 
00050 struct outqueuenode {
00051   struct outqueuenode *next, *back;
00052   void *buffer;
00053   char *textp;
00054   int textlen;
00055   struct timeval printbefore;
00056   struct treething *addr;
00057 };
00058 
00059 static int bracket, forever, address;
00060 static unsigned long timeout= 1000;
00061 static adns_rrtype rrt= adns_r_ptr;
00062 static adns_initflags initflags= 0;
00063 static const char *config_text;
00064 
00065 static int outblocked, inputeof;
00066 static struct { struct outqueuenode *head, *tail; } outqueue;
00067 static int peroutqueuenode, outqueuelen;
00068 
00069 static struct sockaddr_in sa;
00070 static adns_state ads;
00071 
00072 static char addrtextbuf[14];
00073 static int cbyte, inbyte, inbuf;
00074 static unsigned char bytes[4];
00075 static struct timeval printbefore;
00076 
00077 struct treething {
00078   unsigned char bytes[4];
00079   adns_query qu;
00080   adns_answer *ans;
00081 };
00082 
00083 static struct treething *newthing;
00084 static void *treeroot;
00085 
00086 static int nonblock(int fd, int isnonblock) {
00087   int r;
00088 
00089   r= fcntl(fd,F_GETFL);
00090   if (r==-1) return -1;
00091   r= fcntl(fd,F_SETFL, isnonblock ? r|O_NONBLOCK : r&~O_NONBLOCK);
00092   if (r==-1) return -1;
00093   return 0;
00094 }
00095 
00096 void quitnow(int exitstatus) {
00097   nonblock(0,0);
00098   nonblock(1,0);
00099   exit(exitstatus);
00100 }
00101 
00102 static void sysfail(const char *what) NONRETURNING;
00103 static void sysfail(const char *what) {
00104   fprintf(stderr,"adnsresfilter: system call failed: %s: %s\n",what,strerror(errno));
00105   quitnow(2);
00106 }
00107 
00108 static void *xmalloc(size_t sz) {
00109   void *r;
00110   r= malloc(sz);  if (r) return r;
00111   sysfail("malloc");
00112 }
00113 
00114 static void outputerr(void) NONRETURNING;
00115 static void outputerr(void) { sysfail("write to stdout"); }
00116 
00117 static void usage(void) {
00118   if (printf("usage: adnsresfilter [<options ...>]\n"
00119          "       adnsresfilter  -h|--help | --version\n"
00120          "options: -t<milliseconds>|--timeout <milliseconds>\n"
00121          "         -w|--wait        (always wait for queries to time out or fail)\n"
00122          "         -b|--brackets    (require [...] around IP addresses)\n"
00123          "         -a|--address     (always include [address] in output)\n"
00124          "         -u|--unchecked   (do not forward map for checking)\n"
00125          "         --config <text>  (use this instead of resolv.conf)\n"
00126          "         --debug          (turn on adns resolver debugging)\n"
00127          "Timeout is the maximum amount to delay any particular bit of output for.\n"
00128          "Lookups will go on in the background.  Default timeout = 1000 (ms).\n")
00129       == EOF) outputerr();
00130   if (fflush(stdout)) sysfail("flush stdout");
00131 }
00132 
00133 static void usageerr(const char *why) NONRETURNING;
00134 static void usageerr(const char *why) {
00135   fprintf(stderr,"adnsresfilter: bad usage: %s\n",why);
00136   usage();
00137   quitnow(1);
00138 }
00139 
00140 static void adnsfail(const char *what, int e) NONRETURNING;
00141 static void adnsfail(const char *what, int e) {
00142   fprintf(stderr,"adnsresfilter: adns call failed: %s: %s\n",what,strerror(e));
00143   quitnow(2);
00144 }
00145 
00146 static void settimeout(const char *arg) {
00147   char *ep;
00148   timeout= strtoul(arg,&ep,0);
00149   if (*ep) usageerr("invalid timeout");
00150 }
00151 
00152 static void parseargs(const char *const *argv) {
00153   const char *arg;
00154   int c;
00155 
00156   while ((arg= *++argv)) {
00157     if (arg[0] != '-') usageerr("no non-option arguments are allowed");
00158     if (arg[1] == '-') {
00159       if (!strcmp(arg,"--timeout")) {
00160     if (!(arg= *++argv)) usageerr("--timeout needs a value");
00161     settimeout(arg);
00162     forever= 0;
00163       } else if (!strcmp(arg,"--wait")) {
00164     forever= 1;
00165       } else if (!strcmp(arg,"--brackets")) {
00166     bracket= 1;
00167       } else if (!strcmp(arg,"--address")) {
00168     address= 1;
00169       } else if (!strcmp(arg,"--unchecked")) {
00170     rrt= adns_r_ptr_raw;
00171       } else if (!strcmp(arg,"--config")) {
00172     if (!(arg= *++argv)) usageerr("--config needs a value");
00173     config_text= arg;
00174       } else if (!strcmp(arg,"--debug")) {
00175     initflags |= adns_if_debug;
00176       } else if (!strcmp(arg,"--help")) {
00177     usage(); quitnow(0);
00178       } else if (!strcmp(arg,"--version")) {
00179     VERSION_PRINT_QUIT("adnsresfilter"); quitnow(0);
00180       } else {
00181     usageerr("unknown long option");
00182       }
00183     } else {
00184       while ((c= *++arg)) {
00185     switch (c) {
00186     case 't':
00187       if (*++arg) settimeout(arg);
00188       else if ((arg= *++argv)) settimeout(arg);
00189       else usageerr("-t needs a value");
00190       forever= 0;
00191       arg= "\0";
00192       break;
00193     case 'w':
00194       forever= 1;
00195       break;
00196     case 'b':
00197       bracket= 1;
00198       break;
00199     case 'a':
00200       address= 1;
00201       break;
00202     case 'u':
00203       rrt= adns_r_ptr_raw;
00204       break;
00205     case 'h':
00206       usage();
00207       quitnow(0);
00208     default:
00209       usageerr("unknown short option");
00210     }
00211       }
00212     }
00213   }
00214 }
00215 
00216 static void queueoutchar(int c) {
00217   struct outqueuenode *entry;
00218 
00219   entry= outqueue.tail;
00220   if (!entry || entry->addr || entry->textlen >= peroutqueuenode) {
00221     peroutqueuenode= !peroutqueuenode || !entry || entry->addr ? 128 :
00222       peroutqueuenode >= 1024 ? 4096 : peroutqueuenode<<2;
00223     entry= xmalloc(sizeof(*entry));
00224     entry->buffer= xmalloc(peroutqueuenode);
00225     entry->textp= entry->buffer;
00226     entry->textlen= 0;
00227     entry->addr= 0;
00228     LIST_LINK_TAIL(outqueue,entry);
00229     outqueuelen++;
00230   }
00231   entry->textp[entry->textlen++]= c;
00232 }
00233 
00234 static void queueoutstr(const char *str, int len) {
00235   while (len-- > 0) queueoutchar(*str++);
00236 }
00237 
00238 static void writestdout(struct outqueuenode *entry) {
00239   int r;
00240 
00241   while (entry->textlen) {
00242     r= write(1, entry->textp, entry->textlen);
00243     if (r < 0) {
00244       if (errno == EINTR) continue;
00245       if (errno == EAGAIN) { outblocked= 1; break; }
00246       sysfail("write stdout");
00247     }
00248     assert(r <= entry->textlen);
00249     entry->textp += r;
00250     entry->textlen -= r;
00251   }
00252   if (!entry->textlen) {
00253     LIST_UNLINK(outqueue,entry);
00254     free(entry->buffer);
00255     free(entry);
00256     outqueuelen--;
00257   }
00258 }
00259 
00260 static void replacetextwithname(struct outqueuenode *entry) {
00261   char *name, *newbuf;
00262   int namelen, newlen;
00263 
00264   name= entry->addr->ans->rrs.str[0];
00265   namelen= strlen(name);
00266   if (!address) {
00267     free(entry->buffer);
00268     entry->buffer= 0;
00269     entry->textp= name;
00270     entry->textlen= namelen;
00271   } else {
00272     newlen= entry->textlen + namelen + (bracket ? 0 : 2);
00273     newbuf= xmalloc(newlen + 1);
00274     sprintf(newbuf, bracket ? "%s%.*s" : "%s[%.*s]", name, entry->textlen, entry->textp);
00275     free(entry->buffer);
00276     entry->buffer= entry->textp= newbuf;
00277     entry->textlen= newlen;
00278   }
00279 }
00280 
00281 static void checkadnsqueries(void) {
00282   adns_query qu;
00283   adns_answer *ans;
00284   void *context;
00285   struct treething *foundthing;
00286   int r;
00287 
00288   for (;;) {
00289     qu= 0; context= 0; ans= 0;
00290     r= adns_check(ads,&qu,&ans,&context);
00291     if (r == ESRCH || r == EAGAIN) break;
00292     assert(!r);
00293     foundthing= context;
00294     foundthing->ans= ans;
00295     foundthing->qu= 0;
00296   }
00297 }
00298 
00299 static void restartbuf(void) {
00300   if (inbuf>0) queueoutstr(addrtextbuf,inbuf);
00301   inbuf= 0;
00302 }
00303 
00304 static int comparer(const void *a, const void *b) {
00305   return memcmp(a,b,4);
00306 }
00307 
00308 static void procaddr(void) {
00309   struct treething *foundthing;
00310   void **searchfound;
00311   struct outqueuenode *entry;
00312   int r;
00313 
00314   if (!newthing) {
00315     newthing= xmalloc(sizeof(struct treething));
00316     newthing->qu= 0;
00317     newthing->ans= 0;
00318   }
00319 
00320   memcpy(newthing->bytes,bytes,4);
00321   searchfound= tsearch(newthing,&treeroot,comparer);
00322   if (!searchfound) sysfail("tsearch");
00323   foundthing= *searchfound;
00324 
00325   if (foundthing == newthing) {
00326     newthing= 0;
00327     memcpy(&sa.sin_addr,bytes,4);
00328     r= adns_submit_reverse(ads, (const struct sockaddr*)&sa,
00329                rrt,0,foundthing,&foundthing->qu);
00330     if (r) adnsfail("submit",r);
00331   }
00332   entry= xmalloc(sizeof(*entry));
00333   entry->buffer= xmalloc(inbuf);
00334   entry->textp= entry->buffer;
00335   memcpy(entry->textp,addrtextbuf,inbuf);
00336   entry->textlen= inbuf;
00337   entry->addr= foundthing;
00338   entry->printbefore= printbefore;
00339   LIST_LINK_TAIL(outqueue,entry);
00340   outqueuelen++;
00341   inbuf= 0;
00342   cbyte= -1;
00343 }
00344 
00345 static void startaddr(void) {
00346   bytes[cbyte=0]= 0;
00347   inbyte= 0;
00348 }
00349 
00350 static void readstdin(void) {
00351   char readbuf[512], *p;
00352   int r, c, nbyte;
00353 
00354   while ((r= read(0,readbuf,sizeof(readbuf))) <= 0) {
00355     if (r == 0) { inputeof= 1; return; }
00356     if (r == EAGAIN) return;
00357     if (r != EINTR) sysfail("read stdin");
00358   }
00359   for (p=readbuf; r>0; r--,p++) {
00360     c= *p;
00361     if (cbyte==-1 && bracket && c=='[') {
00362       addrtextbuf[inbuf++]= c;
00363       startaddr();
00364     } else if (cbyte==-1 && !bracket && !isalnum(c)) {
00365       queueoutchar(c);
00366       startaddr();
00367     } else if (cbyte>=0 && inbyte<3 && c>='0' && c<='9' &&
00368            (nbyte= bytes[cbyte]*10 + (c-'0')) <= 255) {
00369       bytes[cbyte]= nbyte;
00370       addrtextbuf[inbuf++]= c;
00371       inbyte++;
00372     } else if (cbyte>=0 && cbyte<3 && inbyte>0 && c=='.') {
00373       bytes[++cbyte]= 0;
00374       addrtextbuf[inbuf++]= c;
00375       inbyte= 0;
00376     } else if (cbyte==3 && inbyte>0 && bracket && c==']') {
00377       addrtextbuf[inbuf++]= c;
00378       procaddr();
00379     } else if (cbyte==3 && inbyte>0 && !bracket && !isalnum(c)) {
00380       procaddr();
00381       queueoutchar(c);
00382       startaddr();
00383     } else {
00384       restartbuf();
00385       queueoutchar(c);
00386       cbyte= -1;
00387       if (!bracket && !isalnum(c)) startaddr();
00388     }
00389   }
00390 }
00391 
00392 static void startup(void) {
00393   int r;
00394 
00395   if (nonblock(0,1)) sysfail("set stdin to nonblocking mode");
00396   if (nonblock(1,1)) sysfail("set stdout to nonblocking mode");
00397   memset(&sa,0,sizeof(sa));
00398   sa.sin_family= AF_INET;
00399   if (config_text) {
00400     r= adns_init_strcfg(&ads,initflags,stderr,config_text);
00401   } else {
00402     r= adns_init(&ads,initflags,0);
00403   }
00404   if (r) adnsfail("init",r);
00405   cbyte= -1;
00406   inbyte= -1;
00407   inbuf= 0;
00408   if (!bracket) startaddr();
00409 }
00410 
00411 int main(int argc, const char *const *argv) {
00412   int r, maxfd;
00413   fd_set readfds, writefds, exceptfds;
00414   struct outqueuenode *entry;
00415   struct timeval *tv, tvbuf, now;
00416 
00417   parseargs(argv);
00418   startup();
00419 
00420   while (!inputeof || outqueue.head) {
00421     maxfd= 2;
00422     tv= 0;
00423     FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
00424     if ((entry= outqueue.head) && !outblocked) {
00425       if (!entry->addr) {
00426     writestdout(entry);
00427     continue;
00428       }
00429       if (entry->addr->ans) {
00430     if (entry->addr->ans->nrrs)
00431       replacetextwithname(entry);
00432     entry->addr= 0;
00433     continue;
00434       }
00435       r= gettimeofday(&now,0);  if (r) sysfail("gettimeofday");
00436       if (forever) {
00437     tv= 0;
00438       } else if (!timercmp(&now,&entry->printbefore,<)) {
00439     entry->addr= 0;
00440     continue;
00441       } else {
00442     tvbuf.tv_sec= entry->printbefore.tv_sec - now.tv_sec - 1;
00443     tvbuf.tv_usec= entry->printbefore.tv_usec - now.tv_usec + 1000000;
00444     tvbuf.tv_sec += tvbuf.tv_usec / 1000000;
00445     tvbuf.tv_usec %= 1000000;
00446     tv= &tvbuf;
00447       }
00448       adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,
00449             &tv,&tvbuf,&now);
00450     }
00451     if (outblocked) FD_SET(1,&writefds);
00452     if (!inputeof && outqueuelen<1024) FD_SET(0,&readfds);
00453 
00454     ADNS_CLEAR_ERRNO;
00455     r= select(maxfd,&readfds,&writefds,&exceptfds,tv);
00456     ADNS_CAPTURE_ERRNO;
00457     if (r < 0) { if (r == EINTR) continue; else sysfail("select"); }
00458 
00459     r= gettimeofday(&now,0);  if (r) sysfail("gettimeofday");
00460     adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,&now);
00461     checkadnsqueries();
00462 
00463     if (FD_ISSET(0,&readfds)) {
00464       if (!forever) {
00465     printbefore= now;
00466     timevaladd(&printbefore,timeout);
00467       }
00468       readstdin();
00469     } else if (FD_ISSET(1,&writefds)) {
00470       outblocked= 0;
00471     }
00472   }
00473   if (nonblock(0,0)) sysfail("un-nonblock stdin");
00474   if (nonblock(1,0)) sysfail("un-nonblock stdout");
00475   adns_finish(ads);
00476   exit(0);
00477 }

Generated on Sat May 26 2012 04:32:16 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.