+ * New fanftest test program from Tony Finch (ignored by `make install').
[adns] / 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 (!foundthing->ans) {
126 expectreturn= foundthing;
127 r= (forever ? adns_wait : adns_check)
128 (ads,&foundthing->qu,&foundthing->ans,&expectreturn);
129 assert(r==EAGAIN || (!r && foundthing->ans && expectreturn==foundthing));
130 }
131 if (foundthing->ans && foundthing->ans->nrrs > 0) {
132 if (fputs(foundthing->ans->rrs.str[0],stdout) < 0) outputerr();
133 inbuf= 0;
134 } else {
135 restartbuf();
136 }
137 cbyte= -1;
138 }
139
140 static void startaddr(void) {
141 bytes[cbyte=0]= 0;
142 inbyte= 0;
143 }
144
145 static void mustputchar(int c) {
146 if (putchar(c) == EOF) outputerr();
147 }
148
149 int main(int argc, const char *const *argv) {
150 const char *arg;
151 int nbyte, r;
152
153 while ((arg= *++argv)) {
154 if (arg[0] != '-') usageerr("no non-option arguments are allowed");
155 if (arg[1] == '-') {
156 if (!strcmp(arg,"--brackets")) {
157 bracket= 1;
158 } else if (!strcmp(arg,"--unchecked")) {
159 rrt= adns_r_ptr_raw;
160 } else if (!strcmp(arg,"--wait")) {
161 forever= 1;
162 } else if (!strcmp(arg,"--help")) {
163 usage(); exit(0);
164 } else {
165 usageerr("unknown long option");
166 }
167 } else {
168 while ((c= *++arg)) {
169 switch (c) {
170 case 'b':
171 bracket= 1;
172 break;
173 case 'u':
174 rrt= adns_r_ptr_raw;
175 break;
176 case 'w':
177 forever= 1;
178 break;
179 case 'h':
180 usage(); exit(0);
181 default:
182 usageerr("unknown short option");
183 }
184 }
185 }
186 }
187 if (setvbuf(stdout,0,_IOLBF,0)) sysfail("setvbuf stdout");
188
189 memset(&sa,0,sizeof(sa));
190 sa.sin_family= AF_INET;
191
192 r= adns_init(&ads,0,0); if (r) adnsfail("init",r);
193
194 cbyte= -1;
195 inbyte= -1;
196 inbuf= 0;
197 if (!bracket) startaddr();
198 while ((c= getchar()) != EOF) {
199 if (cbyte==-1 && bracket && c=='[') {
200 buf[inbuf++]= c;
201 startaddr();
202 } else if (cbyte==-1 && !bracket && !isalnum(c)) {
203 mustputchar(c);
204 startaddr();
205 } else if (cbyte>=0 && inbyte<3 && c>='0' && c<='9' &&
206 (nbyte= bytes[cbyte]*10 + (c-'0')) <= 255) {
207 bytes[cbyte]= nbyte;
208 buf[inbuf++]= c;
209 inbyte++;
210 } else if (cbyte>=0 && cbyte<3 && inbyte>0 && c=='.') {
211 bytes[++cbyte]= 0;
212 buf[inbuf++]= c;
213 inbyte= 0;
214 } else if (cbyte==3 && inbyte>0 && bracket && c==']') {
215 buf[inbuf++]= c;
216 procaddr();
217 } else if (cbyte==3 && inbyte>0 && !bracket && !isalnum(c)) {
218 procaddr();
219 mustputchar(c);
220 startaddr();
221 } else {
222 restartbuf();
223 mustputchar(c);
224 cbyte= -1;
225 if (!bracket && !isalnum(c)) startaddr();
226 }
227 }
228 if (ferror(stdin) || fclose(stdin)) sysfail("read stdin");
229 if (cbyte==3 && inbyte>0 && !bracket) procaddr();
230 if (fclose(stdout)) sysfail("close stdout");
231 exit(0);
232 }