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 <ndb.h>
5
#include <ip.h>
6
#include "dns.h"
7
 
8
enum {
9
	Nibwidth = 4,
10
	Nibmask = (1<<Nibwidth) - 1,
11
	V6maxrevdomdepth = 128 / Nibwidth,	/* bits / bits-per-nibble */
12
 
13
	/*
14
	 * ttl for generated ptr records.  it was zero, which might seem
15
	 * like a good idea, but some dns implementations seem to be
16
	 * confused by a zero ttl, and instead of using the data and then
17
	 * discarding the RR, they conclude that they don't have valid data.
18
	 */
19
	Ptrttl = 120,
20
};
21
 
22
static Ndb *db;
23
static Lock	dblock;
24
 
25
static RR*	addrrr(Ndbtuple*, Ndbtuple*);
26
static RR*	cnamerr(Ndbtuple*, Ndbtuple*);
27
static void	createptrs(void);
28
static RR*	dblookup1(char*, int, int, int);
29
static RR*	doaxfr(Ndb*, char*);
30
static Ndbtuple*look(Ndbtuple*, Ndbtuple*, char*);
31
static RR*	mxrr(Ndbtuple*, Ndbtuple*);
32
static RR*	nsrr(Ndbtuple*, Ndbtuple*);
33
static RR*	nullrr(Ndbtuple*, Ndbtuple*);
34
static RR*	ptrrr(Ndbtuple*, Ndbtuple*);
35
static RR*	soarr(Ndbtuple*, Ndbtuple*);
36
static RR*	srvrr(Ndbtuple*, Ndbtuple*);
37
static RR*	txtrr(Ndbtuple*, Ndbtuple*);
38
 
39
static int	implemented[Tall] =
40
{
41
	[Ta]		1,
42
	[Taaaa]		1,
43
	[Tcname]	1,
44
	[Tmx]		1,
45
	[Tns]		1,
46
	[Tnull]		1,
47
	[Tptr]		1,
48
	[Tsoa]		1,
49
	[Tsrv]		1,
50
	[Ttxt]		1,
51
};
52
 
53
/* straddle server configuration */
54
static Ndbtuple *indoms, *innmsrvs, *outnmsrvs;
55
 
56
static void
57
nstrcpy(char *to, char *from, int len)
58
{
59
	strncpy(to, from, len);
60
	to[len-1] = 0;
61
}
62
 
63
int
64
opendatabase(void)
65
{
66
	char netdbnm[256];
67
	Ndb *xdb, *netdb;
68
 
69
	if (db)
70
		return 0;
71
 
72
	xdb = ndbopen(dbfile);		/* /lib/ndb */
73
 
74
	snprint(netdbnm, sizeof netdbnm, "%s/ndb", mntpt);
75
	netdb = ndbopen(netdbnm);	/* /net/ndb */
76
	if(netdb)
77
		netdb->nohash = 1;
78
 
79
	db = ndbcat(netdb, xdb);	/* both */
80
	return db? 0: -1;
81
}
82
 
83
/*
84
 *  lookup an RR in the network database, look for matches
85
 *  against both the domain name and the wildcarded domain name.
86
 *
87
 *  the lock makes sure only one process can be accessing the data
88
 *  base at a time.  This is important since there's a lot of
89
 *  shared state there.
90
 *
91
 *  e.g. for x.research.bell-labs.com, first look for a match against
92
 *       the x.research.bell-labs.com.  If nothing matches,
93
 *	 try *.research.bell-labs.com.
94
 */
95
RR*
96
dblookup(char *name, int class, int type, int auth, int ttl)
97
{
98
	int err;
99
	char *wild, *cp;
100
	char buf[256];
101
	RR *rp, *tp;
102
	DN *dp, *ndp;
103
 
104
	/* so far only internet lookups are implemented */
105
	if(class != Cin)
106
		return 0;
107
 
108
	err = Rname;
109
	rp = nil;
110
 
111
	if(type == Tall){
112
		for (type = Ta; type < Tall; type++)
113
			if(implemented[type]) {
114
				tp = dblookup(name, class, type, auth, ttl);
115
				lock(&dnlock);
116
				rrcat(&rp, tp);
117
				unlock(&dnlock);
118
			}
119
		return rp;
120
	}
121
 
122
	lock(&dblock);
123
	dp = dnlookup(name, class, 1);
124
 
125
	if(opendatabase() < 0)
126
		goto out;
127
	if(dp->rr)
128
		err = 0;
129
 
130
	/* first try the given name */
131
	if(cfg.cachedb)
132
		rp = rrlookup(dp, type, NOneg);
133
	else
134
		rp = dblookup1(name, type, auth, ttl);
135
	if(rp)
136
		goto out;
137
 
138
	/* try lower case version */
139
	for(cp = name; *cp; cp++)
140
		*cp = tolower(*cp);
141
	if(cfg.cachedb)
142
		rp = rrlookup(dp, type, NOneg);
143
	else
144
		rp = dblookup1(name, type, auth, ttl);
145
	if(rp)
146
		goto out;
147
 
148
	/* walk the domain name trying the wildcard '*' at each position */
149
	for(wild = strchr(name, '.'); wild; wild = strchr(wild+1, '.')){
150
		snprint(buf, sizeof buf, "*%s", wild);
151
		ndp = dnlookup(buf, class, 1);
152
		if(ndp->rr)
153
			err = 0;
154
		if(cfg.cachedb)
155
			rp = rrlookup(ndp, type, NOneg);
156
		else
157
			rp = dblookup1(buf, type, auth, ttl);
158
		if(rp)
159
			break;
160
	}
161
out:
162
	/* add owner to uncached records */
163
	if(rp)
164
		for(tp = rp; tp; tp = tp->next)
165
			tp->owner = dp;
166
	else {
167
		/*
168
		 * don't call it non-existent if it's not ours
169
		 * (unless we're a resolver).
170
		 */
171
		if(err == Rname && (!inmyarea(name) || cfg.resolver))
172
			err = Rserver;
173
		dp->respcode = err;
174
	}
175
 
176
	unlock(&dblock);
177
	return rp;
178
}
179
 
180
static ulong
181
intval(Ndbtuple *entry, Ndbtuple *pair, char *attr, ulong def)
182
{
183
	Ndbtuple *t = look(entry, pair, attr);
184
 
185
	return (t? strtoul(t->val, 0, 10): def);
186
}
187
 
188
/*
189
 *  lookup an RR in the network database
190
 */
191
static RR*
192
dblookup1(char *name, int type, int auth, int ttl)
193
{
194
	Ndbtuple *t, *nt;
195
	RR *rp, *list, **l;
196
	Ndbs s;
197
	char dname[Domlen];
198
	char *attr;
199
	DN *dp;
200
	RR *(*f)(Ndbtuple*, Ndbtuple*);
201
	int found, x;
202
 
203
	dp = nil;
204
	switch(type){
205
	case Tptr:
206
		attr = "ptr";
207
		f = ptrrr;
208
		break;
209
	case Ta:
210
		attr = "ip";
211
		f = addrrr;
212
		break;
213
	case Taaaa:
214
		attr = "ipv6";
215
		f = addrrr;
216
		break;
217
	case Tnull:
218
		attr = "nullrr";
219
		f = nullrr;
220
		break;
221
	case Tns:
222
		attr = "ns";
223
		f = nsrr;
224
		break;
225
	case Tsoa:
226
		attr = "soa";
227
		f = soarr;
228
		break;
229
	case Tsrv:
230
		attr = "srv";
231
		f = srvrr;
232
		break;
233
	case Tmx:
234
		attr = "mx";
235
		f = mxrr;
236
		break;
237
	case Tcname:
238
		attr = "cname";
239
		f = cnamerr;
240
		break;
241
	case Taxfr:
242
	case Tixfr:
243
		return doaxfr(db, name);
244
	default:
245
//		dnslog("dnlookup1(%s) bad type", name);
246
		return nil;
247
	}
248
 
249
	/*
250
	 *  find a matching entry in the database
251
	 */
252
	t = nil;
253
	free(ndbgetvalue(db, &s, "dom", name, attr, &t));
254
 
255
	/*
256
	 *  hack for local names
257
	 */
258
	if(t == nil && strchr(name, '.') == nil)
259
		free(ndbgetvalue(db, &s, "sys", name, attr, &t));
260
	if(t == nil) {
261
//		dnslog("dnlookup1(%s) name not found", name);
262
		return nil;
263
	}
264
 
265
	/* search whole entry for default domain name */
266
	strncpy(dname, name, sizeof dname);
267
	for(nt = t; nt; nt = nt->entry)
268
		if(strcmp(nt->attr, "dom") == 0){
269
			nstrcpy(dname, nt->val, sizeof dname);
270
			break;
271
		}
272
 
273
	/* ttl is maximum of soa minttl and entry's ttl ala rfc883 */
274
	x = intval(t, s.t, "ttl", 0);
275
	if(x > ttl)
276
		ttl = x;
277
 
278
	/* default ttl is one day */
279
	if(ttl < 0)
280
		ttl = DEFTTL;
281
 
282
	/*
283
	 *  The database has 2 levels of precedence; line and entry.
284
	 *  Pairs on the same line bind tighter than pairs in the
285
	 *  same entry, so we search the line first.
286
	 */
287
	found = 0;
288
	list = 0;
289
	l = &list;
290
	for(nt = s.t;; ){
291
		if(found == 0 && strcmp(nt->attr, "dom") == 0){
292
			nstrcpy(dname, nt->val, sizeof dname);
293
			found = 1;
294
		}
295
		if(cistrcmp(attr, nt->attr) == 0){
296
			rp = (*f)(t, nt);
297
			rp->auth = auth;
298
			rp->db = 1;
299
			if(ttl)
300
				rp->ttl = ttl;
301
			if(dp == nil)
302
				dp = dnlookup(dname, Cin, 1);
303
			rp->owner = dp;
304
			*l = rp;
305
			l = &rp->next;
306
			nt->ptr = 1;
307
		}
308
		nt = nt->line;
309
		if(nt == s.t)
310
			break;
311
	}
312
 
313
	/* search whole entry */
314
	for(nt = t; nt; nt = nt->entry)
315
		if(nt->ptr == 0 && cistrcmp(attr, nt->attr) == 0){
316
			rp = (*f)(t, nt);
317
			rp->db = 1;
318
			if(ttl)
319
				rp->ttl = ttl;
320
			rp->auth = auth;
321
			if(dp == nil)
322
				dp = dnlookup(dname, Cin, 1);
323
			rp->owner = dp;
324
			*l = rp;
325
			l = &rp->next;
326
		}
327
	ndbfree(t);
328
 
329
//	dnslog("dnlookup1(%s) -> %#p", name, list);
330
	return list;
331
}
332
 
333
/*
334
 *  make various types of resource records from a database entry
335
 */
336
static RR*
337
addrrr(Ndbtuple *entry, Ndbtuple *pair)
338
{
339
	RR *rp;
340
	uchar addr[IPaddrlen];
341
 
342
	USED(entry);
343
	parseip(addr, pair->val);
344
	if(isv4(addr))
345
		rp = rralloc(Ta);
346
	else
347
		rp = rralloc(Taaaa);
348
	rp->ip = dnlookup(pair->val, Cin, 1);
349
	return rp;
350
}
351
static RR*
352
nullrr(Ndbtuple *entry, Ndbtuple *pair)
353
{
354
	RR *rp;
355
 
356
	USED(entry);
357
	rp = rralloc(Tnull);
358
	rp->null->data = (uchar*)estrdup(pair->val);
359
	rp->null->dlen = strlen((char*)rp->null->data);
360
	return rp;
361
}
362
/*
363
 *  txt rr strings are at most 255 bytes long.  one
364
 *  can represent longer strings by multiple concatenated
365
 *  <= 255 byte ones.
366
 */
367
static RR*
368
txtrr(Ndbtuple *entry, Ndbtuple *pair)
369
{
370
	RR *rp;
371
	Txt *t, **l;
372
	int i, len, sofar;
373
 
374
	USED(entry);
375
	rp = rralloc(Ttxt);
376
	l = &rp->txt;
377
	rp->txt = nil;
378
	len = strlen(pair->val);
379
	sofar = 0;
380
	while(len > sofar){
381
		t = emalloc(sizeof(*t));
382
		t->next = nil;
383
 
384
		i = len-sofar;
385
		if(i > 255)
386
			i = 255;
387
 
388
		t->p = emalloc(i+1);
389
		memmove(t->p, pair->val+sofar, i);
390
		t->p[i] = 0;
391
		sofar += i;
392
 
393
		*l = t;
394
		l = &t->next;
395
	}
396
	return rp;
397
}
398
static RR*
399
cnamerr(Ndbtuple *entry, Ndbtuple *pair)
400
{
401
	RR *rp;
402
 
403
	USED(entry);
404
	rp = rralloc(Tcname);
405
	rp->host = dnlookup(pair->val, Cin, 1);
406
	return rp;
407
}
408
static RR*
409
mxrr(Ndbtuple *entry, Ndbtuple *pair)
410
{
411
	RR *rp;
412
 
413
	rp = rralloc(Tmx);
414
	rp->host = dnlookup(pair->val, Cin, 1);
415
	rp->pref = intval(entry, pair, "pref", 1);
416
	return rp;
417
}
418
static RR*
419
nsrr(Ndbtuple *entry, Ndbtuple *pair)
420
{
421
	RR *rp;
422
	Ndbtuple *t;
423
 
424
	rp = rralloc(Tns);
425
	rp->host = dnlookup(pair->val, Cin, 1);
426
	t = look(entry, pair, "soa");
427
	if(t && t->val[0] == 0)
428
		rp->local = 1;
429
	return rp;
430
}
431
static RR*
432
ptrrr(Ndbtuple *entry, Ndbtuple *pair)
433
{
434
	RR *rp;
435
 
436
	USED(entry);
437
	rp = rralloc(Tns);
438
	rp->ptr = dnlookup(pair->val, Cin, 1);
439
	return rp;
440
}
441
static RR*
442
soarr(Ndbtuple *entry, Ndbtuple *pair)
443
{
444
	RR *rp;
445
	Ndbtuple *ns, *mb, *t;
446
	char mailbox[Domlen];
447
	Ndb *ndb;
448
	char *p;
449
 
450
	rp = rralloc(Tsoa);
451
	rp->soa->serial = 1;
452
	for(ndb = db; ndb; ndb = ndb->next)
453
		if(ndb->mtime > rp->soa->serial)
454
			rp->soa->serial = ndb->mtime;
455
 
456
	rp->soa->retry  = intval(entry, pair, "retry", Hour);
457
	rp->soa->expire = intval(entry, pair, "expire", Day);
458
	rp->soa->minttl = intval(entry, pair, "ttl", Day);
459
	rp->soa->refresh = intval(entry, pair, "refresh", Day);
460
	rp->soa->serial = intval(entry, pair, "serial", rp->soa->serial);
461
 
462
	ns = look(entry, pair, "ns");
463
	if(ns == nil)
464
		ns = look(entry, pair, "dom");
465
	rp->host = dnlookup(ns->val, Cin, 1);
466
 
467
	/* accept all of:
468
	 *  mbox=person
469
	 *  mbox=person@machine.dom
470
	 *  mbox=person.machine.dom
471
	 */
472
	mb = look(entry, pair, "mbox");
473
	if(mb == nil)
474
		mb = look(entry, pair, "mb");
475
	if(mb)
476
		if(strchr(mb->val, '.')) {
477
			p = strchr(mb->val, '@');
478
			if(p != nil)
479
				*p = '.';
480
			rp->rmb = dnlookup(mb->val, Cin, 1);
481
		} else {
482
			snprint(mailbox, sizeof mailbox, "%s.%s",
483
				mb->val, ns->val);
484
			rp->rmb = dnlookup(mailbox, Cin, 1);
485
		}
486
	else {
487
		snprint(mailbox, sizeof mailbox, "postmaster.%s", ns->val);
488
		rp->rmb = dnlookup(mailbox, Cin, 1);
489
	}
490
 
491
	/*
492
	 *  hang dns slaves off of the soa.  this is
493
	 *  for managing the area.
494
	 */
495
	for(t = entry; t != nil; t = t->entry)
496
		if(strcmp(t->attr, "dnsslave") == 0)
497
			addserver(&rp->soa->slaves, t->val);
498
 
499
	return rp;
500
}
501
 
502
static RR*
503
srvrr(Ndbtuple *entry, Ndbtuple *pair)
504
{
505
	RR *rp;
506
 
507
	rp = rralloc(Tsrv);
508
	rp->host = dnlookup(pair->val, Cin, 1);
509
	rp->srv->pri = intval(entry, pair, "pri", 0);
510
	rp->srv->weight = intval(entry, pair, "weight", 0);
511
	/* TODO: translate service name to port # */
512
	rp->port = intval(entry, pair, "port", 0);
513
	return rp;
514
}
515
 
516
/*
517
 *  Look for a pair with the given attribute.  look first on the same line,
518
 *  then in the whole entry.
519
 */
520
static Ndbtuple*
521
look(Ndbtuple *entry, Ndbtuple *line, char *attr)
522
{
523
	Ndbtuple *nt;
524
 
525
	/* first look on same line (closer binding) */
526
	for(nt = line;;){
527
		if(cistrcmp(attr, nt->attr) == 0)
528
			return nt;
529
		nt = nt->line;
530
		if(nt == line)
531
			break;
532
	}
533
	/* search whole tuple */
534
	for(nt = entry; nt; nt = nt->entry)
535
		if(cistrcmp(attr, nt->attr) == 0)
536
			return nt;
537
	return 0;
538
}
539
 
540
static RR**
541
linkrr(RR *rp, DN *dp, RR **l)
542
{
543
	rp->owner = dp;
544
	rp->auth = 1;
545
	rp->db = 1;
546
	*l = rp;
547
	return &rp->next;
548
}
549
 
550
/* these are answered specially by the tcp version */
551
static RR*
552
doaxfr(Ndb *db, char *name)
553
{
554
	USED(db, name);
555
	return 0;
556
}
557
 
558
 
559
/*
560
 *  read the all the soa's from the database to determine area's.
561
 *  this is only used when we're not caching the database.
562
 */
563
static void
564
dbfile2area(Ndb *db)
565
{
566
	Ndbtuple *t;
567
 
568
	if(debug)
569
		dnslog("rereading %s", db->file);
570
	Bseek(&db->b, 0, 0);
571
	while(t = ndbparse(db))
572
		ndbfree(t);
573
}
574
 
575
/*
576
 *  read the database into the cache
577
 */
578
static void
579
dbpair2cache(DN *dp, Ndbtuple *entry, Ndbtuple *pair)
580
{
581
	RR *rp;
582
	static ulong ord;
583
 
584
	rp = 0;
585
	if(cistrcmp(pair->attr, "ip") == 0 ||
586
	   cistrcmp(pair->attr, "ipv6") == 0){
587
		dp->ordinal = ord++;
588
		rp = addrrr(entry, pair);
589
	} else 	if(cistrcmp(pair->attr, "ns") == 0)
590
		rp = nsrr(entry, pair);
591
	else if(cistrcmp(pair->attr, "soa") == 0) {
592
		rp = soarr(entry, pair);
593
		addarea(dp, rp, pair);
594
	} else if(cistrcmp(pair->attr, "mx") == 0)
595
		rp = mxrr(entry, pair);
596
	else if(cistrcmp(pair->attr, "srv") == 0)
597
		rp = srvrr(entry, pair);
598
	else if(cistrcmp(pair->attr, "cname") == 0)
599
		rp = cnamerr(entry, pair);
600
	else if(cistrcmp(pair->attr, "nullrr") == 0)
601
		rp = nullrr(entry, pair);
602
	else if(cistrcmp(pair->attr, "txtrr") == 0)
603
		rp = txtrr(entry, pair);
604
	if(rp == nil)
605
		return;
606
 
607
	rp->owner = dp;
608
	dnagenever(dp, 1);
609
	rp->db = 1;
610
	rp->ttl = intval(entry, pair, "ttl", rp->ttl);
611
	rrattach(rp, Notauthoritative);
612
}
613
static void
614
dbtuple2cache(Ndbtuple *t)
615
{
616
	Ndbtuple *et, *nt;
617
	DN *dp;
618
 
619
	for(et = t; et; et = et->entry)
620
		if(strcmp(et->attr, "dom") == 0){
621
			dp = dnlookup(et->val, Cin, 1);
622
 
623
			/* first same line */
624
			for(nt = et->line; nt != et; nt = nt->line){
625
				dbpair2cache(dp, t, nt);
626
				nt->ptr = 1;
627
			}
628
 
629
			/* then rest of entry */
630
			for(nt = t; nt; nt = nt->entry){
631
				if(nt->ptr == 0)
632
					dbpair2cache(dp, t, nt);
633
				nt->ptr = 0;
634
			}
635
		}
636
}
637
static void
638
dbfile2cache(Ndb *db)
639
{
640
	Ndbtuple *t;
641
 
642
	if(debug)
643
		dnslog("rereading %s", db->file);
644
	Bseek(&db->b, 0, 0);
645
	while(t = ndbparse(db)){
646
		dbtuple2cache(t);
647
		ndbfree(t);
648
	}
649
}
650
 
651
/* called with dblock held */
652
static void
653
loaddomsrvs(void)
654
{
655
	Ndbs s;
656
 
657
	if (!cfg.inside || !cfg.straddle || !cfg.serve)
658
		return;
659
	if (indoms) {
660
		ndbfree(indoms);
661
		ndbfree(innmsrvs);
662
		ndbfree(outnmsrvs);
663
		indoms = innmsrvs = outnmsrvs = nil;
664
	}
665
	if (db == nil)
666
		opendatabase();
667
	free(ndbgetvalue(db, &s, "sys", "inside-dom", "dom", &indoms));
668
	free(ndbgetvalue(db, &s, "sys", "inside-ns",  "ip",  &innmsrvs));
669
	free(ndbgetvalue(db, &s, "sys", "outside-ns", "ip",  &outnmsrvs));
670
	dnslog("[%d] ndb changed: reloaded inside-dom, inside-ns, outside-ns",
671
		getpid());
672
}
673
 
674
void
675
db2cache(int doit)
676
{
677
	ulong youngest;
678
	Ndb *ndb;
679
	Dir *d;
680
	static ulong lastcheck, lastyoungest;
681
 
682
	/* no faster than once every 2 minutes */
683
	if(now < lastcheck + 2*Min && !doit)
684
		return;
685
 
686
	refresh_areas(owned);
687
 
688
	lock(&dblock);
689
 
690
	if(opendatabase() < 0){
691
		unlock(&dblock);
692
		return;
693
	}
694
 
695
	/*
696
	 *  file may be changing as we are reading it, so loop till
697
	 *  mod times are consistent.
698
	 *
699
	 *  we don't use the times in the ndb records because they may
700
	 *  change outside of refreshing our cached knowledge.
701
	 */
702
	for(;;){
703
		lastcheck = now;
704
		youngest = 0;
705
		for(ndb = db; ndb; ndb = ndb->next)
706
			/* dirfstat avoids walking the mount table each time */
707
			if((d = dirfstat(Bfildes(&ndb->b))) != nil ||
708
			   (d = dirstat(ndb->file)) != nil){
709
				if(d->mtime > youngest)
710
					youngest = d->mtime;
711
				free(d);
712
			}
713
		if(!doit && youngest == lastyoungest)
714
			break;
715
 
716
		/* forget our area definition */
717
		freearea(&owned);
718
		freearea(&delegated);
719
 
720
		/* reopen all the files (to get oldest for time stamp) */
721
		for(ndb = db; ndb; ndb = ndb->next)
722
			ndbreopen(ndb);
723
 
724
		/* reload straddle-server configuration */
725
		loaddomsrvs();
726
 
727
		if(cfg.cachedb){
728
			/* mark all db records as timed out */
729
			dnagedb();
730
 
731
			/* read in new entries */
732
			for(ndb = db; ndb; ndb = ndb->next)
733
				dbfile2cache(ndb);
734
 
735
			/* mark as authoritative anything in our domain */
736
			dnauthdb();
737
 
738
			/* remove old entries */
739
			dnageall(1);
740
		} else
741
			/* read all the soa's to get database defaults */
742
			for(ndb = db; ndb; ndb = ndb->next)
743
				dbfile2area(ndb);
744
 
745
		doit = 0;
746
		lastyoungest = youngest;
747
		createptrs();
748
	}
749
 
750
	unlock(&dblock);
751
}
752
 
753
void
754
dnforceage(void)
755
{
756
	lock(&dblock);
757
	dnageall(1);
758
	unlock(&dblock);
759
}
760
 
761
extern uchar	ipaddr[IPaddrlen];	/* my ip address */
762
 
763
/*
764
 *  get all my xxx
765
 *  caller ndbfrees the result
766
 */
767
Ndbtuple*
768
lookupinfo(char *attr)
769
{
770
	char buf[64];
771
	char *a[2];
772
	Ndbtuple *t;
773
 
774
	snprint(buf, sizeof buf, "%I", ipaddr);
775
	a[0] = attr;
776
 
777
	lock(&dblock);
778
	if(opendatabase() < 0){
779
		unlock(&dblock);
780
		return nil;
781
	}
782
	t = ndbipinfo(db, "ip", buf, a, 1);
783
	unlock(&dblock);
784
	return t;
785
}
786
 
787
char *localservers =	  "local#dns#servers";
788
char *localserverprefix = "local#dns#server";
789
 
790
/*
791
 *  return non-zero if this is a bad delegation
792
 */
793
int
794
baddelegation(RR *rp, RR *nsrp, uchar *addr)
795
{
796
	Ndbtuple *nt;
797
	static int whined;
798
	static Ndbtuple *t;
799
 
800
	if(t == nil)
801
		t = lookupinfo("dom");
802
	if(t == nil)
803
		return 0;
804
 
805
	for(; rp; rp = rp->next){
806
		if(rp->type != Tns)
807
			continue;
808
 
809
		/* see if delegation is looping */
810
		if(nsrp)
811
		if(rp->owner != nsrp->owner)
812
		if(subsume(rp->owner->name, nsrp->owner->name) &&
813
		   strcmp(nsrp->owner->name, localservers) != 0){
814
			dnslog("delegation loop %R -> %R from %I",
815
				nsrp, rp, addr);
816
			return 1;
817
		}
818
 
819
		/* see if delegating to us what we don't own */
820
		for(nt = t; nt != nil; nt = nt->entry)
821
			if(rp->host && cistrcmp(rp->host->name, nt->val) == 0)
822
				break;
823
		if(nt != nil && !inmyarea(rp->owner->name)){
824
			if (!whined) {
825
				whined = 1;
826
				dnslog("bad delegation %R from %I; "
827
					"no further logging of them", rp, addr);
828
			}
829
			return 1;
830
		}
831
	}
832
 
833
	return 0;
834
}
835
 
836
int
837
myaddr(char *addr)
838
{
839
	char *name, *line, *sp;
840
	char buf[64];
841
	Biobuf *bp;
842
 
843
	snprint(buf, sizeof buf, "%I", ipaddr);
844
	if (strcmp(addr, buf) == 0) {
845
		dnslog("rejecting my ip %s as local dns server", addr);
846
		return 1;
847
	}
848
 
849
	name = smprint("%s/ipselftab", mntpt);
850
	bp = Bopen(name, OREAD);
851
	free(name);
852
	if (bp != nil) {
853
		while ((line = Brdline(bp, '\n')) != nil) {
854
			line[Blinelen(bp) - 1] = '\0';
855
			sp = strchr(line, ' ');
856
			if (sp) {
857
				*sp = '\0';
858
				if (strcmp(addr, line) == 0) {
859
					dnslog("rejecting my ip %s as local dns server",
860
						addr);
861
					return 1;
862
				}
863
			}
864
		}
865
		Bterm(bp);
866
	}
867
	return 0;
868
}
869
 
870
static char *locdns[20];
871
static QLock locdnslck;
872
 
873
static void
874
addlocaldnsserver(DN *dp, int class, char *ipaddr, int i)
875
{
876
	int n;
877
	DN *nsdp;
878
	RR *rp;
879
	char buf[32];
880
	uchar ip[IPaddrlen];
881
 
882
	/* reject our own ip addresses so we don't query ourselves via udp */
883
	if (myaddr(ipaddr))
884
		return;
885
 
886
	qlock(&locdnslck);
887
	for (n = 0; n < i && n < nelem(locdns) && locdns[n]; n++)
888
		if (strcmp(locdns[n], ipaddr) == 0) {
889
			dnslog("rejecting duplicate local dns server ip %s",
890
				ipaddr);
891
			qunlock(&locdnslck);
892
			return;
893
		}
894
	if (n < nelem(locdns))
895
		if (locdns[n] == nil || ++n < nelem(locdns))
896
			locdns[n] = strdup(ipaddr); /* remember 1st few local ns */
897
	qunlock(&locdnslck);
898
 
899
	/* ns record for name server, make up an impossible name */
900
	rp = rralloc(Tns);
901
	snprint(buf, sizeof buf, "%s%d", localserverprefix, i);
902
	nsdp = dnlookup(buf, class, 1);
903
	rp->host = nsdp;
904
	rp->owner = dp;			/* e.g., local#dns#servers */
905
	rp->local = 1;
906
	rp->db = 1;
907
//	rp->ttl = 10*Min;		/* seems too short */
908
	rp->ttl = (1UL<<31)-1;
909
	rrattach(rp, Authoritative);	/* will not attach rrs in my area */
910
 
911
	/* A or AAAA record */
912
	if (parseip(ip, ipaddr) >= 0 && isv4(ip))
913
		rp = rralloc(Ta);
914
	else
915
		rp = rralloc(Taaaa);
916
	rp->ip = dnlookup(ipaddr, class, 1);
917
	rp->owner = nsdp;
918
	rp->local = 1;
919
	rp->db = 1;
920
//	rp->ttl = 10*Min;		/* seems too short */
921
	rp->ttl = (1UL<<31)-1;
922
	rrattach(rp, Authoritative);	/* will not attach rrs in my area */
923
 
924
	dnslog("added local dns server %s at %s", buf, ipaddr);
925
}
926
 
927
/*
928
 *  return list of dns server addresses to use when
929
 *  acting just as a resolver.
930
 */
931
RR*
932
dnsservers(int class)
933
{
934
	int i, n;
935
	char *p;
936
	char *args[5];
937
	Ndbtuple *t, *nt;
938
	RR *nsrp;
939
	DN *dp;
940
 
941
	dp = dnlookup(localservers, class, 1);
942
	nsrp = rrlookup(dp, Tns, NOneg);
943
	if(nsrp != nil)
944
		return nsrp;
945
 
946
	p = getenv("DNSSERVER");		/* list of ip addresses */
947
	if(p != nil){
948
		n = tokenize(p, args, nelem(args));
949
		for(i = 0; i < n; i++)
950
			addlocaldnsserver(dp, class, args[i], i);
951
		free(p);
952
	} else {
953
		t = lookupinfo("@dns");		/* @dns=ip1 @dns=ip2 ... */
954
		if(t == nil)
955
			return nil;
956
		i = 0;
957
		for(nt = t; nt != nil; nt = nt->entry){
958
			addlocaldnsserver(dp, class, nt->val, i);
959
			i++;
960
		}
961
		ndbfree(t);
962
	}
963
 
964
	return rrlookup(dp, Tns, NOneg);
965
}
966
 
967
static void
968
addlocaldnsdomain(DN *dp, int class, char *domain)
969
{
970
	RR *rp;
971
 
972
	/* ptr record */
973
	rp = rralloc(Tptr);
974
	rp->ptr = dnlookup(domain, class, 1);
975
	rp->owner = dp;
976
	rp->db = 1;
977
	rp->ttl = 10*Min;
978
	rrattach(rp, Authoritative);
979
}
980
 
981
/*
982
 *  return list of domains to use when resolving names without '.'s
983
 */
984
RR*
985
domainlist(int class)
986
{
987
	Ndbtuple *t, *nt;
988
	RR *rp;
989
	DN *dp;
990
 
991
	dp = dnlookup("local#dns#domains", class, 1);
992
	rp = rrlookup(dp, Tptr, NOneg);
993
	if(rp != nil)
994
		return rp;
995
 
996
	t = lookupinfo("dnsdomain");
997
	if(t == nil)
998
		return nil;
999
	for(nt = t; nt != nil; nt = nt->entry)
1000
		addlocaldnsdomain(dp, class, nt->val);
1001
	ndbfree(t);
1002
 
1003
	return rrlookup(dp, Tptr, NOneg);
1004
}
1005
 
1006
char *v4ptrdom = ".in-addr.arpa";
1007
char *v6ptrdom = ".ip6.arpa";		/* ip6.int deprecated, rfc 3152 */
1008
 
1009
char *attribs[] = {
1010
	"ipmask",
1011
 
1012
};
1013
 
1014
/*
1015
 *  create ptrs that are in our v4 areas
1016
 */
1017
static void
1018
createv4ptrs(void)
1019
{
1020
	int len, dlen, n;
1021
	char *dom;
1022
	char buf[Domlen+1], ipa[48];
1023
	char *f[40];
1024
	uchar net[IPaddrlen], mask[IPaddrlen];
1025
	Area *s;
1026
	Ndbtuple *t, *nt;
1027
 
1028
	dlen = strlen(v4ptrdom);
1029
	for(s = owned; s; s = s->next){
1030
		dom = s->soarr->owner->name;
1031
		len = strlen(dom);
1032
		if((len <= dlen || cistrcmp(dom+len-dlen, v4ptrdom) != 0) &&
1033
		    cistrcmp(dom, v4ptrdom+1) != 0)
1034
			continue;
1035
 
1036
		/* get mask and net value */
1037
		strncpy(buf, dom, sizeof buf);
1038
		buf[sizeof buf-1] = 0;
1039
		/* buf contains something like 178.204.in-addr.arpa (n==4) */
1040
		n = getfields(buf, f, nelem(f), 0, ".");
1041
		memset(mask, 0xff, IPaddrlen);
1042
		ipmove(net, v4prefix);
1043
		switch(n){
1044
		case 3:			/* /8 */
1045
			net[IPv4off] = atoi(f[0]);
1046
			mask[IPv4off+1] = 0;
1047
			mask[IPv4off+2] = 0;
1048
			mask[IPv4off+3] = 0;
1049
			break;
1050
		case 4:			/* /16 */
1051
			net[IPv4off] = atoi(f[1]);
1052
			net[IPv4off+1] = atoi(f[0]);
1053
			mask[IPv4off+2] = 0;
1054
			mask[IPv4off+3] = 0;
1055
			break;
1056
		case 5:			/* /24 */
1057
			net[IPv4off] = atoi(f[2]);
1058
			net[IPv4off+1] = atoi(f[1]);
1059
			net[IPv4off+2] = atoi(f[0]);
1060
			mask[IPv4off+3] = 0;
1061
			break;
1062
		case 6:		/* rfc2317: classless in-addr.arpa delegation */
1063
			net[IPv4off] = atoi(f[3]);
1064
			net[IPv4off+1] = atoi(f[2]);
1065
			net[IPv4off+2] = atoi(f[1]);
1066
			net[IPv4off+3] = atoi(f[0]);
1067
			sprint(ipa, "%I", net);
1068
			t = ndbipinfo(db, "ip", ipa, attribs, 1);
1069
			if(t == nil)	/* could be a reverse with no forward */
1070
				continue;
1071
			nt = look(t, t, "ipmask");
1072
			if(nt == nil){		/* we're confused */
1073
				ndbfree(t);
1074
				continue;
1075
			}
1076
			parseipmask(mask, nt->val);
1077
			ndbfree(t);
1078
			n = 5;
1079
			break;
1080
		default:
1081
			continue;
1082
		}
1083
 
1084
		/*
1085
		 * go through all domain entries looking for RR's
1086
		 * in this network and create ptrs.
1087
		 * +2 for ".in-addr.arpa".
1088
		 */
1089
		dnptr(net, mask, dom, Ta, 4+2-n, Ptrttl);
1090
	}
1091
}
1092
 
1093
/* convert bytes to nibbles, big-endian */
1094
void
1095
bytes2nibbles(uchar *nibbles, uchar *bytes, int nbytes)
1096
{
1097
	while (nbytes-- > 0) {
1098
		*nibbles++ = *bytes >> Nibwidth;
1099
		*nibbles++ = *bytes++ & Nibmask;
1100
	}
1101
}
1102
 
1103
void
1104
nibbles2bytes(uchar *bytes, uchar *nibbles, int nnibs)
1105
{
1106
	for (; nnibs >= 2; nnibs -= 2) {
1107
		*bytes++ = nibbles[0] << Nibwidth | (nibbles[1]&Nibmask);
1108
		nibbles += 2;
1109
	}
1110
	if (nnibs > 0)
1111
		*bytes = nibbles[0] << Nibwidth;
1112
}
1113
 
1114
/*
1115
 *  create ptrs that are in our v6 areas.  see rfc3596
1116
 */
1117
static void
1118
createv6ptrs(void)
1119
{
1120
	int len, dlen, i, n, pfxnibs;
1121
	char *dom;
1122
	char buf[Domlen+1];
1123
	char *f[40];
1124
	uchar net[IPaddrlen], mask[IPaddrlen];
1125
	uchar nibnet[IPaddrlen*2], nibmask[IPaddrlen*2];
1126
	Area *s;
1127
 
1128
	dlen = strlen(v6ptrdom);
1129
	for(s = owned; s; s = s->next){
1130
		dom = s->soarr->owner->name;
1131
		len = strlen(dom);
1132
		if((len <= dlen || cistrcmp(dom+len-dlen, v6ptrdom) != 0) &&
1133
		    cistrcmp(dom, v6ptrdom+1) != 0)
1134
			continue;
1135
 
1136
		/* get mask and net value */
1137
		strncpy(buf, dom, sizeof buf);
1138
		buf[sizeof buf-1] = 0;
1139
		/* buf contains something like 2.0.0.2.ip6.arpa (n==6) */
1140
		n = getfields(buf, f, nelem(f), 0, ".");
1141
		pfxnibs = n - 2;		/* 2 for .ip6.arpa */
1142
		if (pfxnibs < 0 || pfxnibs > V6maxrevdomdepth)
1143
			continue;
1144
 
1145
		memset(net, 0, IPaddrlen);
1146
		memset(mask, 0xff, IPaddrlen);
1147
		bytes2nibbles(nibnet, net, IPaddrlen);
1148
		bytes2nibbles(nibmask, mask, IPaddrlen);
1149
 
1150
		/* copy prefix of f, in reverse order, to start of net. */
1151
		for (i = 0; i < pfxnibs; i++)
1152
			nibnet[i] = strtol(f[pfxnibs - 1 - i], nil, 16);
1153
		/* zero nibbles of mask after prefix in net */
1154
		memset(nibmask + pfxnibs, 0, V6maxrevdomdepth - pfxnibs);
1155
 
1156
		nibbles2bytes(net, nibnet, 2*IPaddrlen);
1157
		nibbles2bytes(mask, nibmask, 2*IPaddrlen);
1158
 
1159
		/*
1160
		 * go through all domain entries looking for RR's
1161
		 * in this network and create ptrs.
1162
		 */
1163
		dnptr(net, mask, dom, Taaaa, V6maxrevdomdepth - pfxnibs, Ptrttl);
1164
	}
1165
}
1166
 
1167
/*
1168
 *  create ptrs that are in our areas
1169
 */
1170
static void
1171
createptrs(void)
1172
{
1173
	createv4ptrs();
1174
	createv6ptrs();
1175
}
1176
 
1177
/*
1178
 * is this domain (or DOMAIN or Domain or dOMAIN)
1179
 * internal to our organisation (behind our firewall)?
1180
 * only inside straddling servers care, everybody else gets told `yes',
1181
 * so they'll use mntpt for their queries.
1182
 */
1183
int
1184
insideaddr(char *dom)
1185
{
1186
	int domlen, vallen, rv;
1187
	Ndbtuple *t;
1188
 
1189
	if (!cfg.inside || !cfg.straddle || !cfg.serve)
1190
		return 1;
1191
	if (dom[0] == '\0' || strcmp(dom, ".") == 0)	/* dns root? */
1192
		return 1;			/* hack for initialisation */
1193
 
1194
	lock(&dblock);
1195
	if (indoms == nil)
1196
		loaddomsrvs();
1197
	if (indoms == nil) {
1198
		unlock(&dblock);
1199
		return 1;  /* no "inside-dom" sys, try inside nameservers */
1200
	}
1201
 
1202
	rv = 0;
1203
	domlen = strlen(dom);
1204
	for (t = indoms; t != nil; t = t->entry) {
1205
		if (strcmp(t->attr, "dom") != 0)
1206
			continue;
1207
		vallen = strlen(t->val);
1208
		if (cistrcmp(dom, t->val) == 0 ||
1209
		    domlen > vallen &&
1210
		     cistrcmp(dom + domlen - vallen, t->val) == 0 &&
1211
		     dom[domlen - vallen - 1] == '.') {
1212
			rv = 1;
1213
			break;
1214
		}
1215
	}
1216
	unlock(&dblock);
1217
	return rv;
1218
}
1219
 
1220
int
1221
insidens(uchar *ip)
1222
{
1223
	uchar ipa[IPaddrlen];
1224
	Ndbtuple *t;
1225
 
1226
	for (t = innmsrvs; t != nil; t = t->entry)
1227
		if (strcmp(t->attr, "ip") == 0) {
1228
			parseip(ipa, t->val);
1229
			if (memcmp(ipa, ip, sizeof ipa) == 0)
1230
				return 1;
1231
		}
1232
	return 0;
1233
}
1234
 
1235
uchar *
1236
outsidens(int n)
1237
{
1238
	int i;
1239
	Ndbtuple *t;
1240
	static uchar ipa[IPaddrlen];
1241
 
1242
	i = 0;
1243
	for (t = outnmsrvs; t != nil; t = t->entry)
1244
		if (strcmp(t->attr, "ip") == 0 && i++ == n) {
1245
			parseip(ipa, t->val);
1246
			return ipa;
1247
		}
1248
	return nil;
1249
}