3 * - filter which does resolving, not part of the library
6 * This file is part of adns, which is
7 * Copyright (C) 1997-2000,2003,2006,2014 Ian Jackson
8 * Copyright (C) 1999-2000,2003,2006 Tony Finch
9 * Copyright (C) 1991 Massachusetts Institute of Technology
10 * (See the file INSTALL for full details.)
12 * This program is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 3, or (at your option)
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software Foundation.
34 #include <sys/types.h>
44 #ifdef ADNS_REGRESS_TEST
45 # include "hredirect.h"
49 struct outqueuenode
*next
, *back
;
52 struct timeval printbefore
;
53 struct treething
*addr
;
56 static int bracket
, forever
, address
;
57 static unsigned long timeout
= 1000;
58 static adns_rrtype rrt
= adns_r_ptr
;
59 static adns_initflags initflags
= 0;
60 static const char *config_text
;
62 static int outblocked
, inputeof
;
63 static struct { struct outqueuenode
*head
, *tail
; } outqueue
;
64 static int peroutqueuenode
, outqueuelen
;
66 static struct sockaddr_in sa
;
67 static adns_state ads
;
69 static char addrtextbuf
[14];
70 static int cbyte
, inbyte
, inbuf
;
71 static unsigned char bytes
[4];
72 static struct timeval printbefore
;
75 unsigned char bytes
[4];
80 static struct treething
*newthing
;
81 static void *treeroot
;
83 static int nonblock(int fd
, int isnonblock
) {
88 r
= fcntl(fd
,F_SETFL
, isnonblock ? r
|O_NONBLOCK
: r
&~O_NONBLOCK
);
93 void quitnow(int exitstatus
) {
99 static void sysfail(const char *what
) NONRETURNING
;
100 static void sysfail(const char *what
) {
101 fprintf(stderr
,"adnsresfilter: system call failed: %s: %s\n",what
,strerror(errno
));
105 static void *xmalloc(size_t sz
) {
107 r
= malloc(sz
); if (r
) return r
;
111 static void outputerr(void) NONRETURNING
;
112 static void outputerr(void) { sysfail("write to stdout"); }
114 static void usage(void) {
115 if (printf("usage: adnsresfilter [<options ...>]\n"
116 " adnsresfilter -h|--help | --version\n"
117 "options: -t<milliseconds>|--timeout <milliseconds>\n"
118 " -w|--wait (always wait for queries to time out or fail)\n"
119 " -b|--brackets (require [...] around IP addresses)\n"
120 " -a|--address (always include [address] in output)\n"
121 " -u|--unchecked (do not forward map for checking)\n"
122 " --config <text> (use this instead of resolv.conf)\n"
123 " --debug (turn on adns resolver debugging)\n"
124 "Timeout is the maximum amount to delay any particular bit of output for.\n"
125 "Lookups will go on in the background. Default timeout = 1000 (ms).\n")
127 if (fflush(stdout
)) sysfail("flush stdout");
130 static void usageerr(const char *why
) NONRETURNING
;
131 static void usageerr(const char *why
) {
132 fprintf(stderr
,"adnsresfilter: bad usage: %s\n",why
);
137 static void adnsfail(const char *what
, int e
) NONRETURNING
;
138 static void adnsfail(const char *what
, int e
) {
139 fprintf(stderr
,"adnsresfilter: adns call failed: %s: %s\n",what
,strerror(e
));
143 static void settimeout(const char *arg
) {
145 timeout
= strtoul(arg
,&ep
,0);
146 if (*ep
) usageerr("invalid timeout");
149 static void parseargs(const char *const *argv
) {
153 while ((arg
= *++argv
)) {
154 if (arg
[0] != '-') usageerr("no non-option arguments are allowed");
156 if (!strcmp(arg
,"--timeout")) {
157 if (!(arg
= *++argv
)) usageerr("--timeout needs a value");
160 } else if (!strcmp(arg
,"--wait")) {
162 } else if (!strcmp(arg
,"--brackets")) {
164 } else if (!strcmp(arg
,"--address")) {
166 } else if (!strcmp(arg
,"--unchecked")) {
168 } else if (!strcmp(arg
,"--config")) {
169 if (!(arg
= *++argv
)) usageerr("--config needs a value");
171 } else if (!strcmp(arg
,"--debug")) {
172 initflags
|= adns_if_debug
;
173 } else if (!strcmp(arg
,"--help")) {
175 } else if (!strcmp(arg
,"--version")) {
176 VERSION_PRINT_QUIT("adnsresfilter"); quitnow(0);
178 usageerr("unknown long option");
181 while ((c
= *++arg
)) {
184 if (*++arg
) settimeout(arg
);
185 else if ((arg
= *++argv
)) settimeout(arg
);
186 else usageerr("-t needs a value");
206 usageerr("unknown short option");
213 static void queueoutchar(int c
) {
214 struct outqueuenode
*entry
;
216 entry
= outqueue
.tail
;
217 if (!entry
|| entry
->addr
||
218 entry
->textlen
>= peroutqueuenode
- (entry
->textp
- entry
->buffer
)) {
219 peroutqueuenode
= !peroutqueuenode
|| !entry
|| entry
->addr ?
128 :
220 peroutqueuenode
>= 1024 ?
4096 : peroutqueuenode
<<2;
221 entry
= xmalloc(sizeof(*entry
));
222 entry
->buffer
= xmalloc(peroutqueuenode
);
223 entry
->textp
= entry
->buffer
;
226 LIST_LINK_TAIL(outqueue
,entry
);
229 entry
->textp
[entry
->textlen
++]= c
;
232 static void queueoutstr(const char *str
, int len
) {
233 while (len
-- > 0) queueoutchar(*str
++);
236 static void writestdout(struct outqueuenode
*entry
) {
239 while (entry
->textlen
) {
240 r
= write(1, entry
->textp
, entry
->textlen
);
242 if (errno
== EINTR
) continue;
243 if (errno
== EAGAIN
) { outblocked
= 1; break; }
244 sysfail("write stdout");
246 assert(r
<= entry
->textlen
);
250 if (!entry
->textlen
) {
251 LIST_UNLINK(outqueue
,entry
);
258 static void replacetextwithname(struct outqueuenode
*entry
) {
262 name
= entry
->addr
->ans
->rrs
.str
[0];
263 namelen
= strlen(name
);
268 entry
->textlen
= namelen
;
270 newlen
= entry
->textlen
+ namelen
+ (bracket ?
0 : 2);
271 newbuf
= xmalloc(newlen
+ 1);
272 sprintf(newbuf
, bracket ?
"%s%.*s" : "%s[%.*s]", name
, entry
->textlen
, entry
->textp
);
274 entry
->buffer
= entry
->textp
= newbuf
;
275 entry
->textlen
= newlen
;
279 static void checkadnsqueries(void) {
283 struct treething
*foundthing
;
287 qu
= 0; context
= 0; ans
= 0;
288 r
= adns_check(ads
,&qu
,&ans
,&context
);
289 if (r
== ESRCH
|| r
== EAGAIN
) break;
292 foundthing
->ans
= ans
;
297 static void restartbuf(void) {
298 if (inbuf
>0) queueoutstr(addrtextbuf
,inbuf
);
302 static int comparer(const void *a
, const void *b
) {
303 return memcmp(a
,b
,4);
306 static void procaddr(void) {
307 struct treething
*foundthing
;
309 struct outqueuenode
*entry
;
313 newthing
= xmalloc(sizeof(struct treething
));
318 memcpy(newthing
->bytes
,bytes
,4);
319 searchfound
= tsearch(newthing
,&treeroot
,comparer
);
320 if (!searchfound
) sysfail("tsearch");
321 foundthing
= *searchfound
;
323 if (foundthing
== newthing
) {
325 memcpy(&sa
.sin_addr
,bytes
,4);
326 r
= adns_submit_reverse(ads
, (const struct sockaddr
*)&sa
,
327 rrt
,0,foundthing
,&foundthing
->qu
);
328 if (r
) adnsfail("submit",r
);
330 entry
= xmalloc(sizeof(*entry
));
331 entry
->buffer
= xmalloc(inbuf
);
332 entry
->textp
= entry
->buffer
;
333 memcpy(entry
->textp
,addrtextbuf
,inbuf
);
334 entry
->textlen
= inbuf
;
335 entry
->addr
= foundthing
;
336 entry
->printbefore
= printbefore
;
337 LIST_LINK_TAIL(outqueue
,entry
);
343 static void startaddr(void) {
348 static void readstdin(void) {
349 char readbuf
[512], *p
;
352 while ((r
= read(0,readbuf
,sizeof(readbuf
))) <= 0) {
353 if (r
== 0) { inputeof
= 1; return; }
354 if (r
== EAGAIN
) return;
355 if (r
!= EINTR
) sysfail("read stdin");
357 for (p
=readbuf
; r
>0; r
--,p
++) {
359 if (cbyte
==-1 && bracket
&& c
=='[') {
360 addrtextbuf
[inbuf
++]= c
;
362 } else if (cbyte
==-1 && !bracket
&& !isalnum(c
)) {
365 } else if (cbyte
>=0 && inbyte
<3 && c
>='0' && c
<='9' &&
366 (nbyte
= bytes
[cbyte
]*10 + (c
-'0')) <= 255) {
368 addrtextbuf
[inbuf
++]= c
;
370 } else if (cbyte
>=0 && cbyte
<3 && inbyte
>0 && c
=='.') {
372 addrtextbuf
[inbuf
++]= c
;
374 } else if (cbyte
==3 && inbyte
>0 && bracket
&& c
==']') {
375 addrtextbuf
[inbuf
++]= c
;
377 } else if (cbyte
==3 && inbyte
>0 && !bracket
&& !isalnum(c
)) {
385 if (!bracket
&& !isalnum(c
)) startaddr();
390 static void startup(void) {
393 if (nonblock(0,1)) sysfail("set stdin to nonblocking mode");
394 if (nonblock(1,1)) sysfail("set stdout to nonblocking mode");
395 memset(&sa
,0,sizeof(sa
));
396 sa
.sin_family
= AF_INET
;
398 r
= adns_init_strcfg(&ads
,initflags
,stderr
,config_text
);
400 r
= adns_init(&ads
,initflags
,0);
402 if (r
) adnsfail("init",r
);
406 if (!bracket
) startaddr();
409 int main(int argc
, const char *const *argv
) {
411 fd_set readfds
, writefds
, exceptfds
;
412 struct outqueuenode
*entry
;
413 struct timeval
*tv
, tvbuf
, now
;
418 while (!inputeof
|| outqueue
.head
) {
421 FD_ZERO(&readfds
); FD_ZERO(&writefds
); FD_ZERO(&exceptfds
);
422 if ((entry
= outqueue
.head
) && !outblocked
) {
427 if (entry
->addr
->ans
) {
428 if (entry
->addr
->ans
->nrrs
)
429 replacetextwithname(entry
);
433 r
= gettimeofday(&now
,0); if (r
) sysfail("gettimeofday");
436 } else if (!timercmp(&now
,&entry
->printbefore
,<)) {
440 tvbuf
.tv_sec
= entry
->printbefore
.tv_sec
- now
.tv_sec
- 1;
441 tvbuf
.tv_usec
= entry
->printbefore
.tv_usec
- now
.tv_usec
+ 1000000;
442 tvbuf
.tv_sec
+= tvbuf
.tv_usec
/ 1000000;
443 tvbuf
.tv_usec
%= 1000000;
446 adns_beforeselect(ads
,&maxfd
,&readfds
,&writefds
,&exceptfds
,
449 if (outblocked
) FD_SET(1,&writefds
);
450 if (!inputeof
&& outqueuelen
<1024) FD_SET(0,&readfds
);
452 r
= select(maxfd
,&readfds
,&writefds
,&exceptfds
,tv
);
453 if (r
< 0) { if (r
== EINTR
) continue; else sysfail("select"); }
455 r
= gettimeofday(&now
,0); if (r
) sysfail("gettimeofday");
456 adns_afterselect(ads
,maxfd
,&readfds
,&writefds
,&exceptfds
,&now
);
459 if (FD_ISSET(0,&readfds
)) {
462 timevaladd(&printbefore
,timeout
);
465 } else if (FD_ISSET(1,&writefds
)) {
469 if (nonblock(0,0)) sysfail("un-nonblock stdin");
470 if (nonblock(1,0)) sysfail("un-nonblock stdout");