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");