Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include <u.h>
2
#include <libc.h>
3
#include <auth.h>
4
#include <fcall.h>
5
#include <bio.h>
6
#include <ctype.h>
7
#include <ip.h>
8
#include <pool.h>
9
#include "dns.h"
10
 
11
enum
12
{
13
	Maxrequest=		1024,
14
	Maxreply=		8192,		/* was 512 */
15
	Maxrrr=			32,		/* was 16 */
16
	Maxfdata=		8192,
17
 
18
	Defmaxage=		60*60,	/* default domain name max. age */
19
 
20
	Qdir=			0,
21
	Qdns=			1,
22
};
23
 
24
typedef struct Mfile	Mfile;
25
typedef struct Job	Job;
26
typedef struct Network	Network;
27
 
28
extern	ulong	start;
29
 
30
int vers;		/* incremented each clone/attach */
31
 
32
static volatile int stop;
33
 
34
/* holds data to be returned via read of /net/dns, perhaps multiple reads */
35
struct Mfile
36
{
37
	Mfile		*next;		/* next free mfile */
38
	int		ref;
39
 
40
	char		*user;
41
	Qid		qid;
42
	int		fid;
43
 
44
	int		type;		/* reply type */
45
	char		reply[Maxreply];
46
	ushort		rr[Maxrrr];	/* offset of rr's */
47
	ushort		nrr;		/* number of rr's */
48
};
49
 
50
/*
51
 *  active local requests
52
 */
53
struct Job
54
{
55
	Job	*next;
56
	int	flushed;
57
	Fcall	request;
58
	Fcall	reply;
59
};
60
Lock	joblock;
61
Job	*joblist;
62
 
63
struct {
64
	Lock;
65
	Mfile	*inuse;		/* active mfile's */
66
} mfalloc;
67
 
68
Cfg	cfg;
69
int	debug;
70
uchar	ipaddr[IPaddrlen];	/* my ip address */
71
int	maxage = Defmaxage;
72
int	mfd[2];
73
int	needrefresh;
74
ulong	now;
75
vlong	nowns;
76
int	sendnotifies;
77
int	testing;
78
char	*trace;
79
int	traceactivity;
80
char	*zonerefreshprogram;
81
 
82
char	*logfile = "dns";	/* or "dns.test" */
83
char	*dbfile;
84
char	mntpt[Maxpath];
85
 
86
int	addforwtarg(char *);
87
int	fillreply(Mfile*, int);
88
void	freejob(Job*);
89
void	io(void);
90
void	mountinit(char*, char*);
91
Job*	newjob(void);
92
void	rattach(Job*, Mfile*);
93
void	rauth(Job*);
94
void	rclunk(Job*, Mfile*);
95
void	rcreate(Job*, Mfile*);
96
void	rflush(Job*);
97
void	ropen(Job*, Mfile*);
98
void	rread(Job*, Mfile*);
99
void	rremove(Job*, Mfile*);
100
void	rstat(Job*, Mfile*);
101
void	rversion(Job*);
102
char*	rwalk(Job*, Mfile*);
103
void	rwrite(Job*, Mfile*, Request*);
104
void	rwstat(Job*, Mfile*);
105
void	sendmsg(Job*, char*);
106
void	setext(char*, int, char*);
107
 
108
static char *lookupqueryold(Job*, Mfile*, Request*, char*, char*, int, int);
109
static char *lookupquerynew(Job*, Mfile*, Request*, char*, char*, int, int);
110
static char *respond(Job*, Mfile*, RR*, char*, int, int);
111
 
112
void
113
usage(void)
114
{
115
	fprint(2, "usage: %s [-FnorRst] [-a maxage] [-f ndb-file] [-N target] "
116
		"[-T forwip] [-x netmtpt] [-z refreshprog]\n", argv0);
117
	exits("usage");
118
}
119
 
120
void
121
justremount(char *service, char *mntpt)
122
{
123
	int f;
124
 
125
	f = open(service, ORDWR);
126
	if(f < 0)
127
		abort(); 	/* service */;
128
	while (mount(f, -1, mntpt, MAFTER, "") < 0) {
129
		dnslog("dns mount -a on %s failed: %r", mntpt);
130
		sleep(5000);
131
	}
132
}
133
 
134
void
135
main(int argc, char *argv[])
136
{
137
	int kid, pid;
138
	char servefile[Maxpath], ext[Maxpath];
139
	Dir *dir;
140
 
141
	setnetmtpt(mntpt, sizeof mntpt, nil);
142
	ext[0] = 0;
143
	ARGBEGIN{
144
	case 'a':
145
		maxage = atol(EARGF(usage()));
146
		if (maxage <= 0)
147
			maxage = Defmaxage;
148
		break;
149
	case 'd':
150
		debug = 1;
151
		traceactivity = 1;
152
		break;
153
	case 'f':
154
		dbfile = EARGF(usage());
155
		break;
156
	case 'F':
157
		cfg.justforw = cfg.resolver = 1;
158
		break;
159
	case 'n':
160
		sendnotifies = 1;
161
		break;
162
	case 'N':
163
		target = atol(EARGF(usage()));
164
		if (target < 1000)
165
			target = 1000;
166
		break;
167
	case 'o':
168
		cfg.straddle = 1;	/* straddle inside & outside networks */
169
		break;
170
	case 'r':
171
		cfg.resolver = 1;
172
		break;
173
	case 'R':
174
		norecursion = 1;
175
		break;
176
	case 's':
177
		cfg.serve = 1;		/* serve network */
178
		cfg.cachedb = 1;
179
		break;
180
	case 't':
181
		testing = 1;
182
		break;
183
	case 'T':
184
		addforwtarg(EARGF(usage()));
185
		break;
186
	case 'x':
187
		setnetmtpt(mntpt, sizeof mntpt, EARGF(usage()));
188
		setext(ext, sizeof ext, mntpt);
189
		break;
190
	case 'z':
191
		zonerefreshprogram = EARGF(usage());
192
		break;
193
	default:
194
		usage();
195
		break;
196
	}ARGEND
197
	if(argc != 0)
198
		usage();
199
 
200
	if(testing)
201
		mainmem->flags |= POOL_NOREUSE | POOL_ANTAGONISM;
202
	mainmem->flags |= POOL_ANTAGONISM;
203
	rfork(RFREND|RFNOTEG);
204
 
205
	cfg.inside = (*mntpt == '\0' || strcmp(mntpt, "/net") == 0);
206
 
207
	/* start syslog before we fork */
208
	fmtinstall('F', fcallfmt);
209
	dninit();
210
	/* this really shouldn't be fatal */
211
	if(myipaddr(ipaddr, mntpt) < 0)
212
		sysfatal("can't read my ip address");
213
	dnslog("starting %s%sdns %s%s%son %I's %s",
214
		(cfg.straddle? "straddling ": ""),
215
		(cfg.cachedb? "caching ": ""),
216
		(cfg.serve?   "udp server ": ""),
217
		(cfg.justforw? "forwarding-only ": ""),
218
		(cfg.resolver? "resolver ": ""), ipaddr, mntpt);
219
 
220
	opendatabase();
221
	now = time(nil);		/* open time files before we fork */
222
	nowns = nsec();
223
 
224
	snprint(servefile, sizeof servefile, "#s/dns%s", ext);
225
	dir = dirstat(servefile);
226
	if (dir)
227
		sysfatal("%s exists; another dns instance is running",
228
			servefile);
229
	free(dir);
230
 
231
	/* don't unmount here; could deadlock */
232
//	while (unmount(servefile, mntpt) >= 0)
233
//		;
234
	mountinit(servefile, mntpt);	/* forks, parent exits */
235
 
236
	srand(now*getpid());
237
	db2cache(1);
238
//	dnageallnever();
239
 
240
	if (cfg.straddle && !seerootns())
241
		dnslog("straddle server misconfigured; can't resolve root name servers");
242
	/*
243
	 * fork without sharing heap.
244
	 * parent waits around for child to die, then forks & restarts.
245
	 * child may spawn udp server, notify procs, etc.; when it gets too
246
	 * big or too old, it kills itself and any children.
247
	 *
248
	 * /srv/dns remains open and valid, but /net/dns was only mounted in
249
	 * a child's separate namespace from 9p service, to avoid a deadlock
250
	 * from serving our own namespace, so we must remount it upon restart,
251
	 * in a separate process and namespace.
252
	 */
253
	for (;;) {
254
		start = time(nil);
255
		/* don't unmount here; could deadlock */
256
//		unmount(servefile, mntpt);
257
		kid = rfork(RFPROC|RFFDG|RFNOTEG|RFNAMEG);
258
		switch (kid) {
259
		case -1:
260
			sysfatal("fork failed: %r");
261
		case 0:
262
			if(cfg.serve)
263
				dnudpserver(mntpt);
264
			if(sendnotifies)
265
				notifyproc();
266
			io();		/* serve 9p; return implies restart */
267
			_exits("restart");
268
		}
269
		sleep(1000);	/* wait for 9p service to start */
270
		justremount(servefile, mntpt);
271
		while ((pid = waitpid()) != kid && pid != -1)
272
			continue;
273
		dnslog("restarting");
274
	}
275
}
276
 
277
/*
278
 *  if a mount point is specified, set the cs extension to be the mount point
279
 *  with '_'s replacing '/'s
280
 */
281
void
282
setext(char *ext, int n, char *p)
283
{
284
	int i, c;
285
 
286
	n--;
287
	for(i = 0; i < n; i++){
288
		c = p[i];
289
		if(c == 0)
290
			break;
291
		if(c == '/')
292
			c = '_';
293
		ext[i] = c;
294
	}
295
	ext[i] = 0;
296
}
297
 
298
void
299
mountinit(char *service, char *mntpt)
300
{
301
	int f;
302
	int p[2];
303
	char buf[32];
304
 
305
	if(pipe(p) < 0)
306
		abort(); /* "pipe failed" */;
307
	switch(rfork(RFFDG|RFPROC)){
308
	case 0:			/* child: hang around and (re)start main proc */
309
		close(p[1]);
310
		procsetname("%s restarter", mntpt);
311
		mfd[0] = mfd[1] = p[0];
312
		break;
313
	case -1:
314
		abort(); /* "fork failed\n" */;
315
	default:		/* parent: make /srv/dns, mount it, exit */
316
		close(p[0]);
317
 
318
		/*
319
		 *  make a /srv/dns
320
		 */
321
		f = create(service, 1, 0666);
322
		if(f < 0)
323
			abort(); /* service */;
324
		snprint(buf, sizeof buf, "%d", p[1]);
325
		if(write(f, buf, strlen(buf)) != strlen(buf))
326
			abort(); /* "write %s", service */;
327
		close(f);
328
 
329
		/*
330
		 *  put ourselves into the file system
331
		 *  it's too soon; we need 9p service running.
332
		 */
333
//		if(mount(p[1], -1, mntpt, MAFTER, "") < 0)
334
//			dnslog("dns mount -a on %s failed: %r", mntpt);
335
		close(p[1]);
336
		_exits(0);
337
	}
338
}
339
 
340
Mfile*
341
newfid(int fid, int needunused)
342
{
343
	Mfile *mf;
344
 
345
	lock(&mfalloc);
346
	for(mf = mfalloc.inuse; mf != nil; mf = mf->next)
347
		if(mf->fid == fid){
348
			unlock(&mfalloc);
349
			if(needunused)
350
				return nil;
351
			return mf;
352
		}
353
	mf = emalloc(sizeof(*mf));
354
	mf->fid = fid;
355
	mf->user = estrdup("dummy");
356
	mf->next = mfalloc.inuse;
357
	mfalloc.inuse = mf;
358
	unlock(&mfalloc);
359
	return mf;
360
}
361
 
362
void
363
freefid(Mfile *mf)
364
{
365
	Mfile **l;
366
 
367
	lock(&mfalloc);
368
	for(l = &mfalloc.inuse; *l != nil; l = &(*l)->next)
369
		if(*l == mf){
370
			*l = mf->next;
371
			if(mf->user)
372
				free(mf->user);
373
			memset(mf, 0, sizeof *mf);	/* cause trouble */
374
			free(mf);
375
			unlock(&mfalloc);
376
			return;
377
		}
378
	unlock(&mfalloc);
379
	sysfatal("freeing unused fid");
380
}
381
 
382
Mfile*
383
copyfid(Mfile *mf, int fid)
384
{
385
	Mfile *nmf;
386
 
387
	nmf = newfid(fid, 1);
388
	if(nmf == nil)
389
		return nil;
390
	nmf->fid = fid;
391
	free(nmf->user);			/* estrdup("dummy") */
392
	nmf->user = estrdup(mf->user);
393
	nmf->qid.type = mf->qid.type;
394
	nmf->qid.path = mf->qid.path;
395
	nmf->qid.vers = vers++;
396
	return nmf;
397
}
398
 
399
Job*
400
newjob(void)
401
{
402
	Job *job;
403
 
404
	job = emalloc(sizeof *job);
405
	lock(&joblock);
406
	job->next = joblist;
407
	joblist = job;
408
	job->request.tag = -1;
409
	unlock(&joblock);
410
	return job;
411
}
412
 
413
void
414
freejob(Job *job)
415
{
416
	Job **l;
417
 
418
	lock(&joblock);
419
	for(l = &joblist; *l; l = &(*l)->next)
420
		if(*l == job){
421
			*l = job->next;
422
			memset(job, 0, sizeof *job);	/* cause trouble */
423
			free(job);
424
			break;
425
		}
426
	unlock(&joblock);
427
}
428
 
429
void
430
flushjob(int tag)
431
{
432
	Job *job;
433
 
434
	lock(&joblock);
435
	for(job = joblist; job; job = job->next)
436
		if(job->request.tag == tag && job->request.type != Tflush){
437
			job->flushed = 1;
438
			break;
439
		}
440
	unlock(&joblock);
441
}
442
 
443
void
444
io(void)
445
{
446
	volatile long n;
447
	volatile uchar mdata[IOHDRSZ + Maxfdata];
448
	Job *volatile job;
449
	Mfile *volatile mf;
450
	volatile Request req;
451
 
452
	memset(&req, 0, sizeof req);
453
	/*
454
	 *  a slave process is sometimes forked to wait for replies from other
455
	 *  servers.  The master process returns immediately via a longjmp
456
	 *  through 'mret'.
457
	 */
458
	if(setjmp(req.mret))
459
		putactivity(0);
460
	req.isslave = 0;
461
	stop = 0;
462
	while(!stop){
463
		procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms",
464
			stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms);
465
		n = read9pmsg(mfd[0], mdata, sizeof mdata);
466
		if(n<=0){
467
			dnslog("error reading 9P from %s: %r", mntpt);
468
			sleep(2000);	/* don't thrash after read error */
469
			return;
470
		}
471
 
472
		stats.qrecvd9prpc++;
473
		job = newjob();
474
		if(convM2S(mdata, n, &job->request) != n){
475
			freejob(job);
476
			continue;
477
		}
478
		mf = newfid(job->request.fid, 0);
479
		if(debug)
480
			dnslog("%F", &job->request);
481
 
482
		getactivity(&req, 0);
483
		req.aborttime = timems() + Maxreqtm;
484
		req.from = "9p";
485
 
486
		switch(job->request.type){
487
		default:
488
			warning("unknown request type %d", job->request.type);
489
			break;
490
		case Tversion:
491
			rversion(job);
492
			break;
493
		case Tauth:
494
			rauth(job);
495
			break;
496
		case Tflush:
497
			rflush(job);
498
			break;
499
		case Tattach:
500
			rattach(job, mf);
501
			break;
502
		case Twalk:
503
			rwalk(job, mf);
504
			break;
505
		case Topen:
506
			ropen(job, mf);
507
			break;
508
		case Tcreate:
509
			rcreate(job, mf);
510
			break;
511
		case Tread:
512
			rread(job, mf);
513
			break;
514
		case Twrite:
515
			/* &req is handed to dnresolve() */
516
			rwrite(job, mf, &req);
517
			break;
518
		case Tclunk:
519
			rclunk(job, mf);
520
			break;
521
		case Tremove:
522
			rremove(job, mf);
523
			break;
524
		case Tstat:
525
			rstat(job, mf);
526
			break;
527
		case Twstat:
528
			rwstat(job, mf);
529
			break;
530
		}
531
 
532
		freejob(job);
533
 
534
		/*
535
		 *  slave processes die after replying
536
		 */
537
		if(req.isslave){
538
			putactivity(0);
539
			_exits(0);
540
		}
541
 
542
		putactivity(0);
543
	}
544
	/* kill any udp server, notifier, etc. processes */
545
	postnote(PNGROUP, getpid(), "die");
546
	sleep(1000);
547
}
548
 
549
void
550
rversion(Job *job)
551
{
552
	if(job->request.msize > IOHDRSZ + Maxfdata)
553
		job->reply.msize = IOHDRSZ + Maxfdata;
554
	else
555
		job->reply.msize = job->request.msize;
556
	if(strncmp(job->request.version, "9P2000", 6) != 0)
557
		sendmsg(job, "unknown 9P version");
558
	else{
559
		job->reply.version = "9P2000";
560
		sendmsg(job, 0);
561
	}
562
}
563
 
564
void
565
rauth(Job *job)
566
{
567
	sendmsg(job, "dns: authentication not required");
568
}
569
 
570
/*
571
 *  don't flush till all the slaves are done
572
 */
573
void
574
rflush(Job *job)
575
{
576
	flushjob(job->request.oldtag);
577
	sendmsg(job, 0);
578
}
579
 
580
void
581
rattach(Job *job, Mfile *mf)
582
{
583
	if(mf->user != nil)
584
		free(mf->user);
585
	mf->user = estrdup(job->request.uname);
586
	mf->qid.vers = vers++;
587
	mf->qid.type = QTDIR;
588
	mf->qid.path = 0LL;
589
	job->reply.qid = mf->qid;
590
	sendmsg(job, 0);
591
}
592
 
593
char*
594
rwalk(Job *job, Mfile *mf)
595
{
596
	int i, nelems;
597
	char *err;
598
	char **elems;
599
	Mfile *nmf;
600
	Qid qid;
601
 
602
	err = 0;
603
	nmf = nil;
604
	elems  = job->request.wname;
605
	nelems = job->request.nwname;
606
	job->reply.nwqid = 0;
607
 
608
	if(job->request.newfid != job->request.fid){
609
		/* clone fid */
610
		nmf = copyfid(mf, job->request.newfid);
611
		if(nmf == nil){
612
			err = "clone bad newfid";
613
			goto send;
614
		}
615
		mf = nmf;
616
	}
617
	/* else nmf will be nil */
618
 
619
	qid = mf->qid;
620
	if(nelems > 0)
621
		/* walk fid */
622
		for(i=0; i<nelems && i<MAXWELEM; i++){
623
			if((qid.type & QTDIR) == 0){
624
				err = "not a directory";
625
				break;
626
			}
627
			if (strcmp(elems[i], "..") == 0 ||
628
			    strcmp(elems[i], ".") == 0){
629
				qid.type = QTDIR;
630
				qid.path = Qdir;
631
Found:
632
				job->reply.wqid[i] = qid;
633
				job->reply.nwqid++;
634
				continue;
635
			}
636
			if(strcmp(elems[i], "dns") == 0){
637
				qid.type = QTFILE;
638
				qid.path = Qdns;
639
				goto Found;
640
			}
641
			err = "file does not exist";
642
			break;
643
		}
644
 
645
send:
646
	if(nmf != nil && (err!=nil || job->reply.nwqid<nelems))
647
		freefid(nmf);
648
	if(err == nil)
649
		mf->qid = qid;
650
	sendmsg(job, err);
651
	return err;
652
}
653
 
654
void
655
ropen(Job *job, Mfile *mf)
656
{
657
	int mode;
658
	char *err;
659
 
660
	err = 0;
661
	mode = job->request.mode;
662
	if(mf->qid.type & QTDIR)
663
		if(mode)
664
			err = "permission denied";
665
	job->reply.qid = mf->qid;
666
	job->reply.iounit = 0;
667
	sendmsg(job, err);
668
}
669
 
670
void
671
rcreate(Job *job, Mfile *mf)
672
{
673
	USED(mf);
674
	sendmsg(job, "creation permission denied");
675
}
676
 
677
void
678
rread(Job *job, Mfile *mf)
679
{
680
	int i, n;
681
	long clock;
682
	ulong cnt;
683
	vlong off;
684
	char *err;
685
	uchar buf[Maxfdata];
686
	Dir dir;
687
 
688
	n = 0;
689
	err = nil;
690
	off = job->request.offset;
691
	cnt = job->request.count;
692
	*buf = '\0';
693
	job->reply.data = (char*)buf;
694
	if(mf->qid.type & QTDIR){
695
		clock = time(nil);
696
		if(off == 0){
697
			memset(&dir, 0, sizeof dir);
698
			dir.name = "dns";
699
			dir.qid.type = QTFILE;
700
			dir.qid.vers = vers;
701
			dir.qid.path = Qdns;
702
			dir.mode = 0666;
703
			dir.length = 0;
704
			dir.uid = dir.gid = dir.muid = mf->user;
705
			dir.atime = dir.mtime = clock;		/* wrong */
706
			n = convD2M(&dir, buf, sizeof buf);
707
		}
708
	} else if (off < 0)
709
		err = "negative read offset";
710
	else {
711
		/* first offset will always be zero */
712
		for(i = 1; i <= mf->nrr; i++)
713
			if(mf->rr[i] > off)
714
				break;
715
		if(i <= mf->nrr) {
716
			if(off + cnt > mf->rr[i])
717
				n = mf->rr[i] - off;
718
			else
719
				n = cnt;
720
			assert(n >= 0);
721
			job->reply.data = mf->reply + off;
722
		}
723
	}
724
	job->reply.count = n;
725
	sendmsg(job, err);
726
}
727
 
728
void
729
rwrite(Job *job, Mfile *mf, Request *req)
730
{
731
	int rooted, wantsav, send;
732
	ulong cnt;
733
	char *err, *p, *atype;
734
	char errbuf[ERRMAX];
735
 
736
	err = nil;
737
	cnt = job->request.count;
738
	send = 1;
739
	if(mf->qid.type & QTDIR)
740
		err = "can't write directory";
741
	else if (job->request.offset != 0)
742
		err = "writing at non-zero offset";
743
	else if(cnt >= Maxrequest)
744
		err = "request too long";
745
	else
746
		send = 0;
747
	if (send)
748
		goto send;
749
 
750
	job->request.data[cnt] = 0;
751
	if(cnt > 0 && job->request.data[cnt-1] == '\n')
752
		job->request.data[cnt-1] = 0;
753
 
754
	/*
755
	 *  special commands
756
	 */
757
//	dnslog("rwrite got: %s", job->request.data);
758
	send = 1;
759
	if(strcmp(job->request.data, "age")==0){
760
		dnslog("dump, age & dump forced");
761
		dndump("/lib/ndb/dnsdump1");
762
		dnforceage();
763
		dndump("/lib/ndb/dnsdump2");
764
	} else if(strcmp(job->request.data, "debug")==0)
765
		debug ^= 1;
766
	else if(strcmp(job->request.data, "dump")==0)
767
		dndump("/lib/ndb/dnsdump");
768
	else if(strcmp(job->request.data, "poolcheck")==0)
769
		poolcheck(mainmem);
770
	else if(strcmp(job->request.data, "refresh")==0)
771
		needrefresh = 1;
772
	else if(strcmp(job->request.data, "restart")==0)
773
		stop = 1;
774
	else if(strcmp(job->request.data, "stats")==0)
775
		dnstats("/lib/ndb/dnsstats");
776
	else if(strncmp(job->request.data, "target ", 7)==0){
777
		target = atol(job->request.data + 7);
778
		dnslog("target set to %ld", target);
779
	} else
780
		send = 0;
781
	if (send)
782
		goto send;
783
 
784
	/*
785
	 *  kill previous reply
786
	 */
787
	mf->nrr = 0;
788
	mf->rr[0] = 0;
789
 
790
	/*
791
	 *  break up request (into a name and a type)
792
	 */
793
	atype = strchr(job->request.data, ' ');
794
	if(atype == 0){
795
		snprint(errbuf, sizeof errbuf, "illegal request %s",
796
			job->request.data);
797
		err = errbuf;
798
		goto send;
799
	} else
800
		*atype++ = 0;
801
 
802
	/*
803
	 *  tracing request
804
	 */
805
	if(strcmp(atype, "trace") == 0){
806
		if(trace)
807
			free(trace);
808
		if(*job->request.data)
809
			trace = estrdup(job->request.data);
810
		else
811
			trace = 0;
812
		goto send;
813
	}
814
 
815
	/* normal request: domain [type] */
816
	stats.qrecvd9p++;
817
	mf->type = rrtype(atype);
818
	if(mf->type < 0){
819
		snprint(errbuf, sizeof errbuf, "unknown type %s", atype);
820
		err = errbuf;
821
		goto send;
822
	}
823
 
824
	p = atype - 2;
825
	if(p >= job->request.data && *p == '.'){
826
		rooted = 1;
827
		*p = 0;
828
	} else
829
		rooted = 0;
830
 
831
	p = job->request.data;
832
	if(*p == '!'){
833
		wantsav = 1;
834
		p++;
835
	} else
836
		wantsav = 0;
837
 
838
	err = lookupqueryold(job, mf, req, errbuf, p, wantsav, rooted);
839
send:
840
	dncheck(0, 1);
841
	job->reply.count = cnt;
842
	sendmsg(job, err);
843
}
844
 
845
/*
846
 * dnsdebug calls
847
 *	rr = dnresolve(buf, Cin, type, &req, 0, 0, Recurse, rooted, 0);
848
 * which generates a UDP query, which eventually calls
849
 *	dnserver(&reqmsg, &repmsg, &req, buf, rcode);
850
 * which calls
851
 *	rp = dnresolve(name, Cin, type, req, &mp->an, 0, recurse, 1, 0);
852
 *
853
 * but here we just call dnresolve directly.
854
 */
855
static char *
856
lookupqueryold(Job *job, Mfile *mf, Request *req, char *errbuf, char *p,
857
	int wantsav, int rooted)
858
{
859
	int status;
860
	RR *rp, *neg;
861
 
862
	dncheck(0, 1);
863
	status = Rok;
864
	rp = dnresolve(p, Cin, mf->type, req, 0, 0, Recurse, rooted, &status);
865
 
866
	dncheck(0, 1);
867
	lock(&dnlock);
868
	neg = rrremneg(&rp);
869
	if(neg){
870
		status = neg->negrcode;
871
		rrfreelist(neg);
872
	}
873
	unlock(&dnlock);
874
 
875
	return respond(job, mf, rp, errbuf, status, wantsav);
876
}
877
 
878
static char *
879
respond(Job *job, Mfile *mf, RR *rp, char *errbuf, int status, int wantsav)
880
{
881
	long n;
882
	RR *tp;
883
 
884
	if(rp == nil)
885
		switch(status){
886
		case Rname:
887
			return "name does not exist";
888
		case Rserver:
889
			return "dns failure";
890
		case Rok:
891
		default:
892
			snprint(errbuf, ERRMAX,
893
				"resource does not exist; negrcode %d", status);
894
			return errbuf;
895
		}
896
 
897
	lock(&joblock);
898
	if(!job->flushed){
899
		/* format data to be read later */
900
		n = 0;
901
		mf->nrr = 0;
902
		for(tp = rp; mf->nrr < Maxrrr-1 && n < Maxreply && tp &&
903
		    tsame(mf->type, tp->type); tp = tp->next){
904
			mf->rr[mf->nrr++] = n;
905
			if(wantsav)
906
				n += snprint(mf->reply+n, Maxreply-n, "%Q", tp);
907
			else
908
				n += snprint(mf->reply+n, Maxreply-n, "%R", tp);
909
		}
910
		mf->rr[mf->nrr] = n;
911
	}
912
	unlock(&joblock);
913
	rrfreelist(rp);
914
	return nil;
915
}
916
 
917
#ifdef notused
918
/* simulate what dnsudpserver does */
919
static char *
920
lookupquerynew(Job *job, Mfile *mf, Request *req, char *errbuf, char *p,
921
	int wantsav, int)
922
{
923
	char *err;
924
	uchar buf[Udphdrsize + Maxpayload];
925
	DNSmsg *mp;
926
	DNSmsg repmsg;
927
	RR *rp;
928
 
929
	dncheck(0, 1);
930
 
931
	memset(&repmsg, 0, sizeof repmsg);
932
	rp = rralloc(mf->type);
933
	rp->owner = dnlookup(p, Cin, 1);
934
	mp = newdnsmsg(rp, Frecurse|Oquery, (ushort)rand());
935
 
936
	/* BUG: buf is srcip, yet it's uninitialised */
937
	dnserver(mp, &repmsg, req, buf, Rok);
938
 
939
	freeanswers(mp);
940
	err = respond(job, mf, repmsg.an, errbuf, Rok, wantsav);
941
	repmsg.an = nil;		/* freed above */
942
	freeanswers(&repmsg);
943
	return err;
944
}
945
#endif
946
 
947
void
948
rclunk(Job *job, Mfile *mf)
949
{
950
	freefid(mf);
951
	sendmsg(job, 0);
952
}
953
 
954
void
955
rremove(Job *job, Mfile *mf)
956
{
957
	USED(mf);
958
	sendmsg(job, "remove permission denied");
959
}
960
 
961
void
962
rstat(Job *job, Mfile *mf)
963
{
964
	Dir dir;
965
	uchar buf[IOHDRSZ+Maxfdata];
966
 
967
	memset(&dir, 0, sizeof dir);
968
	if(mf->qid.type & QTDIR){
969
		dir.name = ".";
970
		dir.mode = DMDIR|0555;
971
	} else {
972
		dir.name = "dns";
973
		dir.mode = 0666;
974
	}
975
	dir.qid = mf->qid;
976
	dir.length = 0;
977
	dir.uid = dir.gid = dir.muid = mf->user;
978
	dir.atime = dir.mtime = time(nil);
979
	job->reply.nstat = convD2M(&dir, buf, sizeof buf);
980
	job->reply.stat = buf;
981
	sendmsg(job, 0);
982
}
983
 
984
void
985
rwstat(Job *job, Mfile *mf)
986
{
987
	USED(mf);
988
	sendmsg(job, "wstat permission denied");
989
}
990
 
991
void
992
sendmsg(Job *job, char *err)
993
{
994
	int n;
995
	uchar mdata[IOHDRSZ + Maxfdata];
996
	char ename[ERRMAX];
997
 
998
	if(err){
999
		job->reply.type = Rerror;
1000
		snprint(ename, sizeof ename, "dns: %s", err);
1001
		job->reply.ename = ename;
1002
	}else
1003
		job->reply.type = job->request.type+1;
1004
	job->reply.tag = job->request.tag;
1005
	n = convS2M(&job->reply, mdata, sizeof mdata);
1006
	if(n == 0){
1007
		warning("sendmsg convS2M of %F returns 0", &job->reply);
1008
		abort();
1009
	}
1010
	lock(&joblock);
1011
	if(job->flushed == 0)
1012
		if(write(mfd[1], mdata, n)!=n)
1013
			sysfatal("mount write");
1014
	unlock(&joblock);
1015
	if(debug)
1016
		dnslog("%F %d", &job->reply, n);
1017
}
1018
 
1019
/*
1020
 *  the following varies between dnsdebug and dns
1021
 */
1022
void
1023
logreply(int id, uchar *addr, DNSmsg *mp)
1024
{
1025
	RR *rp;
1026
 
1027
	dnslog("%d: rcvd %I flags:%s%s%s%s%s", id, addr,
1028
		mp->flags & Fauth? " auth": "",
1029
		mp->flags & Ftrunc? " trunc": "",
1030
		mp->flags & Frecurse? " rd": "",
1031
		mp->flags & Fcanrec? " ra": "",
1032
		(mp->flags & (Fauth|Rmask)) == (Fauth|Rname)? " nx": "");
1033
	for(rp = mp->qd; rp != nil; rp = rp->next)
1034
		dnslog("%d: rcvd %I qd %s", id, addr, rp->owner->name);
1035
	for(rp = mp->an; rp != nil; rp = rp->next)
1036
		dnslog("%d: rcvd %I an %R", id, addr, rp);
1037
	for(rp = mp->ns; rp != nil; rp = rp->next)
1038
		dnslog("%d: rcvd %I ns %R", id, addr, rp);
1039
	for(rp = mp->ar; rp != nil; rp = rp->next)
1040
		dnslog("%d: rcvd %I ar %R", id, addr, rp);
1041
}
1042
 
1043
void
1044
logsend(int id, int subid, uchar *addr, char *sname, char *rname, int type)
1045
{
1046
	char buf[12];
1047
 
1048
	dnslog("[%d] %d.%d: sending to %I/%s %s %s",
1049
		getpid(), id, subid, addr, sname, rname,
1050
		rrname(type, buf, sizeof buf));
1051
}
1052
 
1053
RR*
1054
getdnsservers(int class)
1055
{
1056
	return dnsservers(class);
1057
}