diff options
| -rw-r--r-- | rfc1035/rfc1035.h | 16 | ||||
| -rw-r--r-- | rfc1035/rfc1035reply.c | 9 | ||||
| -rw-r--r-- | rfc1035/rfc1035search.c | 144 | ||||
| -rw-r--r-- | rfc1035/testlookup.c | 115 | 
4 files changed, 266 insertions, 18 deletions
| diff --git a/rfc1035/rfc1035.h b/rfc1035/rfc1035.h index ee85101..9a92c1b 100644 --- a/rfc1035/rfc1035.h +++ b/rfc1035/rfc1035.h @@ -228,6 +228,22 @@ int rfc1035_resolve_cname(  #define RFC1035_X_RANDOMIZE 1    /* Randomize query results */ +/* +** rfc1035_resolve_cname_multiple is a version of rfc1035_resolve_cname +** that accepts an array of qtypes, and issues a query for each qtype. +** +** qtypes points to a 0-terminated list of RRs. +*/ +int rfc1035_resolve_cname_multiple(struct rfc1035_res *res, +				   char *namebuf, +				   /* RFC1035_MAXNAMESIZE buffer with +				   ** the name to query */ +				   unsigned char *qtypes, +				   unsigned qclass, +				   struct rfc1035_reply **ptr, +				   int x_flags); + +  	/*  	** Always call replyfree when done.  	*/ diff --git a/rfc1035/rfc1035reply.c b/rfc1035/rfc1035reply.c index ac1e87e..ab43dfb 100644 --- a/rfc1035/rfc1035reply.c +++ b/rfc1035/rfc1035reply.c @@ -489,7 +489,10 @@ void rfc1035_rr_rand_ar(struct rfc1035_reply *rr)  void rfc1035_rr_rand(struct rfc1035_reply *rr)  { -	rfc1035_rr_rand_an(rr); -	rfc1035_rr_rand_ns(rr); -	rfc1035_rr_rand_ar(rr); +	if (rr->ancount > 1) +		rfc1035_rr_rand_an(rr); +	if (rr->nscount > 1) +		rfc1035_rr_rand_ns(rr); +	if (rr->arcount > 1) +		rfc1035_rr_rand_ar(rr);  } diff --git a/rfc1035/rfc1035search.c b/rfc1035/rfc1035search.c index 019f521..526e7a0 100644 --- a/rfc1035/rfc1035search.c +++ b/rfc1035/rfc1035search.c @@ -141,7 +141,8 @@ int rfc1035_replysearch_all(const struct rfc1035_res *res,  	return (-1);  } -int rfc1035_resolve_cname(struct rfc1035_res *res, char *namebuf, +int rfc1035_resolve_cname(struct rfc1035_res *res, +			  char *namebuf,  			  unsigned qtype,  			  unsigned qclass,  			  struct rfc1035_reply **ptr, @@ -212,3 +213,144 @@ int	recursion_count=10;  		return (-1);  	}  } + +int rfc1035_resolve_cname_multiple(struct rfc1035_res *res, +				   char *namebuf, +				   unsigned char *qtypes, +				   unsigned qclass, +				   struct rfc1035_reply **ptr, +				   int x_flags) +{ +	int	n, query_again; +	int	retry_count=10; +	unsigned nqueries=strlen((char*)qtypes), u, good, cname; +	struct rfc1035_query qu[nqueries]; +	struct rfc1035_reply *p; + +	char	cmpname1[RFC1035_MAXNAMESIZE+1], +		cmpname2[RFC1035_MAXNAMESIZE+1]; + +	static const char forbidden[] = +		{ +		 RFC1035_TYPE_CNAME, +		 RFC1035_TYPE_AXFR, +		 RFC1035_TYPE_ANY, +		 0 +		}; + +	if (nqueries == 0) +		return -1; + +	for (u=0; u<nqueries; ++u) +	{ +		qu[u].name=namebuf; +		qu[u].qclass=qclass; +		qu[u].qtype=qtypes[u]; + +		if (strchr(forbidden, qtypes[u])) +		{ +			if (nqueries == 1) +			{ +				return rfc1035_resolve_cname(res, namebuf, +							     qtypes[0], +							     qclass, +							     ptr, +							     x_flags); +			} +			return -1; +		} +	} + +	*ptr=NULL; + +	do // query loop +	{ +		if (*ptr) +			rfc1035_replyfree( *ptr ); + +		if ( (*ptr=rfc1035_resolve_multiple(res, RFC1035_OPCODE_QUERY, +				qu, nqueries)) == 0) +			return (-1); + +		query_again=0; + +		for (;;) // change name loop +		{ +			int fatal = 0; + +			good = cname = 0; +			for (u=0, p=*ptr; p; ++u, p=p->next) +			{ +				if (p->rcode != RFC1035_RCODE_NOERROR || +					(n=rfc1035_replysearch_all(res, +								   p, namebuf, +								   qu[u].qtype, +								   qclass, 0)) +				    < 0) +					continue; +				else if (p->allrrs[n]->rrtype == qu[u].qtype) +				{ +					++good; +				} +				else // CNAME (not the queried type). +				{ +					if (rfc1035_replyhostname(p, p->anptr[n].rr.domainname, +						cname? cmpname1: cmpname2) == 0) +							fatal=-1; + +					else if (cname && strcmp(cmpname1, cmpname2)) +						query_again=1;  // different aliases: try again + +					++cname; +				} +			} + +			if (good == 0 && cname == 0) +			{ +				rfc1035_replyfree( *ptr ); +				*ptr=0; +				return (-1); +			} + +			if (good > 0 && cname > 0) +				query_again=1; // have both cnames and non-cnames + +			if (query_again) +			{ +				if (--retry_count > 0) +					break; + +				fatal=RFC1035_ERR_CNAME_RECURSIVE; +			} + +			if (fatal) +			{ +				rfc1035_replyfree( *ptr ); +				*ptr=0; +				return fatal; +			} + +			if (good) +				break; + +		/* CNAME found.  Return alias to caller, and restart from there */ + +			strcpy(namebuf, cmpname1); +		} + +	} while (query_again); + +	if (x_flags & RFC1035_X_RANDOMIZE) +		for (p=*ptr; p; p=p->next) +			if (p->rcode == RFC1035_RCODE_NOERROR) +				rfc1035_rr_rand(p); + +/* +*	Collecting allrrs shall be a further proposal. +	if ((x_flags & RFC1035_X_COLLECT) && +	    (*ptr)->rcode == RFC1035_RCODE_NOERROR) +		rfc1035_collect_allrrs(*ptr); +*/ + +	return (0); +} diff --git a/rfc1035/testlookup.c b/rfc1035/testlookup.c index cd99c81..75c701f 100644 --- a/rfc1035/testlookup.c +++ b/rfc1035/testlookup.c @@ -74,13 +74,65 @@ static void spflookup(const char *current_domain)  	}  } +static int get_q_type_pass(const char *p, +			    void (*cb)(unsigned char, void *), +			    void *ptr) +{ +	char qbuf[strlen(p)+1]; +	char *q; + +	strcpy(qbuf, p); + +	for (q=qbuf; (q=strtok(q, ", \t\r\n")); q=0) +	{ +		int n=rfc1035_type_strtoi(q); + +		if (n < 0) +			return -1; + +		(*cb)(n, ptr); +	} + +	return 0; +} + +static void get_q_type_count(unsigned char c, void *ptr) +{ +	++*(size_t *)ptr; +} + +static void get_q_type_save(unsigned char c, void *ptr) +{ +	*(*(unsigned char **)ptr)++=c; +} + +static unsigned char *get_q_type(const char *p) +{ +	size_t n=0; +	unsigned char *buf, *q; + +	errno=EINVAL; +	if (get_q_type_pass(p, &get_q_type_count, &n) < 0) +		return 0; + +	if ((buf=(unsigned char *)malloc(n+1)) == 0) +		return 0; + +	q=buf; +	get_q_type_pass(p, &get_q_type_save, &q); + +	*q=0; + +	return buf; +} +  int main(int argc, char **argv)  {  struct  rfc1035_res res;  struct	rfc1035_reply *replyp;  int	argn;  const char *q_name; -int	q_type; +unsigned char *q_type;  int	q_class;  int	q_xflag=0;  int	q_rflag=0; @@ -229,18 +281,26 @@ char	ptrbuf[RFC1035_MAXNAMESIZE+1];  		exit(1);  	} -	q_type= -1; +	q_type=0;  	if (argn < argc)  	{  		if (strcmp(argv[argn], "spf") == 0) -			q_type= -2; -		else -			q_type=rfc1035_type_strtoi(argv[argn++]); +		{ +			spflookup(q_name); +			exit(0); +		} +		q_type=get_q_type(argv[argn]); +		if (!q_type) +		{ +			perror(argv[argn]); +			exit(1); +		} +		argn++;  	} -	if (q_type == -1) -		q_type=q_xflag ? RFC1035_TYPE_PTR:RFC1035_TYPE_ANY; +	if (q_type == 0) +		q_type=get_q_type(q_xflag ? "PTR":"ANY");  	q_class= -1;  	if (argn < argc) @@ -248,22 +308,49 @@ char	ptrbuf[RFC1035_MAXNAMESIZE+1];  	if (q_class < 0)  		q_class=RFC1035_CLASS_IN; -	if (q_type == -2) +	if (q_type[0] && q_type[1])  	{ -		spflookup(q_name); -		exit(0); -	} +		char namebuf[RFC1035_MAXNAMESIZE+1]; -	replyp=rfc1035_resolve(&res, RFC1035_OPCODE_QUERY, -			       q_name, q_type, q_class); +		namebuf[0]=0; +		strncat(namebuf, q_name, RFC1035_MAXNAMESIZE); +		if (rfc1035_resolve_cname_multiple(&res, namebuf, +						   q_type, q_class, +						   &replyp, +						   RFC1035_X_RANDOMIZE) +		    < 0) +			replyp=0; +	} +	else +	{ +		replyp=rfc1035_resolve(&res, RFC1035_OPCODE_QUERY, +				       q_name, q_type[0], q_class); +	} +	free(q_type);  	if (!replyp)  	{  		perror(argv[0]);  		exit(1);  	} -	rfc1035_dump(replyp, stdout); +	if (q_type[0] && q_type[1]) +	{ +		struct rfc1035_reply *q; + +		for (q=replyp; q; q=q->next) +		{ +			struct rfc1035_reply *s=q->next; + +			q->next=0; +			rfc1035_dump(q, stdout); +			q->next=s; +		} +	} +	else +	{ +		rfc1035_dump(replyp, stdout); +	}  	rfc1035_replyfree(replyp);  	rfc1035_destroy_resolv(&res);  	return (0); | 
