3 * - filter which does resolving, not part of the library
7 * Copyright (C) 1999 Ian Jackson <ian@davenant.greenend.org.uk>
9 * It is part of adns, which is
10 * Copyright (C) 1997-1999 Ian Jackson <ian@davenant.greenend.org.uk>
11 * Copyright (C) 1999 Tony Finch <dot@dotat.at>
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)
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.
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.
36 #include <sys/fcntl.h>
44 struct outqueuenode
*next
, *back
;
48 struct timeval printbefore
;
49 struct treething
*addr
;
52 static int bracket
, forever
, timeout
=10;
53 static adns_rrtype rrt
= adns_r_ptr
;
55 static int outblocked
, inputeof
;
56 static struct { struct outqueuenode
*head
, *tail
; } outqueue
;
57 static int peroutqueuenode
, outqueuelen
;
59 static struct sockaddr_in sa
;
60 static adns_state ads
;
62 static char addrtextbuf
[14];
63 static int cbyte
, inbyte
, inbuf
;
64 static unsigned char bytes
[4];
65 static struct timeval printbefore
;
68 unsigned char bytes
[4];
73 static struct treething
*newthing
;
74 static void *treeroot
;
76 static int nonblock(int fd
, int isnonblock
) {
81 r
= fcntl(fd
,F_SETFL
, isnonblock ? r
|O_NONBLOCK
: r
&~O_NONBLOCK
);
86 static void quit(int exitstatus
) NONRETURNING
;
87 static void quit(int exitstatus
) {
93 static void sysfail(const char *what
) NONRETURNING
;
94 static void sysfail(const char *what
) {
95 fprintf(stderr
,"adnsresfilter: system call failed: %s: %s\n",what
,strerror(errno
));
99 static void *xmalloc(size_t sz
) {
101 r
= malloc(sz
); if (r
) return r
;
105 static void outputerr(void) NONRETURNING
;
106 static void outputerr(void) { sysfail("write to stdout"); }
108 static void usage(void) {
109 if (printf("usage: adnsresfilter [<options ...>]\n"
110 " adnsresfilter -h|--help\n"
111 "options: -b|--brackets\n"
113 " -t<timeout>|--timeout <timeout>\n"
118 static void usageerr(const char *why
) NONRETURNING
;
119 static void usageerr(const char *why
) {
120 fprintf(stderr
,"adnsresfilter: bad usage: %s\n",why
);
125 static void adnsfail(const char *what
, int e
) NONRETURNING
;
126 static void adnsfail(const char *what
, int e
) {
127 fprintf(stderr
,"adnsresfilter: adns call failed: %s: %s\n",what
,strerror(e
));
131 static int comparer(const void *a
, const void *b
) {
132 return memcmp(a
,b
,4);
135 static void parseargs(const char *const *argv
) {
139 while ((arg
= *++argv
)) {
140 if (arg
[0] != '-') usageerr("no non-option arguments are allowed");
142 if (!strcmp(arg
,"--brackets")) {
144 } else if (!strcmp(arg
,"--unchecked")) {
146 } else if (!strcmp(arg
,"--wait")) {
148 } else if (!strcmp(arg
,"--help")) {
151 usageerr("unknown long option");
154 while ((c
= *++arg
)) {
168 usageerr("unknown short option");
175 static void queueoutchar(int c
) {
176 struct outqueuenode
*entry
;
178 entry
= outqueue
.tail
;
179 if (!entry
->back
|| entry
->addr
|| entry
->textlen
>= peroutqueuenode
) {
180 entry
= xmalloc(sizeof(*entry
));
181 peroutqueuenode
= !entry
->back
|| entry
->addr ?
32 :
182 peroutqueuenode
>= 1024 ?
2048 : peroutqueuenode
<<1;
183 entry
->buffer
= xmalloc(peroutqueuenode
);
184 entry
->textp
= entry
->buffer
;
187 LIST_LINK_TAIL(outqueue
,entry
);
194 static void queueoutstr(const char *str
, int len
) {
195 while (len
> 0) queueoutchar(*str
++);
198 static void writestdout(struct outqueuenode
*entry
) {
201 while (entry
->textlen
) {
202 r
= write(1, entry
->textp
, entry
->textlen
);
204 if (errno
== EINTR
) continue;
205 if (errno
== EAGAIN
) { outblocked
= 1; break; }
206 sysfail("write stdout");
208 assert(r
< entry
->textlen
);
212 if (!entry
->textlen
) {
213 LIST_UNLINK(outqueue
,entry
);
220 static void replacetextwithname(struct outqueuenode
*entry
) {
223 entry
->textp
= entry
->addr
->ans
->rrs
.str
[0];
224 entry
->textlen
= strlen(entry
->textp
);
227 static void checkadnsqueries(void) {
231 struct treething
*foundthing
;
235 qu
= 0; context
= 0; ans
= 0;
236 r
= adns_check(ads
,&qu
,&ans
,&context
);
237 if (r
== ESRCH
|| r
== EAGAIN
) break;
240 foundthing
->ans
= ans
;
245 static void restartbuf(void) {
246 if (inbuf
>0) queueoutstr(addrtextbuf
,inbuf
);
250 static void procaddr(void) {
251 struct treething
*foundthing
;
253 struct outqueuenode
*entry
;
257 newthing
= xmalloc(sizeof(struct treething
));
262 memcpy(newthing
->bytes
,bytes
,4);
263 searchfound
= tsearch(newthing
,&treeroot
,comparer
);
264 if (!searchfound
) sysfail("tsearch");
265 foundthing
= *searchfound
;
267 if (foundthing
== newthing
) {
268 memcpy(&sa
.sin_addr
,bytes
,4);
269 r
= adns_submit_reverse(ads
, (const struct sockaddr
*)&sa
,
270 rrt
,0,foundthing
,&foundthing
->qu
);
271 if (r
) adnsfail("submit",r
);
273 entry
= xmalloc(sizeof(*entry
));
274 entry
->buffer
= xmalloc(inbuf
);
275 entry
->textp
= entry
->buffer
;
276 memcpy(entry
->textp
,addrtextbuf
,inbuf
);
277 entry
->textlen
= inbuf
;
278 entry
->addr
= foundthing
;
279 LIST_LINK_TAIL(outqueue
,entry
);
285 static void startaddr(void) {
290 static void readstdin(void) {
291 char readbuf
[512], *p
;
294 while ((r
= read(0,readbuf
,sizeof(readbuf
))) <= 0) {
295 if (r
== 0) { inputeof
= 1; return; }
296 if (r
== EAGAIN
) return;
297 if (r
!= EINTR
) sysfail("read stdin");
299 for (p
=readbuf
; r
>0; r
--,p
++) {
301 if (cbyte
==-1 && bracket
&& c
=='[') {
302 addrtextbuf
[inbuf
++]= c
;
304 } else if (cbyte
==-1 && !bracket
&& !isalnum(c
)) {
307 } else if (cbyte
>=0 && inbyte
<3 && c
>='0' && c
<='9' &&
308 (nbyte
= bytes
[cbyte
]*10 + (c
-'0')) <= 255) {
310 addrtextbuf
[inbuf
++]= c
;
312 } else if (cbyte
>=0 && cbyte
<3 && inbyte
>0 && c
=='.') {
314 addrtextbuf
[inbuf
++]= c
;
316 } else if (cbyte
==3 && inbyte
>0 && bracket
&& c
==']') {
317 addrtextbuf
[inbuf
++]= c
;
319 } else if (cbyte
==3 && inbyte
>0 && !bracket
&& !isalnum(c
)) {
327 if (!bracket
&& !isalnum(c
)) startaddr();
330 if (cbyte
==3 && inbyte
>0 && !bracket
) procaddr();
333 static void startup(void) {
336 if (setvbuf(stdout
,0,_IOLBF
,0)) sysfail("setvbuf stdout");
337 if (nonblock(0,1)) sysfail("set stdin to nonblocking mode");
338 if (nonblock(1,1)) sysfail("set stdout to nonblocking mode");
339 memset(&sa
,0,sizeof(sa
));
340 sa
.sin_family
= AF_INET
;
341 r
= adns_init(&ads
,0,0); if (r
) adnsfail("init",r
);
345 if (!bracket
) startaddr();
348 int main(int argc
, const char *const *argv
) {
350 fd_set readfds
, writefds
, exceptfds
;
351 struct outqueuenode
*entry
;
352 struct timeval
*tv
, tvbuf
, now
;
357 while (!inputeof
|| outqueue
.head
) {
360 FD_ZERO(&readfds
); FD_ZERO(&writefds
); FD_ZERO(&exceptfds
);
361 if ((entry
= outqueue
.head
) && !outblocked
) {
365 } else if (entry
->addr
->ans
) {
366 if (entry
->addr
->ans
->nrrs
)
367 replacetextwithname(entry
);
371 r
= gettimeofday(&now
,0); if (r
) sysfail("gettimeofday");
374 } else if (!timercmp(&now
,&entry
->printbefore
,<)) {
378 tvbuf
.tv_sec
= printbefore
.tv_sec
- now
.tv_sec
- 1;
379 tvbuf
.tv_usec
= printbefore
.tv_usec
- now
.tv_usec
+ 1000000;
380 tvbuf
.tv_sec
+= tvbuf
.tv_usec
/ 1000000;
381 tvbuf
.tv_usec
%= 1000000;
384 adns_beforeselect(ads
,&maxfd
,&readfds
,&writefds
,&exceptfds
,
387 if (outblocked
) FD_SET(1,&writefds
);
388 if (!inputeof
&& outqueuelen
<1000) FD_SET(0,&readfds
);
390 r
= select(maxfd
,&readfds
,&writefds
,&exceptfds
,tv
);
391 if (r
< 0) { if (r
== EINTR
) continue; else sysfail("select"); }
393 r
= gettimeofday(&now
,0); if (r
) sysfail("gettimeofday");
394 adns_afterselect(ads
,maxfd
,&readfds
,&writefds
,&exceptfds
,&now
);
397 if (FD_ISSET(0,&readfds
)) {
400 timevaladd(&printbefore
,timeout
);
403 } else if (FD_ISSET(1,&writefds
)) {
407 if (ferror(stdin
) || fclose(stdin
)) sysfail("read stdin");
408 if (fclose(stdout
)) sysfail("close stdout");
409 if (nonblock(0,0)) sysfail("un-nonblock stdin");
410 if (nonblock(1,0)) sysfail("un-nonblock stdout");