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

📄 domain.c

📁 uCLinux下的一个TCP/IP协议栈源码
💻 C
📖 第 1 页 / 共 3 页
字号:
					put_rr(new_fp,frrp);
				rrpp = &(*rrpp)->next;
				frrp->source = RR_FILE;
				break;
			}
		}
		*rrpp = NULL;

		/* open up the old file, concurrently with everyone else */
		if((old_fp = fopen(Dfile,READ_TEXT)) == NULL){
			/* great! no old file, so we're ready to go. */
			fclose(new_fp);
			rename(newname,Dfile);
			free_rr(rrlp);
			break;
		}
		if(fstat(fileno(old_fp),&old_stat) != 0){
			printf("dfile_update: can't get old_file status!\n");
			fclose(new_fp);
			fclose(old_fp);
			free_rr(rrlp);
			break;
		}
		if((elapsed = (int32)(new_stat.st_ctime - old_stat.st_ctime)) < 0L)
			elapsed = -elapsed;	/* file times are inconsistant */

		/* Now append any non-duplicate records */
		oldrrp = NULL;
		while((frrp = get_rr(old_fp,oldrrp)) != NULL){
			free_rr(oldrrp);
			if(frrp->name == NULL
			&& frrp->comment != NULL)
				put_rr(new_fp,frrp);
			if(frrp->type != TYPE_MISSING
			&& frrp->rdlength > 0
			&& compare_rr_list(rrlp,frrp) != 0){
				if(frrp->ttl > 0L
				&& (frrp->ttl -= elapsed) <= 0L)
					frrp->ttl = 0L;
				if(frrp->ttl != 0 || !Dfile_clean)
					put_rr(new_fp,frrp);
			}
			oldrrp = frrp;
			if(!main_exit)
				kwait(NULL);	/* run in background */
		}
		free_rr(oldrrp);
		fclose(new_fp);
		fclose(old_fp);
		free_rr(rrlp);

		/* wait for everyone else to finish reading */
		Dfile_writing++;
		while(Dfile_reading > 0)
			kwait(&Dfile_writing);

		unlink(Dfile);
		rename(newname,Dfile);

		Dfile_writing = 0;
		ksignal(&Dfile_reading,0);
	}
	free(newname);

	logmsg(-1,"update Domain.txt finished");
	Dfile_updater = NULL;
}


/**
 **	Domain Server Utilities
 **/

static void
dumpdomain(dhp,rtt)
struct dhdr *dhp;
int32 rtt;
{
	struct rr *rrp;
	char * stuff;

	printf("response id %u (rtt %lu sec) qr %u opcode %u aa %u tc %u rd %u ra %u rcode %u\n",
	 dhp->id,(long)rtt / 1000L,
	 dhp->qr,dhp->opcode,dhp->aa,dhp->tc,dhp->rd,
	 dhp->ra,dhp->rcode);
	printf("%u questions:\n",dhp->qdcount);
	for(rrp = dhp->questions; rrp != NULL; rrp = rrp->next){
		stuff = dtype(rrp->type);
		printf("%s type %s class %u\n",rrp->name,
		 stuff,rrp->class);
	}
	printf("%u answers:\n",dhp->ancount);
	for(rrp = dhp->answers; rrp != NULL; rrp = rrp->next){
		put_rr(stdout,rrp);
	}
	printf("%u authority:\n",dhp->nscount);
	for(rrp = dhp->authority; rrp != NULL; rrp = rrp->next){
		put_rr(stdout,rrp);
	}
	printf("%u additional:\n",dhp->arcount);
	for(rrp = dhp->additional; rrp != NULL; rrp = rrp->next){
		put_rr(stdout,rrp);
	}
	fflush(stdout);
}

static int
dns_makequery(op,srrp,buffer,buflen)
uint16 op;	/* operation */
struct rr *srrp;/* Search RR */
uint8 *buffer;	/* Area for query */
uint16 buflen;	/* Length of same */
{
	uint8 *cp;
	char *cp1;
	char *dname, *sname;
	uint16 parameter;
	uint16 dlen,len;

	cp = buffer;
	/* Use millisecond clock for timestamping */
	cp = put16(cp,(uint16)msclock());
	parameter = (op << 11)
			| 0x0100;	/* Recursion desired */
	cp = put16(cp,parameter);
	cp = put16(cp,1);
	cp = put16(cp,0);
	cp = put16(cp,0);
	cp = put16(cp,0);

	sname = strdup(srrp->name);
	dname = sname;
	dlen = strlen(dname);
	for(;;){
		/* Look for next dot */
		cp1 = strchr(dname,'.');
		if(cp1 != NULL)
			len = cp1-dname;	/* More to come */
		else
			len = dlen;	/* Last component */
		*cp++ = len;		/* Write length of component */
		if(len == 0)
			break;
		/* Copy component up to (but not including) dot */
		strncpy((char *)cp,dname,len);
		cp += len;
		if(cp1 == NULL){
			*cp++ = 0;	/* Last one; write null and finish */
			break;
		}
		dname += len+1;
		dlen -= len+1;
	}
	free(sname);
	cp = put16(cp,srrp->type);
	cp = put16(cp,srrp->class);
	return cp - buffer;
}

/* domain server resolution loop
 * returns: any answers in cache.
 *	(future features)
 *	multiple queries.
 *	inverse queries.
 * return value: 0 if something added to cache, -1 if error
 */
static int
dns_query(rrlp)
struct rr *rrlp;
{
	struct mbuf *bp;
	struct dhdr *dhp;
	struct dserver *dp;	/* server list */
	int32 rtt,abserr;
	int tried = 0;		/* server list has been retried (count) */

	if((dp = Dservers) == NULL)
		return -1;

	for(;;){
		uint8 *buf;
		int len;
		struct sockaddr_in server_in;
		int s;
		int rval;

		dp->queries++;

		s = socket(AF_INET,SOCK_DGRAM,0);
		server_in.sin_family = AF_INET;
		server_in.sin_port = IPPORT_DOMAIN;
		server_in.sin_addr.s_addr = dp->address;

		if(Dtrace){
			printf("dns_query: querying server %s for %s\n",
			 inet_ntoa(dp->address),rrlp->name);
		}

		buf = mallocw(512);
		len = dns_makequery(0,rrlp,buf,512);
		if(sendto(s,buf,len,0,(struct sockaddr *)&server_in,sizeof(server_in)) == -1)
			perror("domain sendto");
		FREE(buf);
		kalarm(max(dp->timeout,100));
		/* Wait for something to happen */
		rval = recv_mbuf(s,&bp,0,NULL,0);
		kalarm(0L);
		close_s(s);

		if(Dtrace){
			if(errno == 0)
				printf("dns_query: received message length %d\n",rval);
			else
				perror("dns_query");
		}

		if(rval > 0)
			break;

		if(errno == EABORT)
			return -1;		/* Killed by "reset" command */

		/* Timeout; back off this one and try another server */
		dp->timeout <<= 1;
		if((dp = dp->next) == NULL){
			dp = Dservers;
			if(Dserver_retries > 0 && ++tried > Dserver_retries)
				return -1;
		}
	}

	/* got a response */
	dp->responses++;
	dhp = (struct dhdr *) mallocw(sizeof(struct dhdr));
	ntohdomain(dhp,&bp);	/* Convert to local format */

	/* Compute and update the round trip time */
	rtt = (int32) ((uint16)msclock() - dhp->id);
	abserr = rtt > dp->srtt ? rtt - dp->srtt : dp->srtt - rtt;
	dp->srtt = ((AGAIN-1) * dp->srtt + rtt + (AGAIN/2)) >> LAGAIN;
	dp->mdev = ((DGAIN-1) * dp->mdev + abserr + (DGAIN/2)) >> LDGAIN;
	dp->timeout = 4 * dp->mdev + dp->srtt;

	/* move to top of list for next time */
	if(dp->prev != NULL){
		dlist_drop(dp);
		dlist_add(dp);
	}

	if(Dtrace)
		dumpdomain(dhp,rtt);

	/* Add negative reply to answers.  This assumes that there was
	 * only one question, which is true for all questions we send.
	 */
	if(dhp->aa && (dhp->rcode == NAME_ERROR || dhp->ancount == 0)){
		register struct rr *rrp;
		long ttl = 600L; /* Default TTL for negative records */

		/* look for SOA ttl */
		for(rrp = dhp->authority; rrp != NULL; rrp = rrp->next){
			if(rrp->type == TYPE_SOA)
				ttl = rrp->ttl;
		}

		/* make the questions the negative answers */
		for(rrp = dhp->questions; rrp != NULL; rrp = rrp->next)
			rrp->ttl = ttl;
	} else {
		free_rr(dhp->questions);
		dhp->questions = NULL;
	}

	/* post in reverse order to maintain original order */
	dcache_update(dhp->additional);
	dcache_update(dhp->authority);
	dcache_update(dhp->answers);
	dcache_update(dhp->questions);

	Dfile_wait_absolute = secclock() + Dfile_wait_relative;
	if(Dfile_updater == NULL){
		Dfile_updater = newproc("domain update",
			512,dfile_update,0,NULL,NULL,0);
	}

#ifdef DEBUG
	if(Dtrace)
		keywait(NULL,1);	/* so we can look around */
#endif
	free(dhp);
	return 0;
}


/**
 **	Resolver Utilities
 **/

/* Return TRUE if string appears to be an IP address in dotted decimal;
 * return FALSE otherwise (i.e., if string is a domain name)
 */
static int
isaddr(s)
register char *s;
{
	char c;

	if(s == NULL)
		return TRUE;	/* Can't happen */

	while((c = *s++) != '\0'){
		if(c != '[' && c != ']' && !isdigit(c) && c != '.')
			return FALSE;
	}
	return TRUE;
}

/* Return "normalized" domain name, with default suffix and trailing '.'
 */
static char *
checksuffix(dname)
char *dname;
{
	char *sname, *tname;

	sname = strdup(dname);
	if(strchr(sname,'.') == NULL && Dsuffix != NULL){
		/* Append default suffix */
		tname = mallocw(strlen(sname)+strlen(Dsuffix)+2);
		sprintf(tname,"%s.%s",sname,Dsuffix);
		free(sname);
		sname = tname;
	}
	if(sname[strlen(sname)-1] != '.'){
		/* Append trailing dot */
		tname = mallocw(strlen(sname)+2);
		sprintf(tname,"%s.",sname);
		free(sname);
		sname = tname;
	}
	return sname;
}

/* Search for resource records.
 * Returns RR list, or NULL if no record found.
 */
static struct rr *
resolver(rrlp)
register struct rr *rrlp;
{
	register struct rr *result_rrlp;

	if((result_rrlp = dcache_search(rrlp)) == NULL){
		result_rrlp = dfile_search(rrlp);
	}
	if(result_rrlp == NULL || check_ttl(result_rrlp) != 0){
		dcache_add(result_rrlp); 	/* save any expired RRs */
		if(dns_query(rrlp) == -1)
			return NULL;
		result_rrlp = dcache_search(rrlp);
	}
	dcache_add(copy_rr_list(result_rrlp));
	return result_rrlp;
}

/* general entry point for address -> domain name resolution.
 * Returns RR list, or NULL if no record found.
 */
struct rr *
inverse_a(ip_address)
int32 ip_address;
{
	struct rr *prrp;
	struct rr *result_rrlp;
	char pname[30];

	if(ip_address == 0L)
		return NULL;

	sprintf( pname, "%u.%u.%u.%u.IN-ADDR.ARPA.",
			lobyte(loword(ip_address)),
			hibyte(loword(ip_address)),
			lobyte(hiword(ip_address)),
			hibyte(hiword(ip_address)) );

	prrp = make_rr(RR_QUERY,pname,CLASS_IN,TYPE_PTR,0,0,NULL);

	prrp->next = 		/* make list to speed search */
		make_rr(RR_INQUERY,NULL,CLASS_IN,TYPE_A,0,4,&ip_address);

	result_rrlp = resolver(prrp);

	free_rr(prrp);
	return result_rrlp;
}

/* general entry point for domain name -> resource resolution.
 * Returns RR list, or NULL if no record found.
 */
struct rr *
resolve_rr(dname,dtype)
char *dname;
uint16 dtype;
{
	struct rr *qrrp;
	struct rr *result_rrlp;
	char *sname;
	int looping = MAXCNAME;

	if(dname == NULL)
		return NULL;

	sname = checksuffix(dname);
	qrrp = make_rr(RR_QUERY,sname,CLASS_IN,dtype,0,0,NULL);
	FREE(sname);

	while(looping > 0){
		if((result_rrlp=resolver(qrrp)) == NULL
		|| result_rrlp->type == dtype)
			break;
#ifdef DEBUG
		if(Dtrace)
			put_rr(stdout,result_rrlp);
#endif
		/* Should be CNAME or PTR record */
		/* Replace name and try again */
		free(qrrp->name);
		qrrp->name = strdup(result_rrlp->rdata.name);
		free_rr(result_rrlp);
		result_rrlp = NULL;
		looping--;
	}
	free_rr(qrrp);
	return result_rrlp;
}

/* main entry point for address -> domain name resolution.
 * Returns string, or NULL if no name found.
 */
char *
resolve_a(ip_address,shorten)
int32 ip_address;		/* search address */
int shorten;			/* return only first part of name (flag)*/
{
	struct rr *save_rrlp, *rrlp;
	char *result = NULL;

	for( rrlp = save_rrlp = inverse_a(ip_address);
	     rrlp != NULL && result == NULL;
	     rrlp = rrlp->next ){
		if(rrlp->rdlength > 0){
			switch(rrlp->type){
			case TYPE_PTR:
				result = strdup(rrlp->rdata.name);
				break;
			case TYPE_A:
				result = strdup(rrlp->name);
				break;
			}
		}
	}
	free_rr(save_rrlp);

	if(result != NULL && shorten){
		int dot;
		char *shortened;

		if((dot = strcspn(result, ".")) == 0){
			shortened = mallocw(dot+1);
			strncpy(shortened, result, dot);
			shortened[dot] = '\0';
			free(result);
			result = shortened;
		}
	}
	return result;
}

/* Main entry point for domain name -> address resolution.
 * Returns 0 if name is currently unresolvable.
 */
int32
resolve(name)
char *name;
{
	register struct rr *rrlp;
	int32 ip_address = 0;

	if(name == NULL)
		return 0;

	if(isaddr(name))
		return aton(name);

	if((rrlp = resolve_rr(name,TYPE_A)) != NULL
	 && rrlp->rdlength > 0)
		ip_address = rrlp->rdata.addr;

	/* multi-homed hosts are handled here */
	if(rrlp != NULL && rrlp->next != NULL) {
		register struct rr *rrp;
		register struct route *rp;
		uint16 cost = MAXINT16;
		rrp = rrlp;
		/* choose the best of a set of routes */
		while(rrp != NULL) {
			if(rrp->rdlength > 0
			 && (rp = rt_lookup(rrp->rdata.addr)) != NULL
			 && rp->metric <= cost) {
				ip_address = rrp->rdata.addr;
				cost = rp->metric;
			}
			rrp = rrp->next;
		}
	}

	free_rr(rrlp);
	return ip_address;
}


/* Main entry point for MX record lookup.
 * Returns 0 if name is currently unresolvable.
 */
int32
resolve_mx(name)
char *name;
{
	register struct rr *rrp, *arrp;
	char *sname, *tmp, *cp;
	int32 addr, ip_address = 0;
	uint16 pref = MAXINT16;

	if(name == NULL)
		return 0;

	if(isaddr(name)){
		if((sname = resolve_a(aton(name),FALSE)) == NULL)
			return 0;
	}
	else
		sname = strdup(name);

	cp = sname;
	while(1){
		rrp = arrp = resolve_rr(sname,TYPE_MX);
		/* Search this list of rr's for an MX record */
		while(rrp != NULL){
			if(rrp->rdlength > 0 && rrp->rdata.mx.pref <= pref &&
			   (addr = resolve(rrp->rdata.mx.exch)) != 0L){
				pref = rrp->rdata.mx.pref;
				ip_address = addr;
			}
			rrp = rrp->next;
		}
		free_rr(arrp);
		if(ip_address != 0)
			break;
		/* Compose wild card one level up */
		if((cp = strchr(cp,'.')) == NULL)
			break;
		tmp = mallocw(strlen(cp)+2);
		sprintf(tmp,"*%s",cp);		/* wildcard expansion */
		free(sname);
		sname = tmp;
		cp = sname + 2;
	}
	free(sname);
	return ip_address;
}

/* Search for local records of the MB, MG and MR type. Returns list of
 * matching records.
 */
struct rr *
resolve_mailb(name)
char *name;		/* local username, without trailing dot */
{
	register struct rr *result_rrlp;
	struct rr *rrlp;
	char *sname;

	/* Append trailing dot */
	sname = mallocw(strlen(name)+2);
	sprintf(sname,"%s.",name);
	rrlp = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MB,0,0,NULL);
	rrlp->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MG,0,0,NULL);
	rrlp->next->next = make_rr(RR_QUERY,sname,CLASS_IN,TYPE_MR,0,0,NULL);
	FREE(sname);
	if((result_rrlp = dcache_search(rrlp)) == NULL){
		result_rrlp = dfile_search(rrlp);
	}
	free_rr(rrlp);
	if(Dsuffix != NULL){
		rrlp = result_rrlp;
		while(rrlp != NULL){	/* add domain suffix to data */
			if(rrlp->rdlength > 0 &&
			   rrlp->rdata.name[rrlp->rdlength-1] != '.'){
				sname = mallocw(rrlp->rdlength +
					strlen(Dsuffix)+2);
				sprintf(sname,"%s.%s",rrlp->rdata.name,Dsuffix);
				free(rrlp->rdata.name);
				rrlp->rdata.name = sname;
				rrlp->rdlength = strlen(sname);
			}
			rrlp = rrlp->next;
		}
	}
	dcache_add(copy_rr_list(result_rrlp));
	return result_rrlp;
}

⌨️ 快捷键说明

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