⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dn.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 2 页
字号:
#include <u.h>#include <libc.h>#include <ip.h>#include <pool.h>#include <ctype.h>#include "dns.h"/* *  Hash table for domain names.  The hash is based only on the *  first element of the domain name. */DN	*ht[HTLEN];static struct{	Lock;	ulong	names;	/* names allocated */	ulong	oldest;	/* longest we'll leave a name around */	int	active;	int	mutex;	int	id;} dnvars;/* names of RR types */char *rrtname[] ={[Ta]		"ip",[Tns]		"ns",[Tmd]		"md",[Tmf]		"mf",[Tcname]	"cname",[Tsoa]		"soa",[Tmb]		"mb",[Tmg]		"mg",[Tmr]		"mr",[Tnull]		"null",[Twks]		"wks",[Tptr]		"ptr",[Thinfo]	"hinfo",[Tminfo]	"minfo",[Tmx]		"mx",[Ttxt]		"txt",[Trp]		"rp",[Tafsdb]	"afsdb",[Tx25]		"x.25",[Tisdn]		"isdn",[Trt]		"rt",[Tnsap]		"nsap",[Tnsapptr]	"nsap-ptr",[Tsig]		"sig",[Tkey]		"key",[Tpx]		"px",[Tgpos]		"gpos",[Taaaa]		"ipv6",[Tloc]		"loc",[Tnxt]		"nxt",[Teid]		"eid",[Tnimloc]	"nimrod",[Tsrv]		"srv",[Tatma]		"atma",[Tnaptr]	"naptr",[Tkx]		"kx",[Tcert]		"cert",[Ta6]		"a6",[Tdname]	"dname",[Tsink]		"sink",[Topt]		"opt",[Tapl]		"apl",[Tds]		"ds",[Tsshfp]	"sshfp",[Tipseckey]	"ipseckey",[Trrsig]	"rrsig",[Tnsec]		"nsec",[Tdnskey]	"dnskey",[Tspf]		"spf",[Tuinfo]	"uinfo",[Tuid]		"uid",[Tgid]		"gid",[Tunspec]	"unspec",[Ttkey]		"tkey",[Ttsig]		"tsig",[Tixfr]		"ixfr",[Taxfr]		"axfr",[Tmailb]	"mailb",[Tmaila]	"maila",[Tall]		"all",		0,};/* names of response codes */char *rname[Rmask+1] ={[Rok]			"ok",[Rformat]		"format error",[Rserver]		"server failure",[Rname]			"bad name",[Runimplimented]	"unimplemented",[Rrefused]		"we don't like you",[Ryxdomain]		"name should not exist",[Ryxrrset]		"rr set should not exist",[Rnxrrset]		"rr set should exist",[Rnotauth]		"not authorative",[Rnotzone]		"not in zone",[Rbadvers]		"bad opt version",/* [Rbadsig]		"bad signature", */[Rbadkey]		"bad key",[Rbadtime]		"bad signature time",[Rbadmode]		"bad mode",[Rbadname]		"duplicate key name",[Rbadalg]		"bad algorithm",};/* names of op codes */char *opname[] ={[Oquery]	"query",[Oinverse]	"inverse query (retired)",[Ostatus]	"status",[Oupdate]	"update",};Lock	dnlock;static int sencodefmt(Fmt*);/* *  set up a pipe to use as a lock */voiddninit(void){	fmtinstall('E', eipfmt);	fmtinstall('I', eipfmt);	fmtinstall('V', eipfmt);	fmtinstall('R', rrfmt);	fmtinstall('Q', rravfmt);	fmtinstall('H', sencodefmt);	dnvars.oldest = maxage;	dnvars.names = 0;}/* *  hash for a domain name */static ulongdnhash(char *name){	ulong hash;	uchar *val = (uchar*)name;	for(hash = 0; *val; val++)		hash = (hash*13) + tolower(*val)-'a';	return hash % HTLEN;}/* *  lookup a symbol.  if enter is not zero and the name is *  not found, create it. */DN*dnlookup(char *name, int class, int enter){	DN **l;	DN *dp;	l = &ht[dnhash(name)];	lock(&dnlock);	for(dp = *l; dp; dp = dp->next) {		assert(dp->magic == DNmagic);		if(dp->class == class && cistrcmp(dp->name, name) == 0){			dp->referenced = now;			unlock(&dnlock);			return dp;		}		l = &dp->next;	}	if(enter == 0){		unlock(&dnlock);		return 0;	}	dnvars.names++;	dp = emalloc(sizeof(*dp));	dp->magic = DNmagic;	dp->name = estrdup(name);	assert(dp->name != 0);	dp->class = class;	dp->rr = 0;	dp->next = 0;	dp->referenced = now;	*l = dp;	unlock(&dnlock);	return dp;}/* *  dump the cache */voiddndump(char *file){	DN *dp;	int i, fd;	RR *rp;	fd = open(file, OWRITE|OTRUNC);	if(fd < 0)		return;	lock(&dnlock);	for(i = 0; i < HTLEN; i++){		for(dp = ht[i]; dp; dp = dp->next){			fprint(fd, "%s\n", dp->name);			for(rp = dp->rr; rp; rp = rp->next)				fprint(fd, "	%R %c%c %lud/%lud\n", rp, rp->auth?'A':'U',					rp->db?'D':'N', rp->expire, rp->ttl);		}	}	unlock(&dnlock);	close(fd);}/* *  purge all records */voiddnpurge(void){	DN *dp;	RR *rp, *srp;	int i;	lock(&dnlock);	for(i = 0; i < HTLEN; i++)		for(dp = ht[i]; dp; dp = dp->next){			srp = rp = dp->rr;			dp->rr = nil;			for(; rp != nil; rp = rp->next)				rp->cached = 0;			rrfreelist(srp);		}	unlock(&dnlock);}/* *  check the age of resource records, free any that have timed out */voiddnage(DN *dp){	RR **l;	RR *rp, *next;	ulong diff;	diff = now - dp->referenced;	if(diff < Reserved)		return;	l = &dp->rr;	for(rp = dp->rr; rp; rp = next){		assert(rp->magic == RRmagic && rp->cached);		next = rp->next;		if(!rp->db)		if(rp->expire < now || diff > dnvars.oldest){			*l = next;			rp->cached = 0;			rrfree(rp);			continue;		}		l = &rp->next;	}}#define REF(x) if(x) x->refs++/* *  our target is 4000 names cached, this should be larger on large servers */#define TARGET 4000/* *  periodicly sweep for old records and remove unreferenced domain names * *  only called when all other threads are locked out */voiddnageall(int doit){	DN *dp, **l;	int i;	RR *rp;	static ulong nextage;	if(dnvars.names < TARGET && now < nextage && !doit){		dnvars.oldest = maxage;		return;	}	if(dnvars.names > TARGET)		dnvars.oldest /= 2;	nextage = now + maxage;	lock(&dnlock);	/* time out all old entries (and set refs to 0) */	for(i = 0; i < HTLEN; i++)		for(dp = ht[i]; dp; dp = dp->next){			dp->refs = 0;			dnage(dp);		}	/* mark all referenced domain names */	for(i = 0; i < HTLEN; i++)		for(dp = ht[i]; dp; dp = dp->next)			for(rp = dp->rr; rp; rp = rp->next){				REF(rp->owner);				if(rp->negative){					REF(rp->negsoaowner);					continue;				}				switch(rp->type){				case Thinfo:					REF(rp->cpu);					REF(rp->os);					break;				case Ttxt:					break;				case Tcname:				case Tmb:				case Tmd:				case Tmf:				case Tns:					REF(rp->host);					break;				case Tmg:				case Tmr:					REF(rp->mb);					break;				case Tminfo:					REF(rp->rmb);					REF(rp->mb);					break;				case Trp:					REF(rp->rmb);					REF(rp->rp);					break;				case Tmx:					REF(rp->host);					break;				case Ta:				case Taaaa:					REF(rp->ip);					break;				case Tptr:					REF(rp->ptr);					break;				case Tsoa:					REF(rp->host);					REF(rp->rmb);					break;				}			}	/* sweep and remove unreferenced domain names */	for(i = 0; i < HTLEN; i++){		l = &ht[i];		for(dp = *l; dp; dp = *l){			if(dp->rr == 0 && dp->refs == 0){				assert(dp->magic == DNmagic);				*l = dp->next;				if(dp->name)					free(dp->name);				dp->magic = ~dp->magic;				dnvars.names--;				free(dp);				continue;			}			l = &dp->next;		}	}	unlock(&dnlock);}/* *  timeout all database records (used when rereading db) */voiddnagedb(void){	DN *dp;	int i;	RR *rp;	static ulong nextage;	lock(&dnlock);	/* time out all database entries */	for(i = 0; i < HTLEN; i++)		for(dp = ht[i]; dp; dp = dp->next)			for(rp = dp->rr; rp; rp = rp->next)				if(rp->db)					rp->expire = 0;	unlock(&dnlock);}/* *  mark all local db records about my area as authoritative, time out any others */voiddnauthdb(void){	DN *dp;	int i;	Area *area;	RR *rp;	static ulong nextage;	lock(&dnlock);	/* time out all database entries */	for(i = 0; i < HTLEN; i++)		for(dp = ht[i]; dp; dp = dp->next){			area = inmyarea(dp->name);			for(rp = dp->rr; rp; rp = rp->next)				if(rp->db){					if(area){						if(rp->ttl < area->soarr->soa->minttl)							rp->ttl = area->soarr->soa->minttl;						rp->auth = 1;					}					if(rp->expire == 0){						rp->db = 0;						dp->referenced = now - Reserved - 1;					}				}		}	unlock(&dnlock);}/* *  keep track of other processes to know if we can *  garbage collect.  block while garbage collecting. */intgetactivity(Request *req, int recursive){	int rv;	if(traceactivity) syslog(0, "dns", "get %d by %d from %p", dnvars.active, getpid(), getcallerpc(&req));	lock(&dnvars);	/*	 * can't block here if we're already holding one	 * of the dnvars.active (recursive).  will deadlock.	 */	while(!recursive && dnvars.mutex){		unlock(&dnvars);		sleep(200);		lock(&dnvars);	}	rv = ++dnvars.active;	now = time(0);	req->id = ++dnvars.id;	unlock(&dnvars);	return rv;}voidputactivity(int recursive){	static ulong lastclean;	if(traceactivity) syslog(0, "dns", "put %d by %d", dnvars.active, getpid());	lock(&dnvars);	dnvars.active--;	assert(dnvars.active >= 0); /* "dnvars.active %d", dnvars.active */;	/*	 *  clean out old entries and check for new db periodicly	 *  can't block here if being called to let go a "recursive" lock	 *  or we'll deadlock waiting for ourselves to give up the dnvars.active.	 */	if(recursive || dnvars.mutex || (needrefresh == 0 && dnvars.active > 0)){		unlock(&dnvars);		return;	}	/* wait till we're alone */	dnvars.mutex = 1;	while(dnvars.active > 0){		unlock(&dnvars);		sleep(100);		lock(&dnvars);	}	unlock(&dnvars);	db2cache(needrefresh);	dnageall(0);	/* let others back in */	lastclean = now;	needrefresh = 0;	dnvars.mutex = 0;}/* *  Attach a single resource record to a domain name. *	- Avoid duplicates with already present RR's *	- Chain all RR's of the same type adjacent to one another *	- chain authoritative RR's ahead of non-authoritative ones */static voidrrattach1(RR *new, int auth){	RR **l;	RR *rp;	DN *dp;	assert(new->magic == RRmagic && !new->cached);	if(!new->db)		new->expire = new->ttl;	else		new->expire = now + Year;	dp = new->owner;	assert(dp->magic == DNmagic);	new->auth |= auth;	new->next = 0;	/*	 *  find first rr of the right type	 */	l = &dp->rr;	for(rp = *l; rp; rp = *l){		assert(rp->magic == RRmagic && rp->cached);		if(rp->type == new->type)			break;		l = &rp->next;	}	/*	 *  negative entries replace positive entries	 *  positive entries replace negative entries	 *  newer entries replace older entries with the same fields	 */	for(rp = *l; rp; rp = *l){		assert(rp->magic == RRmagic && rp->cached);		if(rp->type != new->type)			break;		if(rp->db == new->db && rp->auth == new->auth){			/* negative drives out positive and vice versa */			if(rp->negative != new->negative){				*l = rp->next;				rp->cached = 0;				rrfree(rp);				continue;			}			/* all things equal, pick the newer one */			if(rp->arg0 == new->arg0 && rp->arg1 == new->arg1){				/* new drives out old */				if(new->ttl > rp->ttl || new->expire > rp->expire){					*l = rp->next;					rp->cached = 0;					rrfree(rp);					continue;				} else {					rrfree(new);					return;				}			}			/*  Hack for pointer records.  This makes sure			 *  the ordering in the list reflects the ordering			 *  received or read from the database			 */			if(rp->type == Tptr){				if(!rp->negative && !new->negative				&& rp->ptr->ordinal > new->ptr->ordinal)					break;			}		}		l = &rp->next;	}	/*	 *  add to chain	 */	new->cached = 1;	new->next = *l;	*l = new;}/* *  Attach a list of resource records to a domain name. *	- Avoid duplicates with already present RR's *	- Chain all RR's of the same type adjacent to one another *	- chain authoritative RR's ahead of non-authoritative ones *	- remove any expired RR's */voidrrattach(RR *rp, int auth){	RR *next;	lock(&dnlock);	for(; rp; rp = next){		next = rp->next;		rp->next = 0;		/* avoid any outside spoofing */		if(cachedb && !rp->db && inmyarea(rp->owner->name))			rrfree(rp);		else			rrattach1(rp, auth);	}	unlock(&dnlock);}/* *  allocate a resource record of a given type */RR*rralloc(int type){	RR *rp;	rp = emalloc(sizeof(*rp));	rp->magic = RRmagic;	rp->pc = getcallerpc(&type);	rp->type = type;	switch(type){	case Tsoa:		rp->soa = emalloc(sizeof(*rp->soa));		rp->soa->slaves = nil;		break;	case Tkey:		rp->key = emalloc(sizeof(*rp->key));		break;	case Tcert:		rp->cert = emalloc(sizeof(*rp->cert));		break;	case Tsig:		rp->sig = emalloc(sizeof(*rp->sig));		break;	case Tnull:		rp->null = emalloc(sizeof(*rp->null));		break;	}	rp->ttl = 0;	rp->expire = 0;	rp->next = 0;	return rp;}/* *  free a resource record and any related structs */voidrrfree(RR *rp){	DN *dp;	RR *nrp;	Txt *t;	assert(rp->magic = RRmagic);	assert(!rp->cached);	dp = rp->owner;	if(dp){		assert(dp->magic == DNmagic);		for(nrp = dp->rr; nrp; nrp = nrp->next)			assert(nrp != rp); /* "rrfree of live rr" */;	}	switch(rp->type){	case Tsoa:		freeserverlist(rp->soa->slaves);		free(rp->soa);		break;	case Tkey:		free(rp->key->data);		free(rp->key);		break;	case Tcert:		free(rp->cert->data);		free(rp->cert);		break;	case Tsig:		free(rp->sig->data);		free(rp->sig);		break;	case Tnull:		free(rp->null->data);		free(rp->null);		break;	case Ttxt:		while(rp->txt != nil){			t = rp->txt;			rp->txt = t->next;			free(t->p);			free(t);		}		break;	}	rp->magic = ~rp->magic;	free(rp);}/* *  free a list of resource records and any related structs */voidrrfreelist(RR *rp){	RR *next;	for(; rp; rp = next){		next = rp->next;		rrfree(rp);	}}extern RR**rrcopy(RR *rp, RR **last){	RR *nrp;	SOA *soa;	Key *key;	Cert *cert;	Sig *sig;	Null *null;	Txt *t, *nt, **l;	nrp = rralloc(rp->type);	switch(rp->type){	case Ttxt:		*nrp = *rp;		l = &nrp->txt;		*l = nil;		for(t = rp->txt; t != nil; t = t->next){			nt = emalloc(sizeof(*nt));			nt->p = estrdup(t->p);			nt->next = nil;			*l = nt;			l = &nt->next;		}		break;	case Tsoa:		soa = nrp->soa;		*nrp = *rp;		nrp->soa = soa;		*nrp->soa = *rp->soa;		nrp->soa->slaves = copyserverlist(rp->soa->slaves);		break;	case Tkey:		key = nrp->key;		*nrp = *rp;		nrp->key = key;		*key = *rp->key;		key->data = emalloc(key->dlen);		memmove(key->data, rp->key->data, rp->key->dlen);		break;	case Tsig:		sig = nrp->sig;		*nrp = *rp;		nrp->sig = sig;		*sig = *rp->sig;		sig->data = emalloc(sig->dlen);		memmove(sig->data, rp->sig->data, rp->sig->dlen);		break;	case Tcert:		cert = nrp->cert;		*nrp = *rp;		nrp->cert = cert;		*cert = *rp->cert;		cert->data = emalloc(cert->dlen);		memmove(cert->data, rp->cert->data, rp->cert->dlen);		break;	case Tnull:		null = nrp->null;		*nrp = *rp;		nrp->null = null;		*null = *rp->null;		null->data = emalloc(null->dlen);		memmove(null->data, rp->null->data, rp->null->dlen);		break;	default:		*nrp = *rp;		break;	}	nrp->cached = 0;	nrp->next = 0;	*last = nrp;	return &nrp->next;}/* *  lookup a resource record of a particular type and *  class attached to a domain name.  Return copies. * *  Priority ordering is: *	db authoritative *	not timed out network authoritative *	not timed out network unauthoritative *	unauthoritative db * *  if flag NOneg is set, don't return negative cached entries. *  return nothing instead.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -