Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5 #include <ip.h>
6 #include <ndb.h>
7 #include "dns.h"
9 enum
10 {
11 Maxrequest= 128,
12 Ncache= 8,
13 Maxpath= 128,
14 Maxreply= 512,
15 Maxrrr= 16,
16 };
18 static char *servername;
19 static RR *serverrr;
20 static RR *serveraddrs;
22 int debug;
23 int cachedb;
24 ulong now;
25 int testing;
26 int traceactivity;
27 char *trace;
28 int needrefresh;
29 int resolver;
30 uchar ipaddr[IPaddrlen]; /* my ip address */
31 int maxage;
32 char *logfile = "dns";
33 char *dbfile;
34 char mntpt[Maxpath];
35 char *zonerefreshprogram;
37 int prettyrrfmt(Fmt*);
38 void preloadserveraddrs(void);
39 void squirrelserveraddrs(void);
40 int setserver(char*);
41 void doquery(char*, char*);
42 void docmd(int, char**);
44 void
45 main(int argc, char *argv[])
46 {
47 int n;
48 Biobuf in;
49 char *p;
50 char *f[4];
52 strcpy(mntpt, "/net");
54 ARGBEGIN{
55 case 'r':
56 resolver = 1;
57 break;
58 case 'x':
59 dbfile = "/lib/ndb/external";
60 strcpy(mntpt, "/net.alt");
61 break;
62 case 'f':
63 dbfile = ARGF();
64 break;
65 }ARGEND
67 now = time(0);
68 dninit();
69 fmtinstall('R', prettyrrfmt);
70 if(myipaddr(ipaddr, mntpt) < 0)
71 sysfatal("can't read my ip address");
72 opendatabase();
74 if(resolver)
75 squirrelserveraddrs();
77 debug = 1;
79 if(argc > 0){
80 docmd(argc, argv);
81 exits(0);
82 }
84 Binit(&in, 0, OREAD);
85 for(print("> "); p = Brdline(&in, '\n'); print("> ")){
86 p[Blinelen(&in)-1] = 0;
87 n = tokenize(p, f, 3);
88 if(n<1)
89 continue;
91 /* flush the cache */
92 dnpurge();
94 docmd(n, f);
96 }
97 exits(0);
98 }
100 static char*
101 longtime(long t)
103 int d, h, m, n;
104 static char x[128];
106 for(d = 0; t >= 24*60*60; t -= 24*60*60)
107 d++;
108 for(h = 0; t >= 60*60; t -= 60*60)
109 h++;
110 for(m = 0; t >= 60; t -= 60)
111 m++;
112 n = 0;
113 if(d)
114 n += sprint(x, "%d day ", d);
115 if(h)
116 n += sprint(x+n, "%d hr ", h);
117 if(m)
118 n += sprint(x+n, "%d min ", m);
119 if(t || n == 0)
120 sprint(x+n, "%ld sec", t);
121 return x;
124 int
125 prettyrrfmt(Fmt *f)
127 RR *rp;
128 char buf[3*Domlen];
129 char *p, *e;
130 Txt *t;
132 rp = va_arg(f->args, RR*);
133 if(rp == 0){
134 strcpy(buf, "<null>");
135 goto out;
138 p = buf;
139 e = buf + sizeof(buf);
140 p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name,
141 longtime(rp->db ? rp->ttl : (rp->ttl-now)),
142 rrname(rp->type, buf, sizeof buf));
144 if(rp->negative){
145 seprint(p, e, "negative rcode %d\n", rp->negrcode);
146 goto out;
149 switch(rp->type){
150 case Thinfo:
151 seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name);
152 break;
153 case Tcname:
154 case Tmb:
155 case Tmd:
156 case Tmf:
157 case Tns:
158 seprint(p, e, "\t%s", rp->host->name);
159 break;
160 case Tmg:
161 case Tmr:
162 seprint(p, e, "\t%s", rp->mb->name);
163 break;
164 case Tminfo:
165 seprint(p, e, "\t%s %s", rp->mb->name, rp->rmb->name);
166 break;
167 case Tmx:
168 seprint(p, e, "\t%lud %s", rp->pref, rp->host->name);
169 break;
170 case Ta:
171 case Taaaa:
172 seprint(p, e, "\t%s", rp->ip->name);
173 break;
174 case Tptr:
175 seprint(p, e, "\t%s", rp->ptr->name);
176 break;
177 case Tsoa:
178 seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud", rp->host->name,
179 rp->rmb->name, rp->soa->serial, rp->soa->refresh, rp->soa->retry,
180 rp->soa->expire, rp->soa->minttl);
181 break;
182 case Tnull:
183 seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data);
184 break;
185 case Ttxt:
186 p = seprint(p, e, "\t");
187 for(t = rp->txt; t != nil; t = t->next)
188 p = seprint(p, e, "%s", t->p);
189 break;
190 case Trp:
191 seprint(p, e, "\t%s %s", rp->rmb->name, rp->rp->name);
192 break;
193 case Tkey:
194 seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto,
195 rp->key->alg);
196 break;
197 case Tsig:
198 seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s",
199 rp->sig->type, rp->sig->alg, rp->sig->labels, rp->sig->ttl,
200 rp->sig->exp, rp->sig->incep, rp->sig->tag, rp->sig->signer->name);
201 break;
202 case Tcert:
203 seprint(p, e, "\t%d %d %d",
204 rp->sig->type, rp->sig->tag, rp->sig->alg);
205 break;
206 default:
207 break;
209 out:
210 return fmtstrcpy(f, buf);
213 void
214 logsection(char *flag, RR *rp)
216 if(rp == nil)
217 return;
218 print("\t%s%R\n", flag, rp);
219 for(rp = rp->next; rp != nil; rp = rp->next)
220 print("\t %R\n", rp);
223 void
224 logreply(int id, uchar *addr, DNSmsg *mp)
226 RR *rp;
227 char buf[12];
228 char resp[32];
230 switch(mp->flags & Rmask){
231 case Rok:
232 strcpy(resp, "OK");
233 break;
234 case Rformat:
235 strcpy(resp, "Format error");
236 break;
237 case Rserver:
238 strcpy(resp, "Server failed");
239 break;
240 case Rname:
241 strcpy(resp, "Nonexistent");
242 break;
243 case Runimplimented:
244 strcpy(resp, "Unimplemented");
245 break;
246 case Rrefused:
247 strcpy(resp, "Refused");
248 break;
249 default:
250 sprint(resp, "%d", mp->flags & Rmask);
251 break;
254 print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr,
255 mp->flags & Fauth ? "authoritative" : "",
256 mp->flags & Ftrunc ? " truncated" : "",
257 mp->flags & Frecurse ? " recurse" : "",
258 mp->flags & Fcanrec ? " can_recurse" : "",
259 mp->flags & (Fauth|Rname) == (Fauth|Rname) ?
260 " nx" : "");
261 for(rp = mp->qd; rp != nil; rp = rp->next)
262 print("\tQ: %s %s\n", rp->owner->name, rrname(rp->type, buf, sizeof buf));
263 logsection("Ans: ", mp->an);
264 logsection("Auth: ", mp->ns);
265 logsection("Hint: ", mp->ar);
268 void
269 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
271 char buf[12];
273 print("%d.%d: sending to %I/%s %s %s\n", id, subid,
274 addr, sname, rname, rrname(type, buf, sizeof buf));
277 RR*
278 getdnsservers(int class)
280 RR *rr;
282 if(servername == nil)
283 return dnsservers(class);
285 rr = rralloc(Tns);
286 rr->owner = dnlookup("local#dns#servers", class, 1);
287 rr->host = dnlookup(servername, class, 1);
289 return rr;
292 void
293 squirrelserveraddrs(void)
295 RR *rr, *rp, **l;
296 Request req;
298 /* look up the resolver address first */
299 resolver = 0;
300 debug = 0;
301 if(serveraddrs)
302 rrfreelist(serveraddrs);
303 serveraddrs = nil;
304 rr = getdnsservers(Cin);
305 l = &serveraddrs;
306 for(rp = rr; rp != nil; rp = rp->next){
307 if(strcmp(ipattr(rp->host->name), "ip") == 0){
308 *l = rralloc(Ta);
309 (*l)->owner = rp->host;
310 (*l)->ip = rp->host;
311 l = &(*l)->next;
312 continue;
314 req.isslave = 1;
315 req.aborttime = now + 60; /* don't spend more than 60 seconds */
316 *l = dnresolve(rp->host->name, Cin, Ta, &req, 0, 0, Recurse, 0, 0);
317 while(*l != nil)
318 l = &(*l)->next;
320 resolver = 1;
321 debug = 1;
324 void
325 preloadserveraddrs(void)
327 RR *rp, **l, *first;
329 l = &first;
330 for(rp = serveraddrs; rp != nil; rp = rp->next){
331 rrcopy(rp, l);
332 rrattach(first, 1);
336 int
337 setserver(char *server)
339 if(servername != nil){
340 free(servername);
341 servername = nil;
342 resolver = 0;
344 if(server == nil || *server == 0)
345 return 0;
346 servername = strdup(server);
347 squirrelserveraddrs();
348 if(serveraddrs == nil){
349 print("can't resolve %s\n", servername);
350 resolver = 0;
351 } else {
352 resolver = 1;
354 return resolver ? 0 : -1;
357 void
358 doquery(char *name, char *tstr)
360 Request req;
361 RR *rr, *rp;
362 int len, type;
363 char *p, *np;
364 int rooted;
365 char buf[1024];
367 if(resolver)
368 preloadserveraddrs();
370 /* default to an "ip" request if alpha, "ptr" if numeric */
371 if(tstr == nil || *tstr == 0) {
372 if(strcmp(ipattr(name), "ip") == 0)
373 tstr = "ptr";
374 else
375 tstr = "ip";
378 /* if name end in '.', remove it */
379 len = strlen(name);
380 if(len > 0 && name[len-1] == '.'){
381 rooted = 1;
382 name[len-1] = 0;
383 } else
384 rooted = 0;
386 /* inverse queries may need to be permuted */
387 strncpy(buf, name, sizeof buf);
388 if(strcmp("ptr", tstr) == 0
389 && strstr(name, "IN-ADDR") == 0
390 && strstr(name, "in-addr") == 0){
391 for(p = name; *p; p++)
393 *p = '.';
394 np = buf;
395 len = 0;
396 while(p >= name){
397 len++;
398 p--;
399 if(*p == '.'){
400 memmove(np, p+1, len);
401 np += len;
402 len = 0;
405 memmove(np, p+1, len);
406 np += len;
407 strcpy(np, "in-addr.arpa");
410 /* look it up */
411 type = rrtype(tstr);
412 if(type < 0){
413 print("!unknown type %s\n", tstr);
414 return;
417 getactivity(&req);
418 req.isslave = 1;
419 req.aborttime = now + 60; /* don't spend more than 60 seconds */
420 rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0);
421 if(rr){
422 print("----------------------------\n");
423 for(rp = rr; rp; rp = rp->next)
424 print("answer %R\n", rp);
425 print("----------------------------\n");
427 rrfreelist(rr);
429 putactivity();
432 void
433 docmd(int n, char **f)
435 int tmpsrv;
436 char *name, *type;
438 name = nil;
439 type = nil;
440 tmpsrv = 0;
442 if(*f[0] == '@') {
443 if(setserver(f[0]+1) < 0)
444 return;
446 switch(n){
447 case 3:
448 type = f[2];
449 /* fall through */
450 case 2:
451 name = f[1];
452 tmpsrv = 1;
453 break;
455 } else {
456 switch(n){
457 case 2:
458 type = f[1];
459 /* fall through */
460 case 1:
461 name = f[0];
462 break;
466 if(name == nil)
467 return;
469 doquery(name, type);
471 if(tmpsrv)
472 setserver("");