ReactOS  0.4.13-dev-249-gcba1a2f
adnsresfilter.c
Go to the documentation of this file.
1 /*
2  * adnsresfilter.c
3  * - filter which does resolving, not part of the library
4  */
5 /*
6  * This file is
7  * Copyright (C) 1999-2000 Ian Jackson <ian@davenant.greenend.org.uk>
8  *
9  * It is part of adns, which is
10  * Copyright (C) 1997-2000 Ian Jackson <ian@davenant.greenend.org.uk>
11  * Copyright (C) 1999-2000 Tony Finch <dot@dotat.at>
12  *
13  * This program is free software; you can redistribute it and/or modify
14  * it under the terms of the GNU General Public License as published by
15  * the Free Software Foundation; either version 2, or (at your option)
16  * any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26  */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <errno.h>
32 #include <search.h>
33 #include <assert.h>
34 #include <ctype.h>
35 
36 #include <sys/types.h>
37 #include <unistd.h>
38 #include <fcntl.h>
39 
40 #include "config.h"
41 #include "adns.h"
42 #include "dlist.h"
43 #include "tvarith.h"
44 #include "client.h"
45 
46 #ifdef ADNS_REGRESS_TEST
47 # include "hredirect.h"
48 #endif
49 
50 struct outqueuenode {
51  struct outqueuenode *next, *back;
52  void *buffer;
53  char *textp;
54  int textlen;
56  struct treething *addr;
57 };
58 
59 static int bracket, forever, address;
60 static unsigned long timeout= 1000;
63 static const char *config_text;
64 
65 static int outblocked, inputeof;
66 static struct { struct outqueuenode *head, *tail; } outqueue;
68 
69 static struct sockaddr_in sa;
70 static adns_state ads;
71 
72 static char addrtextbuf[14];
73 static int cbyte, inbyte, inbuf;
74 static unsigned char bytes[4];
75 static struct timeval printbefore;
76 
77 struct treething {
78  unsigned char bytes[4];
81 };
82 
83 static struct treething *newthing;
84 static void *treeroot;
85 
86 static int nonblock(int fd, int isnonblock) {
87  int r;
88 
89  r= fcntl(fd,F_GETFL);
90  if (r==-1) return -1;
91  r= fcntl(fd,F_SETFL, isnonblock ? r|O_NONBLOCK : r&~O_NONBLOCK);
92  if (r==-1) return -1;
93  return 0;
94 }
95 
96 void quitnow(int exitstatus) {
97  nonblock(0,0);
98  nonblock(1,0);
99  exit(exitstatus);
100 }
101 
102 static void sysfail(const char *what) NONRETURNING;
103 static void sysfail(const char *what) {
104  fprintf(stderr,"adnsresfilter: system call failed: %s: %s\n",what,strerror(errno));
105  quitnow(2);
106 }
107 
108 static void *xmalloc(size_t sz) {
109  void *r;
110  r= malloc(sz); if (r) return r;
111  sysfail("malloc");
112 }
113 
114 static void outputerr(void) NONRETURNING;
115 static void outputerr(void) { sysfail("write to stdout"); }
116 
117 static void usage(void) {
118  if (printf("usage: adnsresfilter [<options ...>]\n"
119  " adnsresfilter -h|--help | --version\n"
120  "options: -t<milliseconds>|--timeout <milliseconds>\n"
121  " -w|--wait (always wait for queries to time out or fail)\n"
122  " -b|--brackets (require [...] around IP addresses)\n"
123  " -a|--address (always include [address] in output)\n"
124  " -u|--unchecked (do not forward map for checking)\n"
125  " --config <text> (use this instead of resolv.conf)\n"
126  " --debug (turn on adns resolver debugging)\n"
127  "Timeout is the maximum amount to delay any particular bit of output for.\n"
128  "Lookups will go on in the background. Default timeout = 1000 (ms).\n")
129  == EOF) outputerr();
130  if (fflush(stdout)) sysfail("flush stdout");
131 }
132 
133 static void usageerr(const char *why) NONRETURNING;
134 static void usageerr(const char *why) {
135  fprintf(stderr,"adnsresfilter: bad usage: %s\n",why);
136  usage();
137  quitnow(1);
138 }
139 
140 static void adnsfail(const char *what, int e) NONRETURNING;
141 static void adnsfail(const char *what, int e) {
142  fprintf(stderr,"adnsresfilter: adns call failed: %s: %s\n",what,strerror(e));
143  quitnow(2);
144 }
145 
146 static void settimeout(const char *arg) {
147  char *ep;
148  timeout= strtoul(arg,&ep,0);
149  if (*ep) usageerr("invalid timeout");
150 }
151 
152 static void parseargs(const char *const *argv) {
153  const char *arg;
154  int c;
155 
156  while ((arg= *++argv)) {
157  if (arg[0] != '-') usageerr("no non-option arguments are allowed");
158  if (arg[1] == '-') {
159  if (!strcmp(arg,"--timeout")) {
160  if (!(arg= *++argv)) usageerr("--timeout needs a value");
161  settimeout(arg);
162  forever= 0;
163  } else if (!strcmp(arg,"--wait")) {
164  forever= 1;
165  } else if (!strcmp(arg,"--brackets")) {
166  bracket= 1;
167  } else if (!strcmp(arg,"--address")) {
168  address= 1;
169  } else if (!strcmp(arg,"--unchecked")) {
171  } else if (!strcmp(arg,"--config")) {
172  if (!(arg= *++argv)) usageerr("--config needs a value");
173  config_text= arg;
174  } else if (!strcmp(arg,"--debug")) {
176  } else if (!strcmp(arg,"--help")) {
177  usage(); quitnow(0);
178  } else if (!strcmp(arg,"--version")) {
179  VERSION_PRINT_QUIT("adnsresfilter"); quitnow(0);
180  } else {
181  usageerr("unknown long option");
182  }
183  } else {
184  while ((c= *++arg)) {
185  switch (c) {
186  case 't':
187  if (*++arg) settimeout(arg);
188  else if ((arg= *++argv)) settimeout(arg);
189  else usageerr("-t needs a value");
190  forever= 0;
191  arg= "\0";
192  break;
193  case 'w':
194  forever= 1;
195  break;
196  case 'b':
197  bracket= 1;
198  break;
199  case 'a':
200  address= 1;
201  break;
202  case 'u':
204  break;
205  case 'h':
206  usage();
207  quitnow(0);
208  default:
209  usageerr("unknown short option");
210  }
211  }
212  }
213  }
214 }
215 
216 static void queueoutchar(int c) {
217  struct outqueuenode *entry;
218 
219  entry= outqueue.tail;
220  if (!entry || entry->addr || entry->textlen >= peroutqueuenode) {
221  peroutqueuenode= !peroutqueuenode || !entry || entry->addr ? 128 :
222  peroutqueuenode >= 1024 ? 4096 : peroutqueuenode<<2;
223  entry= xmalloc(sizeof(*entry));
224  entry->buffer= xmalloc(peroutqueuenode);
225  entry->textp= entry->buffer;
226  entry->textlen= 0;
227  entry->addr= 0;
229  outqueuelen++;
230  }
231  entry->textp[entry->textlen++]= c;
232 }
233 
234 static void queueoutstr(const char *str, int len) {
235  while (len-- > 0) queueoutchar(*str++);
236 }
237 
238 static void writestdout(struct outqueuenode *entry) {
239  int r;
240 
241  while (entry->textlen) {
242  r= write(1, entry->textp, entry->textlen);
243  if (r < 0) {
244  if (errno == EINTR) continue;
245  if (errno == EAGAIN) { outblocked= 1; break; }
246  sysfail("write stdout");
247  }
249  entry->textp += r;
250  entry->textlen -= r;
251  }
252  if (!entry->textlen) {
254  free(entry->buffer);
255  free(entry);
256  outqueuelen--;
257  }
258 }
259 
260 static void replacetextwithname(struct outqueuenode *entry) {
261  char *name, *newbuf;
262  int namelen, newlen;
263 
264  name= entry->addr->ans->rrs.str[0];
265  namelen= strlen(name);
266  if (!address) {
267  free(entry->buffer);
268  entry->buffer= 0;
269  entry->textp= name;
270  entry->textlen= namelen;
271  } else {
272  newlen= entry->textlen + namelen + (bracket ? 0 : 2);
273  newbuf= xmalloc(newlen + 1);
274  sprintf(newbuf, bracket ? "%s%.*s" : "%s[%.*s]", name, entry->textlen, entry->textp);
275  free(entry->buffer);
276  entry->buffer= entry->textp= newbuf;
277  entry->textlen= newlen;
278  }
279 }
280 
281 static void checkadnsqueries(void) {
282  adns_query qu;
283  adns_answer *ans;
284  void *context;
285  struct treething *foundthing;
286  int r;
287 
288  for (;;) {
289  qu= 0; context= 0; ans= 0;
290  r= adns_check(ads,&qu,&ans,&context);
291  if (r == ESRCH || r == EAGAIN) break;
292  assert(!r);
293  foundthing= context;
294  foundthing->ans= ans;
295  foundthing->qu= 0;
296  }
297 }
298 
299 static void restartbuf(void) {
301  inbuf= 0;
302 }
303 
304 static int comparer(const void *a, const void *b) {
305  return memcmp(a,b,4);
306 }
307 
308 static void procaddr(void) {
309  struct treething *foundthing;
310  void **searchfound;
311  struct outqueuenode *entry;
312  int r;
313 
314  if (!newthing) {
315  newthing= xmalloc(sizeof(struct treething));
316  newthing->qu= 0;
317  newthing->ans= 0;
318  }
319 
320  memcpy(newthing->bytes,bytes,4);
321  searchfound= tsearch(newthing,&treeroot,comparer);
322  if (!searchfound) sysfail("tsearch");
323  foundthing= *searchfound;
324 
325  if (foundthing == newthing) {
326  newthing= 0;
327  memcpy(&sa.sin_addr,bytes,4);
328  r= adns_submit_reverse(ads, (const struct sockaddr*)&sa,
329  rrt,0,foundthing,&foundthing->qu);
330  if (r) adnsfail("submit",r);
331  }
332  entry= xmalloc(sizeof(*entry));
333  entry->buffer= xmalloc(inbuf);
334  entry->textp= entry->buffer;
335  memcpy(entry->textp,addrtextbuf,inbuf);
336  entry->textlen= inbuf;
337  entry->addr= foundthing;
338  entry->printbefore= printbefore;
340  outqueuelen++;
341  inbuf= 0;
342  cbyte= -1;
343 }
344 
345 static void startaddr(void) {
346  bytes[cbyte=0]= 0;
347  inbyte= 0;
348 }
349 
350 static void readstdin(void) {
351  char readbuf[512], *p;
352  int r, c, nbyte;
353 
354  while ((r= read(0,readbuf,sizeof(readbuf))) <= 0) {
355  if (r == 0) { inputeof= 1; return; }
356  if (r == EAGAIN) return;
357  if (r != EINTR) sysfail("read stdin");
358  }
359  for (p=readbuf; r>0; r--,p++) {
360  c= *p;
361  if (cbyte==-1 && bracket && c=='[') {
362  addrtextbuf[inbuf++]= c;
363  startaddr();
364  } else if (cbyte==-1 && !bracket && !isalnum(c)) {
365  queueoutchar(c);
366  startaddr();
367  } else if (cbyte>=0 && inbyte<3 && c>='0' && c<='9' &&
368  (nbyte= bytes[cbyte]*10 + (c-'0')) <= 255) {
369  bytes[cbyte]= nbyte;
370  addrtextbuf[inbuf++]= c;
371  inbyte++;
372  } else if (cbyte>=0 && cbyte<3 && inbyte>0 && c=='.') {
373  bytes[++cbyte]= 0;
374  addrtextbuf[inbuf++]= c;
375  inbyte= 0;
376  } else if (cbyte==3 && inbyte>0 && bracket && c==']') {
377  addrtextbuf[inbuf++]= c;
378  procaddr();
379  } else if (cbyte==3 && inbyte>0 && !bracket && !isalnum(c)) {
380  procaddr();
381  queueoutchar(c);
382  startaddr();
383  } else {
384  restartbuf();
385  queueoutchar(c);
386  cbyte= -1;
387  if (!bracket && !isalnum(c)) startaddr();
388  }
389  }
390 }
391 
392 static void startup(void) {
393  int r;
394 
395  if (nonblock(0,1)) sysfail("set stdin to nonblocking mode");
396  if (nonblock(1,1)) sysfail("set stdout to nonblocking mode");
397  memset(&sa,0,sizeof(sa));
398  sa.sin_family= AF_INET;
399  if (config_text) {
401  } else {
402  r= adns_init(&ads,initflags,0);
403  }
404  if (r) adnsfail("init",r);
405  cbyte= -1;
406  inbyte= -1;
407  inbuf= 0;
408  if (!bracket) startaddr();
409 }
410 
411 int main(int argc, const char *const *argv) {
412  int r, maxfd;
413  fd_set readfds, writefds, exceptfds;
414  struct outqueuenode *entry;
415  struct timeval *tv, tvbuf, now;
416 
417  parseargs(argv);
418  startup();
419 
420  while (!inputeof || outqueue.head) {
421  maxfd= 2;
422  tv= 0;
423  FD_ZERO(&readfds); FD_ZERO(&writefds); FD_ZERO(&exceptfds);
424  if ((entry= outqueue.head) && !outblocked) {
425  if (!entry->addr) {
427  continue;
428  }
429  if (entry->addr->ans) {
430  if (entry->addr->ans->nrrs)
432  entry->addr= 0;
433  continue;
434  }
435  r= gettimeofday(&now,0); if (r) sysfail("gettimeofday");
436  if (forever) {
437  tv= 0;
438  } else if (!timercmp(&now,&entry->printbefore,<)) {
439  entry->addr= 0;
440  continue;
441  } else {
442  tvbuf.tv_sec= entry->printbefore.tv_sec - now.tv_sec - 1;
443  tvbuf.tv_usec= entry->printbefore.tv_usec - now.tv_usec + 1000000;
444  tvbuf.tv_sec += tvbuf.tv_usec / 1000000;
445  tvbuf.tv_usec %= 1000000;
446  tv= &tvbuf;
447  }
448  adns_beforeselect(ads,&maxfd,&readfds,&writefds,&exceptfds,
449  &tv,&tvbuf,&now);
450  }
451  if (outblocked) FD_SET(1,&writefds);
452  if (!inputeof && outqueuelen<1024) FD_SET(0,&readfds);
453 
455  r= select(maxfd,&readfds,&writefds,&exceptfds,tv);
457  if (r < 0) { if (r == EINTR) continue; else sysfail("select"); }
458 
459  r= gettimeofday(&now,0); if (r) sysfail("gettimeofday");
460  adns_afterselect(ads,maxfd,&readfds,&writefds,&exceptfds,&now);
462 
463  if (FD_ISSET(0,&readfds)) {
464  if (!forever) {
465  printbefore= now;
467  }
468  readstdin();
469  } else if (FD_ISSET(1,&writefds)) {
470  outblocked= 0;
471  }
472  }
473  if (nonblock(0,0)) sysfail("un-nonblock stdin");
474  if (nonblock(1,0)) sysfail("un-nonblock stdout");
475  adns_finish(ads);
476  exit(0);
477 }
static adns_state ads
Definition: adnsresfilter.c:70
static void readstdin(void)
Definition: winsock.h:66
adns_initflags
Definition: adns.h:87
static int argc
Definition: ServiceArgs.c:12
struct timeval printbefore
Definition: adnsresfilter.c:55
static void * xmalloc(size_t sz)
UINT32 strtoul(const char *String, char **Terminator, UINT32 Base)
Definition: utclib.c:696
static void queueoutstr(const char *str, int len)
int memcmp(void *Buffer1, void *Buffer2, ACPI_SIZE Count)
Definition: utclib.c:112
struct outqueuenode * tail
Definition: adnsresfilter.c:66
ADNS_API void adns_beforeselect(adns_state ads, int *maxfd, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval **tv_mod, struct timeval *tv_buf, const struct timeval *now)
Definition: event.c:562
adns_answer * ans
Definition: adnsresfilter.c:80
Definition: http.c:6587
struct outqueuenode * head
Definition: adnsresfilter.c:66
ACPI_SIZE strlen(const char *String)
Definition: utclib.c:269
int main(int argc, const char *const *argv)
ADNS_API void adns_finish(adns_state ads)
Definition: setup.c:650
GLdouble GLdouble GLdouble r
Definition: gl.h:2055
adns_rrtype
Definition: adns.h:113
ADNS_API int adns_submit_reverse(adns_state ads, const struct sockaddr *addr, adns_rrtype type, adns_queryflags flags, void *context, adns_query *query_r)
Definition: query.c:304
#define O_NONBLOCK
Definition: port.h:158
#define free
Definition: debug_ros.c:5
#define EINTR
Definition: acclib.h:80
struct outqueuenode * back
Definition: adnsresfilter.c:51
static void writestdout(struct outqueuenode *entry)
unsigned long tv_sec
Definition: linux.h:1738
static void outputerr(void)
static int inbuf
Definition: adnsresfilter.c:73
#define assert(x)
Definition: debug.h:53
static int fd
Definition: io.c:51
adns_query qu
Definition: adnsresfilter.c:79
struct outqueuenode * next
Definition: adnsresfilter.c:51
void * arg
Definition: msvc.h:12
Definition: dhcpd.h:245
int errno
static void usage(void)
static void * treeroot
Definition: adnsresfilter.c:84
#define FD_ZERO(set)
Definition: winsock.h:96
_Check_return_ _CRTIMP int __cdecl isalnum(_In_ int _C)
#define argv
Definition: mplay32.c:18
static void adnsfail(const char *what, int e) NONRETURNING
#define FD_SET(fd, set)
Definition: winsock.h:89
GLint namelen
Definition: glext.h:7232
const char * strerror(int err)
Definition: compat_str.c:23
static void procaddr(void)
FILE * stdout
ADNS_API void adns_afterselect(adns_state ads, int maxfd, const fd_set *readfds, const fd_set *writefds, const fd_set *exceptfds, const struct timeval *now)
Definition: event.c:595
#define ESRCH
Definition: errno.h:9
static int inbyte
Definition: adnsresfilter.c:73
#define sprintf(buf, format,...)
Definition: sprintf.c:55
#define write
Definition: acwin.h:73
#define gettimeofday(tv, tz)
Definition: adns_win32.h:159
#define LIST_LINK_TAIL(list, node)
Definition: dlist.h:51
static unsigned char bytes[4]
Definition: adnsresfilter.c:74
#define FD_ISSET(fd, set)
Definition: winsock.h:100
INT WSAAPI select(IN INT s, IN OUT LPFD_SET readfds, IN OUT LPFD_SET writefds, IN OUT LPFD_SET exceptfds, IN CONST struct timeval *timeout)
Definition: select.c:41
_Check_return_opt_ _CRTIMP int __cdecl fprintf(_Inout_ FILE *_File, _In_z_ _Printf_format_string_ const char *_Format,...)
#define e
Definition: ke_i.h:82
time_t now
Definition: finger.c:65
void quitnow(int exitstatus)
Definition: adnsresfilter.c:96
const WCHAR * str
unsigned long tv_usec
Definition: linux.h:1739
static int outblocked
Definition: adnsresfilter.c:65
#define LIST_UNLINK(list, node)
Definition: dlist.h:50
Definition: arc.h:35
static struct treething * newthing
Definition: adnsresfilter.c:83
static int outqueuelen
Definition: adnsresfilter.c:67
#define ADNS_CLEAR_ERRNO
Definition: adns_win32.h:108
static void timevaladd(struct timeval *tv_io, long ms)
Definition: tvarith.h:31
static int cbyte
Definition: adnsresfilter.c:73
ADNS_API int adns_init_strcfg(adns_state *newstate_r, adns_initflags flags, FILE *diagfile, const char *configtext)
Definition: setup.c:629
static void checkadnsqueries(void)
static void sysfail(const char *what) NONRETURNING
static adns_rrtype rrt
Definition: adnsresfilter.c:61
GLboolean GLboolean GLboolean b
Definition: glext.h:6204
static int bracket
Definition: adnsresfilter.c:59
const GLubyte * c
Definition: glext.h:8905
GLuint address
Definition: glext.h:9393
static void parseargs(const char *const *argv)
static int nonblock(int fd, int isnonblock)
Definition: adnsresfilter.c:86
#define VERSION_PRINT_QUIT(program)
Definition: client.h:42
#define NONRETURNING
Definition: acconfig.h:94
static void restartbuf(void)
static int address
Definition: adnsresfilter.c:59
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
GLenum GLsizei len
Definition: glext.h:6722
static void startaddr(void)
static void startup(void)
static struct timeval printbefore
Definition: adnsresfilter.c:75
struct treething * addr
Definition: adnsresfilter.c:56
static char addrtextbuf[14]
Definition: adnsresfilter.c:72
_Check_return_opt_ _CRTIMP int __cdecl fflush(_Inout_opt_ FILE *_File)
ADNS_API int adns_init(adns_state *newstate_r, adns_initflags flags, FILE *diagfile)
Definition: setup.c:568
static const char * config_text
Definition: adnsresfilter.c:63
#define ADNS_CAPTURE_ERRNO
Definition: adns_win32.h:107
static adns_initflags initflags
Definition: adnsresfilter.c:62
ADNS_API int adns_check(adns_state ads, adns_query *query_io, adns_answer **answer_r, void **context_r)
Definition: event.c:731
#define EOF
Definition: stdio.h:24
#define timercmp(tvp, uvp, cmp)
Definition: rdesktop.h:184
Definition: name.c:36
#define c
Definition: ke_i.h:80
FILE * stderr
#define AF_INET
Definition: tcpip.h:117
int strcmp(const char *String1, const char *String2)
Definition: utclib.c:469
static int peroutqueuenode
Definition: adnsresfilter.c:67
static void usageerr(const char *why) NONRETURNING
unsigned char bytes[4]
Definition: adnsresfilter.c:78
#define malloc
Definition: debug_ros.c:4
static int comparer(const void *a, const void *b)
static void queueoutchar(int c)
static void settimeout(const char *arg)
GLboolean GLboolean GLboolean GLboolean a
Definition: glext.h:6204
void exit(int exitcode)
Definition: _exit.c:33
GLfloat GLfloat p
Definition: glext.h:8902
static void replacetextwithname(struct outqueuenode *entry)
static int inputeof
Definition: adnsresfilter.c:65
#define memset(x, y, z)
Definition: compat.h:39
static struct @3820 outqueue
static int forever
Definition: adnsresfilter.c:59
static struct sockaddr_in sa
Definition: adnsresfilter.c:69
_CRTIMP int __cdecl read(_In_ int _FileHandle, _Out_writes_bytes_(_MaxCharCount) void *_DstBuf, _In_ unsigned int _MaxCharCount)
#define printf
Definition: config.h:203
GLuint const GLchar * name
Definition: glext.h:6031