Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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