chiark / gitweb /
d7150e849519a590798a1a2afa3c5cd702b76903
[adns.git] / client / adnsresfilter.c
1 /*
2  * adnsresfilter.c
3  * - filter which does resolving, not part of the library
4  */
5 /*
6  *  This file is
7  *    Copyright (C) 1999 Ian Jackson <ian@davenant.greenend.org.uk>
8  *
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>
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 "adns.h"
37 #include "config.h"
38
39 static void sysfail(const char *what) NONRETURNING;
40 static void sysfail(const char *what) {
41   fprintf(stderr,"adnsresfilter: system call failed: %s: %s\n",what,strerror(errno));
42   exit(2);
43 }
44
45 static void outputerr(void) NONRETURNING;
46 static void outputerr(void) { sysfail("write to stdout"); }
47
48 static void usage(void) {
49   if (printf("usage: adnsresfilter [<options ...>]\n"
50              "       adnsresfilter  -h|--help\n"
51              "options: -b|--brackets\n"
52              "         -w|--wait\n"
53              "         -u|--unchecked\n")
54       == EOF) outputerr();
55 }
56
57 static void usageerr(const char *why) NONRETURNING;
58 static void usageerr(const char *why) {
59   fprintf(stderr,"adnsresfilter: bad usage: %s\n",why);
60   usage();
61   exit(1);
62 }
63
64 static void adnsfail(const char *what, int e) NONRETURNING;
65 static void adnsfail(const char *what, int e) {
66   fprintf(stderr,"adnsresfilter: adns call failed: %s: %s\n",what,strerror(e));
67   exit(2);
68 }
69
70 static int bracket, forever;
71 static adns_rrtype rrt= adns_r_ptr;
72
73 static struct sockaddr_in sa;
74 static adns_state ads;
75
76 static char buf[14];
77 static int c, cbyte, inbyte, inbuf;
78 static unsigned char bytes[4];
79
80 struct treething {
81   unsigned char bytes[4];
82   adns_query qu;
83   adns_answer *ans;
84 };
85
86 static struct treething *newthing;
87 static void *treeroot;
88
89 static int comparer(const void *a, const void *b) {
90   return memcmp(a,b,4);
91 }
92
93 static void restartbuf(void) {
94   if (inbuf>0) {
95     buf[inbuf++]= 0;
96     if (fputs(buf,stdout) < 0) outputerr();
97   }
98   inbuf= 0;
99 }
100
101 static void procaddr(void) {
102   struct treething *foundthing;
103   void *expectreturn, **searchfound;
104   int r;
105   
106   if (!newthing) {
107     newthing= malloc(sizeof(struct treething));
108     if (!newthing) sysfail("malloc");
109     newthing->qu= 0;
110     newthing->ans= 0;
111   }
112
113   memcpy(newthing->bytes,bytes,4);
114   searchfound= tsearch(newthing,&treeroot,comparer);
115   if (!searchfound) sysfail("tsearch");
116   foundthing= *searchfound;
117
118   if (foundthing == newthing) {
119     newthing= 0;
120     memcpy(&sa.sin_addr,bytes,4);
121     r= adns_submit_reverse(ads, (const struct sockaddr*)&sa,
122                            rrt,0,foundthing,&foundthing->qu);
123     if (r) adnsfail("submit",r);
124   }
125   if (!forever && foundthing->ans && foundthing->ans->status == adns_s_timeout) {
126     free(foundthing->ans);
127     foundthing->ans= 0;
128   }
129   if (!foundthing->ans) {
130     expectreturn= foundthing;
131     r= (forever ? adns_wait : adns_check)
132       (ads,&foundthing->qu,&foundthing->ans,&expectreturn);
133     assert(r==EAGAIN || (!r && foundthing->ans && expectreturn==foundthing));
134   }
135   if (foundthing->ans && foundthing->ans->nrrs > 0) {
136     if (fputs(foundthing->ans->rrs.str[0],stdout) < 0) outputerr();
137     inbuf= 0;
138   } else {
139     restartbuf();
140   }
141   cbyte= -1;
142 }
143
144 static void startaddr(void) {
145   bytes[cbyte=0]= 0;
146   inbyte= 0;
147 }
148
149 static void mustputchar(int c) {
150   if (putchar(c) == EOF) outputerr();
151 }
152
153 int main(int argc, const char *const *argv) {
154   const char *arg;
155   int nbyte, r;
156
157   while ((arg= *++argv)) {
158     if (arg[0] != '-') usageerr("no non-option arguments are allowed");
159     if (arg[1] == '-') {
160       if (!strcmp(arg,"--brackets")) {
161         bracket= 1;
162       } else if (!strcmp(arg,"--unchecked")) {
163         rrt= adns_r_ptr_raw;
164       } else if (!strcmp(arg,"--wait")) {
165         forever= 1;
166       } else if (!strcmp(arg,"--help")) {
167         usage(); exit(0);
168       } else {
169         usageerr("unknown long option");
170       }
171     } else {
172       while ((c= *++arg)) {
173         switch (c) {
174         case 'b':
175           bracket= 1;
176           break;
177         case 'u':
178           rrt= adns_r_ptr_raw;
179           break;
180         case 'w':
181           forever= 1;
182           break;
183         case 'h':
184           usage(); exit(0);
185         default:
186           usageerr("unknown short option");
187         }
188       }
189     }
190   }
191   if (setvbuf(stdout,0,_IOLBF,0)) sysfail("setvbuf stdout");
192
193   memset(&sa,0,sizeof(sa));
194   sa.sin_family= AF_INET;
195
196   r= adns_init(&ads,0,0);  if (r) adnsfail("init",r);
197
198   cbyte= -1;
199   inbyte= -1;
200   inbuf= 0;
201   if (!bracket) startaddr();
202   while ((c= getchar()) != EOF) {
203     if (cbyte==-1 && bracket && c=='[') {
204       buf[inbuf++]= c;
205       startaddr();
206     } else if (cbyte==-1 && !bracket && !isalnum(c)) {
207       mustputchar(c);
208       startaddr();
209     } else if (cbyte>=0 && inbyte<3 && c>='0' && c<='9' &&
210                (nbyte= bytes[cbyte]*10 + (c-'0')) <= 255) {
211       bytes[cbyte]= nbyte;
212       buf[inbuf++]= c;
213       inbyte++;
214     } else if (cbyte>=0 && cbyte<3 && inbyte>0 && c=='.') {
215       bytes[++cbyte]= 0;
216       buf[inbuf++]= c;
217       inbyte= 0;
218     } else if (cbyte==3 && inbyte>0 && bracket && c==']') {
219       buf[inbuf++]= c;
220       procaddr();
221     } else if (cbyte==3 && inbyte>0 && !bracket && !isalnum(c)) {
222       procaddr();
223       mustputchar(c);
224       startaddr();
225     } else {
226       restartbuf();
227       mustputchar(c);
228       cbyte= -1;
229       if (!bracket && !isalnum(c)) startaddr();
230     }
231   }
232   if (ferror(stdin) || fclose(stdin)) sysfail("read stdin");
233   if (cbyte==3 && inbyte>0 && !bracket) procaddr();
234   if (fclose(stdout)) sysfail("close stdout");
235   exit(0);
236 }