Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenadnsresfilter.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
1.7.6.1
|