592aa664 |
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 | } |