]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/ndb/dnsdebug.c
ip/ipconfig, ndb/dns, libndb: handle parseipmask() errors
[plan9front.git] / sys / src / cmd / ndb / dnsdebug.c
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"
8
9 enum {
10         Maxrequest=             128,
11 };
12
13 Cfg cfg;
14
15 static char *servername;
16 static RR *serveraddrs;
17
18 char    *dbfile;
19 int     debug;
20 char    *logfile = "dnsdebug";
21 int     maxage  = 60*60;
22 char    mntpt[Maxpath];
23 int     needrefresh;
24 ulong   now;
25 vlong   nowns;
26 char    *trace;
27 int     traceactivity;
28 char    *zonerefreshprogram;
29
30 void    docmd(int, char**);
31 void    doquery(char*, char*);
32 void    preloadserveraddrs(void);
33 int     prettyrrfmt(Fmt*);
34 int     setserver(char*);
35 void    squirrelserveraddrs(void);
36
37 void
38 usage(void)
39 {
40         fprint(2, "%s: [-rx] [-f db-file] [[@server] domain [type]]\n", argv0);
41         exits("usage");
42 }
43
44 void
45 main(int argc, char *argv[])
46 {
47         int n;
48         Biobuf in;
49         char *p;
50         char *f[4];
51
52         strcpy(mntpt, "/net");
53         cfg.inside = 1;
54
55         ARGBEGIN{
56         case 'f':
57                 dbfile = EARGF(usage());
58                 break;
59         case 'r':
60                 cfg.resolver = 1;
61                 break;
62         case 'x':
63                 dbfile = "/lib/ndb/external";
64                 strcpy(mntpt, "/net.alt");
65                 break;
66         default:
67                 usage();
68         }ARGEND
69
70         now = time(nil);
71         nowns = nsec();
72         dninit();
73         fmtinstall('R', prettyrrfmt);
74         opendatabase();
75         srand(truerand());
76
77         if(cfg.resolver)
78                 squirrelserveraddrs();
79
80         debug = 1;
81
82         if(argc > 0){
83                 docmd(argc, argv);
84                 exits(0);
85         }
86
87         Binit(&in, 0, OREAD);
88         for(print("> "); p = Brdline(&in, '\n'); print("> ")){
89                 p[Blinelen(&in)-1] = 0;
90                 n = tokenize(p, f, 3);
91                 if(n>=1) {
92                         dnpurge();              /* flush the cache */
93                         docmd(n, f);
94                 }
95         }
96         exits(0);
97 }
98
99 static char*
100 longtime(long t)
101 {
102         int d, h, m, n;
103         static char x[128];
104
105         for(d = 0; t >= 24*60*60; t -= 24*60*60)
106                 d++;
107         for(h = 0; t >= 60*60; t -= 60*60)
108                 h++;
109         for(m = 0; t >= 60; t -= 60)
110                 m++;
111         n = 0;
112         if(d)
113                 n += sprint(x, "%d day ", d);
114         if(h)
115                 n += sprint(x+n, "%d hr ", h);
116         if(m)
117                 n += sprint(x+n, "%d min ", m);
118         if(t || n == 0)
119                 sprint(x+n, "%ld sec", t);
120         return x;
121 }
122
123 /*
124  *  convert address into a reverse lookup address
125  */
126 static void
127 mkptrname(char *ip, char *rip, int rlen)
128 {
129         uchar a[IPaddrlen];
130         char *p, *e;
131         int i;
132
133         if(cistrstr(ip, "in-addr.arpa") || cistrstr(ip, "ip6.arpa") || parseip(a, ip) == -1)
134                 snprint(rip, rlen, "%s", ip);
135         else if(isv4(a))
136                 snprint(rip, rlen, "%ud.%ud.%ud.%ud.in-addr.arpa",
137                         a[15], a[14], a[13], a[12]);
138         else{
139                 p = rip;
140                 e = rip + rlen;
141                 for(i = 15; i >= 0; i--){
142                         p = seprint(p, e, "%ux.", a[i]&0xf);
143                         p = seprint(p, e, "%ux.", a[i]>>4);
144                 }
145                 seprint(p, e, "ip6.arpa");
146         }
147 }
148
149 int
150 prettyrrfmt(Fmt *f)
151 {
152         RR *rp;
153         char buf[3*Domlen];
154         char *p, *e;
155         Txt *t;
156
157         rp = va_arg(f->args, RR*);
158         if(rp == 0){
159                 strcpy(buf, "<null>");
160                 goto out;
161         }
162
163         p = buf;
164         e = buf + sizeof(buf);
165         p = seprint(p, e, "%-32.32s %-15.15s %-5.5s", rp->owner->name,
166                 longtime(rp->ttl),
167                 rrname(rp->type, buf, sizeof buf));
168
169         if(rp->negative){
170                 seprint(p, e, "negative rcode %d", rp->negrcode);
171                 goto out;
172         }
173
174         switch(rp->type){
175         case Thinfo:
176                 seprint(p, e, "\t%s %s", rp->cpu->name, rp->os->name);
177                 break;
178         case Tcname:
179         case Tmb:
180         case Tmd:
181         case Tmf:
182         case Tns:
183                 seprint(p, e, "\t%s", (rp->host? rp->host->name: ""));
184                 break;
185         case Tmg:
186         case Tmr:
187                 seprint(p, e, "\t%s", (rp->mb? rp->mb->name: ""));
188                 break;
189         case Tminfo:
190                 seprint(p, e, "\t%s %s", (rp->mb? rp->mb->name: ""),
191                         (rp->rmb? rp->rmb->name: ""));
192                 break;
193         case Tmx:
194                 seprint(p, e, "\t%lud %s", rp->pref,
195                         (rp->host? rp->host->name: ""));
196                 break;
197         case Ta:
198         case Taaaa:
199                 seprint(p, e, "\t%s", (rp->ip? rp->ip->name: ""));
200                 break;
201         case Tptr:
202                 seprint(p, e, "\t%s", (rp->ptr? rp->ptr->name: ""));
203                 break;
204         case Tsoa:
205                 seprint(p, e, "\t%s %s %lud %lud %lud %lud %lud",
206                         rp->host->name, rp->rmb->name, rp->soa->serial,
207                         rp->soa->refresh, rp->soa->retry,
208                         rp->soa->expire, rp->soa->minttl);
209                 break;
210         case Tsrv:
211                 seprint(p, e, "\t%ud %ud %ud %s",
212                         rp->srv->pri, rp->srv->weight, rp->port, rp->host->name);
213                 break;
214         case Tnull:
215                 seprint(p, e, "\t%.*H", rp->null->dlen, rp->null->data);
216                 break;
217         case Ttxt:
218                 p = seprint(p, e, "\t");
219                 for(t = rp->txt; t != nil; t = t->next)
220                         p = seprint(p, e, "%s", t->p);
221                 break;
222         case Trp:
223                 seprint(p, e, "\t%s %s", rp->rmb->name, rp->rp->name);
224                 break;
225         case Tkey:
226                 seprint(p, e, "\t%d %d %d", rp->key->flags, rp->key->proto,
227                         rp->key->alg);
228                 break;
229         case Tsig:
230                 seprint(p, e, "\t%d %d %d %lud %lud %lud %d %s",
231                         rp->sig->type, rp->sig->alg, rp->sig->labels,
232                         rp->sig->ttl, rp->sig->exp, rp->sig->incep,
233                         rp->sig->tag, rp->sig->signer->name);
234                 break;
235         case Tcert:
236                 seprint(p, e, "\t%d %d %d",
237                         rp->sig->type, rp->sig->tag, rp->sig->alg);
238                 break;
239         }
240 out:
241         return fmtstrcpy(f, buf);
242 }
243
244 void
245 logsection(char *flag, RR *rp)
246 {
247         if(rp == nil)
248                 return;
249         print("\t%s%R\n", flag, rp);
250         for(rp = rp->next; rp != nil; rp = rp->next)
251                 print("\t      %R\n", rp);
252 }
253
254 void
255 logreply(int id, uchar *addr, DNSmsg *mp)
256 {
257         RR *rp;
258         char buf[12], resp[32];
259
260         switch(mp->flags & Rmask){
261         case Rok:
262                 strcpy(resp, "OK");
263                 break;
264         case Rformat:
265                 strcpy(resp, "Format error");
266                 break;
267         case Rserver:
268                 strcpy(resp, "Server failed");
269                 break;
270         case Rname:
271                 strcpy(resp, "Nonexistent");
272                 break;
273         case Runimplimented:
274                 strcpy(resp, "Unimplemented");
275                 break;
276         case Rrefused:
277                 strcpy(resp, "Refused");
278                 break;
279         default:
280                 sprint(resp, "%d", mp->flags & Rmask);
281                 break;
282         }
283
284         print("%d: rcvd %s from %I (%s%s%s%s%s)\n", id, resp, addr,
285                 mp->flags & Fauth? "authoritative": "",
286                 mp->flags & Ftrunc? " truncated": "",
287                 mp->flags & Frecurse? " recurse": "",
288                 mp->flags & Fcanrec? " can_recurse": "",
289                 (mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
290         for(rp = mp->qd; rp != nil; rp = rp->next)
291                 print("\tQ:    %s %s\n", rp->owner->name,
292                         rrname(rp->type, buf, sizeof buf));
293         logsection("Ans:  ", mp->an);
294         logsection("Auth: ", mp->ns);
295         logsection("Hint: ", mp->ar);
296 }
297
298 void
299 logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
300 {
301         char buf[12];
302
303         print("%d.%d: sending to %I/%s %s %s\n", id, subid,
304                 addr, sname, rname, rrname(type, buf, sizeof buf));
305 }
306
307 RR*
308 getdnsservers(int class)
309 {
310         RR *rr;
311
312         if(servername == nil)
313                 return dnsservers(class);
314
315         rr = rralloc(Tns);
316         rr->owner = dnlookup("local#dns#servers", class, 1);
317         rr->host = idnlookup(servername, class, 1);
318
319         return rr;
320 }
321
322 void
323 squirrelserveraddrs(void)
324 {
325         int v4;
326         char *attr;
327         RR *rr, *rp, **l;
328         Request req;
329
330         /* look up the resolver address first */
331         cfg.resolver = 0;
332         debug = 0;
333         if(serveraddrs){
334                 rrfreelist(serveraddrs);
335                 serveraddrs = nil;
336         }
337         rr = getdnsservers(Cin);
338         l = &serveraddrs;
339         for(rp = rr; rp != nil; rp = rp->next){
340                 attr = ipattr(rp->host->name);
341                 v4 = strcmp(attr, "ip") == 0;
342                 if(v4 || strcmp(attr, "ipv6") == 0){
343                         *l = rralloc(v4? Ta: Taaaa);
344                         (*l)->owner = rp->host;
345                         (*l)->ip = rp->host;
346                         l = &(*l)->next;
347                         continue;
348                 }
349                 memset(&req, 0, sizeof req);
350                 req.isslave = 1;
351                 req.aborttime = NS2MS(nowns) + Maxreqtm;
352                 *l = dnresolve(rp->host->name, Cin, Ta, &req, nil, 0, Recurse, 0, nil);
353                 if(*l == nil)
354                         *l = dnresolve(rp->host->name, Cin, Taaaa, &req,
355                                 nil, 0, Recurse, 0, nil);
356                 while(*l != nil)
357                         l = &(*l)->next;
358         }
359         cfg.resolver = 1;
360         debug = 1;
361 }
362
363 void
364 preloadserveraddrs(void)
365 {
366         RR *rp, **l, *first;
367
368         first = nil;
369         l = &first;
370         for(rp = serveraddrs; rp != nil; rp = rp->next){
371                 rrcopy(rp, l);
372                 rrattach(first, Authoritative);
373         }
374 }
375
376 int
377 setserver(char *server)
378 {
379         if(servername != nil){
380                 free(servername);
381                 servername = nil;
382                 cfg.resolver = 0;
383         }
384         if(server == nil || *server == 0)
385                 return 0;
386         servername = strdup(server);
387         squirrelserveraddrs();
388         if(serveraddrs == nil){
389                 print("can't resolve %s\n", servername);
390                 cfg.resolver = 0;
391         } else
392                 cfg.resolver = 1;
393         return cfg.resolver? 0: -1;
394 }
395
396 void
397 doquery(char *name, char *tstr)
398 {
399         int len, type, rooted;
400         char buf[1024];
401         RR *rr, *rp;
402         Request req;
403
404         if(cfg.resolver)
405                 preloadserveraddrs();
406
407         /* default to an "ip" request if alpha, "ptr" if numeric */
408         if(tstr == nil || *tstr == 0)
409                 if(strcmp(ipattr(name), "ip") == 0)
410                         tstr = "ptr";
411                 else
412                         tstr = "ip";
413
414         /* look it up */
415         type = rrtype(tstr);
416         if(type < 0){
417                 print("!unknown type %s\n", tstr);
418                 return;
419         }
420
421         /* if name end in '.', remove it */
422         len = strlen(name);
423         if(len > 0 && name[len-1] == '.'){
424                 rooted = 1;
425                 name[len-1] = 0;
426         } else
427                 rooted = 0;
428
429         /* inverse queries may need to be permuted */
430         if(type == Tptr)
431                 mkptrname(name, buf, sizeof buf);
432         else
433                 strncpy(buf, name, sizeof buf);
434
435         memset(&req, 0, sizeof req);
436         getactivity(&req, 0);
437         req.isslave = 1;
438         req.aborttime = NS2MS(nowns) + Maxreqtm;
439         rr = dnresolve(buf, Cin, type, &req, nil, 0, Recurse, rooted, nil);
440         if(rr){
441                 print("----------------------------\n");
442                 for(rp = rr; rp; rp = rp->next)
443                         print("answer %R\n", rp);
444                 print("----------------------------\n");
445         }
446         rrfreelist(rr);
447
448         putactivity(0);
449 }
450
451 void
452 docmd(int n, char **f)
453 {
454         int tmpsrv;
455         char *name, *type;
456
457         name = type = nil;
458         tmpsrv = 0;
459
460         if(*f[0] == '@') {
461                 if(setserver(f[0]+1) < 0)
462                         return;
463
464                 switch(n){
465                 case 3:
466                         type = f[2];
467                         /* fall through */
468                 case 2:
469                         name = f[1];
470                         tmpsrv = 1;
471                         break;
472                 }
473         } else
474                 switch(n){
475                 case 2:
476                         type = f[1];
477                         /* fall through */
478                 case 1:
479                         name = f[0];
480                         break;
481                 }
482
483         if(name == nil)
484                 return;
485
486         doquery(name, type);
487
488         if(tmpsrv)
489                 setserver("");
490 }