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

📄 domain.c

📁 uCLinux下的一个TCP/IP协议栈源码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 *	DOMAIN.C -- domain name system stub resolver
 */

#include <stdio.h>
#include <ctype.h>
#include <time.h>
#include <sys/stat.h>
#include "global.h"
#include "mbuf.h"
#include "proc.h"
#include "ip.h"
#include "netuser.h"
#include "session.h"
#include "socket.h"
#include "cmdparse.h"
#include "commands.h"
#include "files.h"
#include "main.h"
#include "domain.h"

#undef	DEBUG				/* for certain trace messages */
#undef	DEBUG_PAIN			/* for painful debugging */

static struct rr *Dcache = NULL;	/* Cache of resource records */
static int Dcache_size = 20;		/* size limit */
static time_t Dcache_time = 0L; 	/* timestamp */

static int Dfile_clean = FALSE; 	/* discard expired records (flag) */
static int Dfile_reading = 0;		/* read interlock (count) */
static int Dfile_writing = 0;		/* write interlock (count) */

struct proc *Dfile_updater = NULL;
static int32 Dfile_wait_absolute = 0L;	/* timeout Clock time */
static int Dfile_wait_relative = 300;	/* timeout file activity (seconds) */

static struct dserver *Dservers = NULL; /* List of potential servers */
static int Dserver_retries = 2;		/* Attempts to reach servers */

static char *Dsuffix = NULL;	/* Default suffix for names without periods */
static int Dtrace = FALSE;
static char *Dtypes[] = {
	"",
	"A",
	"NS",
	"MD",
	"MF",
	"CNAME",
	"SOA",
	"MB",
	"MG",
	"MR",
	"NULL",
	"WKS",
	"PTR",
	"HINFO",
	"MINFO",
	"MX",
	"TXT"
};
static int Ndtypes = 17;
static char delim[] = " \t\r\n";

static int docache(int argc,char *argv[],void *p);
static int dosuffix(int argc,char *argv[],void *p);

static int docacheclean(int argc,char *argv[],void *p);
static int docachelist(int argc,char *argv[],void *p);
static int docachesize(int argc,char *argv[],void *p);
static int docachewait(int argc,char *argv[],void *p);

static void dlist_add(struct dserver *dp);
static void dlist_drop(struct dserver *dp);
static int dodnsadd(int argc,char *argv[],void *p);
static int dodnsdrop(int argc,char *argv[],void *p);
static int dodnslist(int argc,char *argv[],void *p);
static int dodnsquery(int argc,char *argv[],void *p);
static int dodnsretry(int argc,char *argv[],void *p);
static int dodnstrace(int argc,char *argv[],void *p);

static char * dtype(int value);
static int check_ttl(struct rr *rrlp);
static int compare_rr(struct rr *search_rrp,struct rr *target_rrp);
static int compare_rr_list(struct rr *rrlp,struct rr *target_rrp);
static struct rr *copy_rr(struct rr *rrp);
static struct rr *copy_rr_list(struct rr *rrlp);
static struct rr *make_rr(int source,
	char *dname,uint16 class,uint16 type,int32 ttl,uint16 rdl,void *data);

static void dcache_add(struct rr *rrlp);
static void dcache_drop(struct rr *rrp);
static struct rr *dcache_search(struct rr *rrlp);
static void dcache_update(struct rr *rrlp);

static struct rr *get_rr(FILE *fp, struct rr *lastrrp);
static void put_rr(FILE *fp,struct rr *rrp);
static struct rr *dfile_search(struct rr *rrlp);
static void dfile_update(int s,void *unused,void *p);

static void dumpdomain(struct dhdr *dhp,int32 rtt);
static int dns_makequery(uint16 op,struct rr *rrp,
	uint8 *buffer,uint16 buflen);
static int dns_query(struct rr *rrlp);

static int isaddr(char *s);
static char *checksuffix(char *dname);
static struct rr *resolver(struct rr *rrlp);


/**
 **	Domain Resolver Commands
 **/

static struct cmds Dcmds[] = {
	"addserver",	dodnsadd,	0, 2, "add <hostid>",
	"dropserver",	dodnsdrop,	0, 2, "drop <hostid>",
	"list",		dodnslist,	0, 0, NULL,
	"query",	dodnsquery,   512, 2, "query <hostid>",
	"retry",	dodnsretry,	0, 0, NULL,
	"suffix",	dosuffix,	0, 0, NULL,
	"trace",	dodnstrace,	0, 0, NULL,
	"cache",	docache,	0, 0, NULL,
	NULL,
};

static struct cmds Dcachecmds[] = {
	"clean",	docacheclean,	0, 0, NULL,
	"list",		docachelist,  512, 0, NULL,
	"size",		docachesize,	0, 0, NULL,
	"wait",		docachewait,	0, 0, NULL,
	NULL,
};

int
dodomain(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return subcmd(Dcmds,argc,argv,p);
}

static int
docache(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return subcmd(Dcachecmds,argc,argv,p);
}

static int
dosuffix(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	if(argc < 2){
		if(Dsuffix != NULL)
			printf("%s\n",Dsuffix);
		return 0;
	}
	free(Dsuffix);
	Dsuffix = strdup(argv[1]);
	return 0;
}

static int
docacheclean(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setbool( &Dfile_clean, "discard expired records", argc,argv );
}

static int
docachelist(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	struct rr *rrp;
	struct session *sp;
	int row = 25;

	if((sp = newsession(Cmdline,DCLIST,1)) == NULL){
		return -1;
	}

	(void)dcache_search(NULL); /* update ttl */

	/* Put tty into raw mode so single-char responses will work */
	sp->ttystate.echo = sp->ttystate.edit = 0;

	for(rrp=Dcache;rrp!=NULL;rrp=rrp->next)
	{
		put_rr(stdout,rrp);
		if(--row == 0){
			row = keywait("--More--",0);
			switch(row){
			case -1:
			case 'q':
			case 'Q':
				rrp = NULL;
				break;
			case '\n':
			case '\r':
				row = 1;
				break;
			case ' ':
			default:
				row = 25;
			};
		}
	}
	fflush(stdout);
	keywait(NULL,1);
	freesession(sp);
	return 0;
}

static int
docachesize(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	int newsize;
	int oldsize;
	int result;

	newsize = oldsize = Dcache_size;
	result = setint( &newsize, "memory cache size", argc,argv );

	if(newsize > 0){
		Dcache_size = newsize;
		if(newsize < oldsize){
			(void)dcache_search(NULL); /* update size */
		}
	}
	return result;
}

static int
docachewait(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setint( &Dfile_wait_relative, "time before file update (seconds)", argc,argv );
}

static void
dlist_add(dp)
register struct dserver *dp;
{
	dp->prev = NULL;
	dp->next = Dservers;
	if(Dservers != NULL)
		Dservers->prev = dp;
	Dservers = dp;
}

static void
dlist_drop(dp)
register struct dserver *dp;
{
	if(dp->prev != NULL)
		dp->prev->next = dp->next;
	else
		Dservers = dp->next;
	if(dp->next != NULL)
		dp->next->prev = dp->prev;
}

static int
dodnsadd(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	int32 address;

	if((address = resolve(argv[1])) == 0L){
		printf("Resolver %s unknown\n",argv[1]);
		return 1;
	}
	return add_nameserver(address);
}
int
add_nameserver(address)
int32 address;
{
	struct dserver *dp;

	dp = (struct dserver *)callocw(1,sizeof(struct dserver));
	dp->address = address;
	dp->srtt = INITRTT;
	dp->mdev = 0;
	dp->timeout = 2 * dp->mdev + dp->srtt + 3;
	dlist_add(dp);
	return 0;
}

static int
dodnsdrop(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	struct dserver *dp;
	int32 addr;

	addr = resolve(argv[1]);
	for(dp = Dservers;dp != NULL;dp = dp->next)
		if(addr == dp->address)
			break;

	if(dp == NULL){
		printf("Not found\n");
		return 1;
	}

	dlist_drop(dp);
	free(dp);
	return 0;
}

static int
dodnslist(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	register struct dserver *dp;

	printf("Server address          srtt    mdev   timeout   queries responses\n");
	for(dp = Dservers;dp != NULL;dp = dp->next){
		printf("%-20s%8lu%8lu%10lu%10lu%10lu\n",
		 inet_ntoa(dp->address),
		 dp->srtt,dp->mdev,dp->timeout,
		 dp->queries,dp->responses);
	}
	return 0;
}

static int
dodnsquery(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	struct rr *rrp;
	struct rr *result_rrlp;
	char *sname;
	struct session *sp;
	int row = 25;

	if((sp = newsession(Cmdline,DQUERY,1)) == NULL){
		return -1;
	}

	if ( isaddr( argv[1] ) ) {
		result_rrlp = inverse_a( aton( argv[1] ) );
	} else {
		sname = checksuffix( argv[1] );
		rrp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_ANY,0,0,NULL);
		FREE(sname);

		dns_query(rrp);
		result_rrlp = dcache_search(rrp);
		free_rr(rrp);
	}

	/* Put tty into raw mode so single-char responses will work */
	sp->ttystate.echo = sp->ttystate.edit = 0;

	for( rrp=result_rrlp; rrp!=NULL; rrp=rrp->next)
	{
		put_rr(stdout,rrp);
		if(--row == 0){
			row = keywait("--More--",0);
			switch(row){
			case -1:
			case 'q':
			case 'Q':
				rrp = NULL;
				break;
			case '\n':
			case '\r':
				row = 1;
				break;
			case ' ':
			default:
				row = 25;
			};
		}
	}
	fflush(stdout);
	free_rr(result_rrlp);
	keywait(NULL,1);
	freesession(sp);
	return 0;
}

static int
dodnsretry(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setint( &Dserver_retries, "server retries", argc,argv );
}

static int
dodnstrace(argc,argv,p)
int argc;
char *argv[];
void *p;
{
	return setbool(&Dtrace,"server trace",argc,argv);
}


/**
 **	Domain Resource Record Utilities
 **/

static char *
dtype(value)
int value;
{
	static char buf[10];

	if (value < Ndtypes)
		return Dtypes[value];

	sprintf( buf, "{%d}", value);
	return buf;
}

/* check list of resource records for any expired ones.
 * returns number of expired records.
 */
static int
check_ttl(rrlp)
register struct rr *rrlp;
{
	int count = 0;

	while(rrlp != NULL){
		if(rrlp->ttl == 0L)
			count++;
		rrlp = rrlp->next;
	}
	return count;
}

/* Compare two resource records.
 * returns 0 if match, nonzero otherwise.
 */
static int
compare_rr(search_rrp,target_rrp)
register struct rr *search_rrp,*target_rrp;
{
	int i;

	if(search_rrp == NULL || target_rrp == NULL)
		return -32765;

	if(search_rrp->class != target_rrp->class)
		return -32763;

	if(search_rrp->type != TYPE_ANY
	&& search_rrp->type != target_rrp->type
	&& (search_rrp->source != RR_QUERY
	 || (target_rrp->type != TYPE_CNAME
	  && target_rrp->type != TYPE_PTR)))
		return -32761;

	if(search_rrp->source != RR_INQUERY){
		if((i = strlen(search_rrp->name)) != strlen(target_rrp->name))
			return -32759;
		if((i = strnicmp(search_rrp->name,target_rrp->name,i)) != 0)
			return i;

		/* match negative records so that they are replaced */
		if(target_rrp->rdlength == 0)
			return 0;
	}

	/* if a query has gotten this far, match it */
	if(search_rrp->source == RR_QUERY)
		return 0;

	/* ensure negative records don't replace older records */
	if(search_rrp->rdlength == 0)
		return -32757;

	/* match expired records so that they are replaced */
	if(search_rrp->source != RR_INQUERY){
		if(target_rrp->ttl == 0L)
			return 0;
	}

	/* Note: rdlengths are not compared because they vary depending
	 * on the representation (ASCII or encoded) this record was
	 * generated from.
	 */

	switch(search_rrp->type){
	case TYPE_A:
		i = search_rrp->rdata.addr != target_rrp->rdata.addr;
		break;
	case TYPE_CNAME:
	case TYPE_MB:
	case TYPE_MG:
	case TYPE_MR:
	case TYPE_NS:
	case TYPE_PTR:
	case TYPE_TXT:
		i = stricmp(search_rrp->rdata.data,target_rrp->rdata.data);
		break;
	case TYPE_HINFO:
		i = strcmp(search_rrp->rdata.hinfo.cpu,target_rrp->rdata.hinfo.cpu) ||
			strcmp(search_rrp->rdata.hinfo.os,target_rrp->rdata.hinfo.os);
		break;
	case TYPE_MX:
		i = stricmp(search_rrp->rdata.mx.exch,target_rrp->rdata.mx.exch);
		break;
	case TYPE_SOA:
		i = search_rrp->rdata.soa.serial != target_rrp->rdata.soa.serial;
		break;
	default:
		i = -32755;	/* unsupported */
	}
	return i;
}

static int
compare_rr_list(rrlp,target_rrp)
register struct rr *rrlp,*target_rrp;
{
	while(rrlp != NULL){
		if(compare_rr(rrlp,target_rrp) == 0)
			return 0;
#ifdef DEBUG_PAIN
		if(Dtrace)
			printf("%15d %s\n",
				compare_rr(rrlp,target_rrp),
				target_rrp->name);
#endif
		rrlp = rrlp->next;
	}
	return -32767;
}

/* Make a new copy of a resource record */
static struct rr *
copy_rr(rrp)
register struct rr *rrp;
{
	register struct rr *newrr;

	if(rrp == NULL)
		return NULL;

	newrr = (struct rr *)callocw(1,sizeof(struct rr));
	newrr->source =	rrp->source;
	newrr->name =	strdup(rrp->name);
	newrr->type =	rrp->type;
	newrr->class =	rrp->class;
	newrr->ttl =	rrp->ttl;
	if((newrr->rdlength = rrp->rdlength) == 0)
		return newrr;

	switch(rrp->type){
	case TYPE_A:
		newrr->rdata.addr = rrp->rdata.addr;
		break;
	case TYPE_CNAME:
	case TYPE_MB:
	case TYPE_MG:
	case TYPE_MR:
	case TYPE_NS:
	case TYPE_PTR:
	case TYPE_TXT:
		newrr->rdata.name = strdup(rrp->rdata.name);
		break;
	case TYPE_HINFO:
		newrr->rdata.hinfo.cpu = strdup(rrp->rdata.hinfo.cpu);
		newrr->rdata.hinfo.os = strdup(rrp->rdata.hinfo.os);
		break;
	case TYPE_MX:
		newrr->rdata.mx.pref = rrp->rdata.mx.pref;
		newrr->rdata.mx.exch = strdup(rrp->rdata.mx.exch);
		break;
	case TYPE_SOA:
		newrr->rdata.soa.mname = 	strdup(rrp->rdata.soa.mname);
		newrr->rdata.soa.rname = 	strdup(rrp->rdata.soa.rname);
		newrr->rdata.soa.serial = 	rrp->rdata.soa.serial;
		newrr->rdata.soa.refresh = 	rrp->rdata.soa.refresh;
		newrr->rdata.soa.retry = 	rrp->rdata.soa.retry;
		newrr->rdata.soa.expire = 	rrp->rdata.soa.expire;
		newrr->rdata.soa.minimum = 	rrp->rdata.soa.minimum;
		break;
	}
	return newrr;
}

static struct rr *
copy_rr_list(rrlp)

⌨️ 快捷键说明

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