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

📄 ns_validate.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
/************************************************************************** * ns_validate.c (was security.c in original ISI contribution) * author: anant kumar * contributed: March 17, 1993 * * implements validation procedure for RR's received from a server as a * response to a query. */#include <sys/param.h>#include <sys/socket.h>#include <sys/file.h>#include <netinet/in.h>#include <arpa/nameser.h>#include <syslog.h>#include <errno.h>#include <stdio.h>#include <resolv.h>#include "named.h"#ifdef VALIDATEstatic int		isvalid __P((struct namebuf *, int, int, char *, int)),			check_addr_ns __P((struct databuf **,					   struct sockaddr_in *,					   char *)),			check_in_tables __P((struct databuf **,					     struct sockaddr_in *,					     char *));static void		stick_in_queue __P((char *, int, int, char *));static NAMEADDR		nameaddrlist[MAXNAMECACHE];static int		firstNA = 0,			lastNA = 0;static TO_Validate	*validateQ, *currentVQ;static int		VQcount;/***************************************************************** * validate() is called from dovalidate(). it takes as parameters,  * the domain name sought, the class, type etc. of record, the server * that gave us the answer and the data it gave us * * it returns VALID if it is able to validate the record, INVALID if it cannot. * furtehr VALID is split into VALID_CACHE if we need to cache this record * since the domainname is not something we are authoritative for and * VALID_NO_CACHE if the name is something we are authoritative for. * * pseudocode for function validate is as follows: * validate(domain, server, type, class, data, dlen, rcode) { * *       if(dname or a higher level name not found in cache) *          return INVALID; *       if (NS records for "domain" found in cache){ * *           if(we are authoritative)  /findns() returned NXDOMAIN;/ *              if(we did not have an exact match on names) *                 =>the name does not exist in our database *                 => data is bad: return INVALID *              if(data agrees with what we have) *                return VALID_NO_CACHE; *              else return INVALID; *     *          if(we are not authoritative) /findns() returned OK;/        *          if (address records for NS's found in cache){ *                       if("server" = one of the addresses){ *                               return VALID_CACHE; *                       }else{ *                          stick in queue of "to_validate" data; *                          return (INVALID); *                       } *          else return INVALID; * * This performs the validation procedure described above. Checks * for the longest component of the dname that has a NS record * associated with it. At any stage, if no data is found, it implies * that the name is bad (has an unknown domain identifier) thus, we * return INVALID. * If address of one of these servers matches the address of the server * that returned us this data, we are happy! * * since findns will set needs_prime_cache if np = NULL is passed, we always * reset it. will let ns_req do it when we are searching for ns records to * query someone. hence in all the three cases of switch(findns()) *                                 we have needs_prime_cache = 0; *****************************************************************************/intvalidate(dname, server, type, class, data, dlen#ifdef NCACHE	 ,rcode#endif	 )	char *dname;	struct sockaddr_in *server;	int type;	int class;	char *data;	int dlen;#ifdef NCACHE	int rcode;#endif{	struct namebuf *np, *dnamep;	struct hashbuf *htp;	struct databuf *nsp[NSMAX];	int count;	char *fname;	int exactmatch = 0;	struct fwdinfo *fwd;#ifdef	DATUMREFCNT	nsp[0] = NULL;#endif	dprintf(3, (ddt,		    "validate(), d:%s, s:[%s], t:%d, c:%d\n",		    dname, inet_ntoa(server->sin_addr), type, class));	/* everything from forwarders is the GOSPEL */	for (fwd = fwdtab; fwd != NULL; fwd = fwd->next) {		if (server->sin_addr.s_addr == fwd->fwdaddr.sin_addr.s_addr)			return(VALID_CACHE);	}	htp = hashtab;	if (priming && (dname[0] == '\0'))		np = NULL;	else		np = nlookup(dname, &htp, &fname, 0);    	/* we were able to locate namebufs for this domain, or a parent domain,	 * or ??? */	if (np == NULL) {		fname = malloc(1);		fname[0] = '\0';	}	dprintf(5, (ddt,		    "validate:namebuf found np:0x%x, d:\"%s\", f:\"%s\"\n",		    np, dname, fname));	/* save the namebuf if we were able to locate the exact dname */	if (!strcasecmp(dname, fname)) {		dnamep = np;		exactmatch = 1;	}	if (np == NULL && fname != NULL) {		free((char *)fname);	}	switch (findns(&np, class, nsp, &count, 0)) {	case NXDOMAIN:		/** we are authoritative for this domain, lookup name 		 * in our zone data, if it matches, return valid.		 * in either case, do not cache		 **/		dprintf(5, (ddt, "validate: auth data found\n"));#ifdef	DATUMREFCNT		free_nsp(nsp);#endif		if (needs_prime_cache)			needs_prime_cache = 0;#ifdef NCACHE		if(rcode == NXDOMAIN) {			/* If we had an exactmatch on the name, we found the			 * name in our authority database, so this couldn't 			 * have been a bad name. INVALID data, say so			 */			if (exactmatch)				return INVALID;			else				/* we did not have an exactmatch, the data is				 * good, we do not NCACHE stuff we are				 * authoritative for, though.				 */				return VALID_NO_CACHE;		}#endif		if (!strcasecmp(dname, np->n_dname)) {      			/* if the name we seek is the same as that we have ns			 * records for, compare the data we have to see if it			 * matches. if it does, return valid_no_cache, if it			 * doesn't, invalid.			 */			if (isvalid(np, type, class, data, dlen))				return VALID_NO_CACHE;			else				return INVALID;		}    		/* we found ns records in a higher level, if we were unable to		 * locate the exact name earlier, it means we are		 * authoritative for this domain but do not have records for		 * this name. this name is obviously invalid		 */		if (!exactmatch)			return INVALID;    		/* we found the exact name earlier and we are obviously		 * authoritative so check for data records and see if any		 * match.		 */		if (isvalid(dnamep, type, class, data, dlen))			return VALID_NO_CACHE;		else			return INVALID;  	case SERVFAIL:/* could not find name server records*/		/* stick_in_queue(dname, type, class, data); */		if (needs_prime_cache)			needs_prime_cache = 0;#ifdef	DATUMREFCNT		free_nsp(nsp);#endif		return INVALID;    	case OK: /*proceed */		dprintf(5,			(ddt,			 "validate:found ns records:calling check_addr_ns\n"));		if (needs_prime_cache)			needs_prime_cache = 0;		if (check_addr_ns(nsp, server, dname)) {#ifdef	DATUMREFCNT			free_nsp(nsp);#endif			return VALID_CACHE;		}		/* server is not one of those we know of */		/* stick_in_queue(dname, type, class, data); */#ifdef	DATUMREFCNT		free_nsp(nsp);#endif		return INVALID;	default:#ifdef	DATUMREFCNT		free_nsp(nsp);#endif		return INVALID;	} /*switch*/} /*validate*//*********************************************************************** * validate rr returned by somebody against your own database, if you are  * authoritative for the information. if you have a record that matches, * return 1, else return 0. validate() above will use this and determine * if the record should be returned/discarded. ***********************************************************************/static intisvalid(np, type, class, data, dlen)	struct namebuf *np;	int type, class;	char *data;	int dlen;{	register struct databuf *dp;  	for (dp = np->n_data; dp != NULL; dp = dp->d_next) {		if (!wanted(dp, class, type)) {			if ((type == T_CNAME) && (class == dp->d_class)) { 				/* if a cname exists, any other will not */				return(0);				/* we come here only for zone info,				 * so -ve $ed info can't be				 */			}			continue;		}		/* type and class match, if i get here 		 * let's now compare the data section, per RR type		 */  		/* unless, of course, the data was negative, in which case		 * we should return FAILURE since we should not have found		 * data here.		 */		if ((data == NULL) || (dlen == 0)) {			return 0;		} 			        switch (type) {			char *td;			u_char *tdp;			int x;			case T_A:			case T_WKS:			case T_HINFO:			case T_UINFO:			case T_UID:			case T_GID:			case T_TXT:#ifdef ALLOW_T_UNSPEC			case T_UNSPEC:#endif			       x = memcmp(dp->d_data, data, dlen);			       dprintf(3, (ddt, "type = %d, GOOD = %d\n",					   type, x));			       if (x == 0)				       return (1);			       else				       break;			case T_CNAME:			case T_MB:			case T_MG:			case T_MR:			case T_NS:			case T_PTR:			       x = strncasecmp((char *)dp->d_data, data, dlen);			       dprintf(3, (ddt, "type = %d, GOOD = %d\n",					   type, x));			       if (x == 0)				       return (1);			       else				      break; 			case T_MINFO:			case T_SOA:			case T_RP:				/* compare first string */				x = strncasecmp((char *)dp->d_data, data,						strlen(data) + 1);				if (x != 0) 					break;				/* move to second string */				td = data + (strlen(data) + 1);				tdp = dp->d_data + 					(strlen((char *)dp->d_data)+1);				/* compare second string */				x = strncasecmp(td, (char *)tdp, 						strlen((char *)td+1));				if (x != 0)					break;				/* move beyond second string, to				 * set of words in SOA.				 * RP and MINFO stuff really				 * ends here				 */				td = td + strlen((char *)td) + 1;				tdp = tdp + strlen((char *)tdp) + 1;				if (type == T_SOA) {					x = memcmp(td, (char *)tdp,						   5*sizeof(u_int32_t));					if (x != 0)						break;				}								/* everything was equal, wow!				 * so return a success				 */			        return (1);			case T_MX:			case T_AFSDB:				x = memcmp(dp->d_data, data,					   sizeof(u_int16_t));				if (x != 0)					break;				td = data + sizeof(u_int16_t);				tdp = dp->d_data + sizeof(u_int16_t);				x = strncasecmp(td, (char *)tdp, 						strlen((char *)td) + 1);				if (x != 0)					break;				return (1);			default:				dprintf(3, (ddt, "unknown type %d\n", type));				return (0);		}		/* continue in loop if record did not match */	}	/* saw no record of interest in whole chain	 * If the data we were trying to validate was negative, we succeeded!	 * else we failed	 */	if ((data == NULL) || (dlen == 0)) {		/* negative data, report success */		return 1; 	} 	/* positive data, no such RR, validation failed */	return (0);}/******************************************************************  * get a list of databufs that have ns addresses for the closest domain  * you know about, get their addresses and confirm that server indeed  * is one of them. if yes return 1 else 0.   * first checks the cache that we build in nslookup() earlier   * when we ns_forw(). if unableto find it there, it checks the entire  * hash table to do address translations.  *******************************************************************/static intcheck_addr_ns(nsp, server, dname)	struct databuf **nsp;	struct sockaddr_in *server;	char *dname;{	int i, found=0;	char sname[MAXDNAME];	struct in_addr *saddr = &(server->sin_addr);	struct databuf **nsdp;	dprintf(5, (ddt,		    "check_addr_ns: s:[%s], db:0x%x, d:\"%s\"\n", 		    inet_ntoa(*saddr), nsp, dname));	for(i = lastNA; i != firstNA; i = (i+1) % MAXNAMECACHE) {		if (!bcmp((char *)saddr,			  (char *)&(nameaddrlist[i].ns_addr),			  sizeof(struct in_addr))) {			strcpy(sname, nameaddrlist[i].nsname);			found = 1;			break;		}	}	if (found) {		dprintf(3, (ddt,			    "check_addr_ns: found address:[%s]\n",			    inet_ntoa(*saddr)));		for (nsdp = nsp; *nsdp != NULL;nsdp++) {			dprintf(5, (ddt,				    "check_addr_ns:names are:%s, %s\n",				    sname,(*nsdp)->d_data));			if (!strcasecmp(sname,(char *)((*nsdp)->d_data))) {				return (1);			}		}		/* syslog(LOG_ERR,"check_addr_ns: %s != %s? %s",			inet_ntoa(*saddr),  sname, *dname?dname:"'.'"); */	return (0);	}	/* could not find name in my cache of servers, must go through the	 * whole grind	 */	dprintf(2, (ddt, "check_addr_ns:calling check_in_tables()\n"));	return (check_in_tables(nsp, server, dname));}/************************************************************************* * checks in hash tables for the address of servers whose name is in the  * data section of nsp records. borrows code from nslookup()/ns_forw.c * largely. *************************************************************************/static intcheck_in_tables(nsp, server, syslogdname)	struct databuf *nsp[];	struct sockaddr_in *server;	char *syslogdname;{	register struct namebuf *np;	register struct databuf *dp, *nsdp;	struct hashbuf *tmphtp;	char *dname, *fname;	int class;	int qcomp();  	dprintf(3, (ddt, "check_in_tables(nsp=x%x,qp=x%x,'%s')\n",		    nsp, server, syslogdname));  	while ((nsdp = *nsp++) != NULL) {		class = nsdp->d_class;		dname = (char *)nsdp->d_data;		dprintf(3, (ddt, "check_in_tables: NS %s c%d t%d (x%x)\n",			    dname, class, nsdp->d_type, nsdp->d_flags));		tmphtp = ((nsdp->d_flags & DB_F_HINT) ? fcachetab : hashtab);		np = nlookup(dname, &tmphtp, &fname, 1);		if (np == NULL || fname != dname) {			dprintf(3, (ddt, "%s: not found %s %x\n",				    dname, fname, np));			continue;		}		/* look for name server addresses */		for (dp = np->n_data;  dp != NULL;  dp = dp->d_next) {			if (stale(dp))				continue;			if (dp->d_type != T_A || dp->d_class != class)				continue;#ifdef NCACHE			if (dp->d_rcode)				continue;#endif			if (!bcmp((char *)dp->d_data,				  (char *)&(server->sin_addr),				  sizeof(struct in_addr))) {				return (1);			}		}	}	return (0); /* haven't been able to locate the right address */}/************************************************************************ * is called in nslookup() and stores the name vs address of a name server *           --& check_in_tables above-- * we contact, in a list of a maximum MAXNAMECACHE entries. we later refer *             -- NAMEADDR nameaddrlist[MAXNAMECACHE]; -- * to this list when we are trying to resolve the name in check_addr_ns(). *************************************************************************/voidstore_name_addr(servername, serveraddr, syslogdname, sysloginfo)	char *servername;	struct in_addr *serveraddr;	char *syslogdname;	char *sysloginfo;{	int i;	dprintf(3, (ddt,		    "store_name_addr:s:%s, a:[%s]\n",		    servername, inet_ntoa(*serveraddr)));	/* if we already have the name address pair in cache, return */	for(i = lastNA;  i != firstNA;  i = (i+1) % MAXNAMECACHE) {		if (strcasecmp(servername, nameaddrlist[i].nsname) == 0) {			if (serveraddr->s_addr			    ==			    nameaddrlist[i].ns_addr.s_addr) {				dprintf(5, (ddt,			  "store_name_addr:found n and a [%s] [%s] in our $\n",					    inet_ntoa(nameaddrlist[i].ns_addr),					    inet_ntoa(*serveraddr)));				return;			} /* if */		} else if (serveraddr->s_addr			   ==			   nameaddrlist[i].ns_addr.s_addr) {			/*			 * log this as it needs to be fixed.			 * replace old name by new, next query likely to have			 * NS record matching new			 */			if (!haveComplained(				(char*)dhash((u_char*)nameaddrlist[i].nsname,					     strlen(nameaddrlist[i].nsname)					     ),				(char*)dhash((u_char*)servername,					     strlen(servername)					     )					    )			    ) {				syslog(LOG_INFO,	       "%s: server name mismatch for [%s]: (%s != %s) (server for %s)",				       sysloginfo,				       inet_ntoa(*serveraddr),				       nameaddrlist[i].nsname, servername,				       syslogdname);			}			free(nameaddrlist[i].nsname);			nameaddrlist[i].nsname =				 malloc((unsigned)strlen(servername)+1);			strcpy(nameaddrlist[i].nsname, servername);			return;		} 	}	/* we have to add this one to our cache */	nameaddrlist[firstNA].nsname = malloc((unsigned)strlen(servername)+1);	strcpy(nameaddrlist[firstNA].nsname, servername);	bcopy((char *)serveraddr,	      (char *)&(nameaddrlist[firstNA].ns_addr),	      sizeof(struct in_addr));	dprintf(2, (ddt, "store_name_addr:added entry #:%d n:%s a:[%s]\n",		    firstNA, nameaddrlist[firstNA].nsname,		    inet_ntoa(nameaddrlist[firstNA].ns_addr)));	firstNA = (firstNA+1) % MAXNAMECACHE;	if (firstNA == lastNA) {

⌨️ 快捷键说明

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