diff options
Diffstat (limited to 'rfc1035/rfc1035resolve.c')
| -rw-r--r-- | rfc1035/rfc1035resolve.c | 236 | 
1 files changed, 236 insertions, 0 deletions
| diff --git a/rfc1035/rfc1035resolve.c b/rfc1035/rfc1035resolve.c new file mode 100644 index 0000000..d772eb0 --- /dev/null +++ b/rfc1035/rfc1035resolve.c @@ -0,0 +1,236 @@ +/* +** Copyright 1998 - 2000 Double Precision, Inc. +** See COPYING for distribution information. +*/ + +#include	"config.h" +#include	<stdio.h> +#include	"soxwrap/soxwrap.h" +#include	"rfc1035.h" +#include	<errno.h> +#if	HAVE_UNISTD_H +#include	<unistd.h> +#endif +#include	<stdlib.h> +#include	<string.h> + + +struct querybuf { +	char qbuf[512]; +	unsigned qbuflen; +	} ; + +static void putqbuf(const char *p, unsigned l, void *q) +{ +struct querybuf *qp=(struct querybuf *)q; + +	if (qp->qbuflen < sizeof(qp->qbuf) && +			sizeof(qp->qbuf) - qp->qbuflen >= l) +		memcpy(qp->qbuf+qp->qbuflen, p, l); +	qp->qbuflen += l; +} + +struct rfc1035_reply *rfc1035_resolve_multiple( +			struct rfc1035_res *res, +			int opcode, +			const struct rfc1035_query *queries, +			unsigned nqueries) +{ +struct	querybuf qbuf; +int	udpfd; +int	attempt; +const RFC1035_ADDR *ns; +unsigned nscount; +unsigned current_timeout, timeout_backoff; +unsigned nbackoff, backoff_num; +int	af; +static const char fakereply[]={0, 0, 0, RFC1035_RCODE_SERVFAIL, +		0, 0, +		0, 0, +		0, 0, +		0, 0}; + +	nscount=res->rfc1035_nnameservers; +	ns=res->nameservers; + +	if (res->rfc1035_good_ns >= nscount) +		res->rfc1035_good_ns=0; + +	qbuf.qbuflen=0; +	if ( rfc1035_mkquery(res, +		opcode, queries, nqueries, &putqbuf, &qbuf)) +	{ +		errno=EINVAL; +		return (0); +	} + +	/* Prepare the UDP socket */ + +	if ((udpfd=rfc1035_open_udp(&af)) < 0)	return (0); + +	/* Keep trying until we get an answer from a nameserver */ + +	current_timeout=res->rfc1035_timeout_initial; +	nbackoff=res->rfc1035_timeout_backoff; +	if (!current_timeout)	current_timeout=RFC1035_DEFAULT_INITIAL_TIMEOUT; +	if (!nbackoff)	nbackoff=RFC1035_DEFAULT_MAXIMUM_BACKOFF; + +	timeout_backoff=current_timeout; +    for (backoff_num=0; backoff_num < nbackoff; backoff_num++, +					current_timeout *= timeout_backoff) + + +	for ( attempt=0; attempt < nscount; ++attempt) +	{ +	int	nbytes; +	char	*reply; +	struct	rfc1035_reply *rfcreply=0; + +	const RFC1035_ADDR *sin=&ns[(res->rfc1035_good_ns+attempt) % nscount]; +	int	sin_len=sizeof(*sin); + +	int	dotcp=0, isaxfr=0; +	unsigned i; + +		for (i=0; i<nqueries; i++) +			if (queries[i].qtype == RFC1035_TYPE_AXFR) +			{ +				dotcp=1; +				isaxfr=1; +				break; +			} + +		if (isaxfr && nqueries > 1) +			return (rfc1035_replyparse(fakereply, +				sizeof(fakereply))); + +		if (!dotcp) +		{ +		/* Send the query via UDP */ +		RFC1035_NETADDR	addrbuf; +		const struct sockaddr *addrptr; +		int	addrptrlen; + +			if (rfc1035_mkaddress(af, &addrbuf, +				sin, htons(53), +				&addrptr, &addrptrlen)) +				continue; + +			if ((reply=rfc1035_query_udp(res, udpfd, addrptr, +				addrptrlen, qbuf.qbuf, qbuf.qbuflen, &nbytes, +					current_timeout)) == 0) +				continue; + +			res->rfc1035_good_ns= (res->rfc1035_good_ns + attempt) % +					nscount; + +		/* Parse the reply */ + +			rfcreply=rfc1035_replyparse(reply, nbytes); +			if (!rfcreply) +			{ +				free(reply); +				if (errno == ENOMEM)	break; +				continue; +			/* Bad response from the server, try the next one. */ +			} +			rfcreply->mallocedbuf=reply; +		/* +		** If the reply came back with the truncated bit set, +		** retry the query via TCP. +		*/ + +			if (rfcreply->tc) +			{ +				dotcp=1; +				rfc1035_replyfree(rfcreply); +			} +		} + +		if (dotcp) +		{ +		int	tcpfd; +		struct	rfc1035_reply *firstreply=0, *lastreply=0; + +			if ((tcpfd=rfc1035_open_tcp(res, sin)) < 0) +				continue;	/* +						** Can't connect via TCP, +						** try the next server. +						*/ + +			reply=rfc1035_query_tcp(res, tcpfd, qbuf.qbuf, +				qbuf.qbuflen, &nbytes, current_timeout); + +			if (!reply) +			{ +				sox_close(tcpfd); +				continue; +			} + +			res->rfc1035_good_ns= (res->rfc1035_good_ns +					+ attempt) % nscount; + +			rfcreply=rfc1035_replyparse(reply, nbytes); +			if (!rfcreply) +			{ +				free(reply); +				sox_close(tcpfd); +				continue; +			} +			rfcreply->mallocedbuf=reply; +			firstreply=lastreply=rfcreply; +			while (isaxfr && rfcreply->rcode == 0) +			{ +				if ((reply=rfc1035_recv_tcp(res, +					tcpfd, &nbytes, current_timeout))==0) +					break; +				 +				rfcreply=rfc1035_replyparse(reply, nbytes); +				if (!rfcreply) +				{ +					free(reply); +					rfc1035_replyfree(firstreply); +					firstreply=0; +					break; +				} +				rfcreply->mallocedbuf=reply; +				lastreply->next=rfcreply; +				lastreply=rfcreply; + +				if ( rfcreply->ancount && +					rfcreply->anptr[0].rrtype == +						RFC1035_TYPE_SOA) +					break; +			} +			sox_close(tcpfd); +			if (!firstreply) +				return (0); +			rfcreply=firstreply; +		} +		memcpy(&rfcreply->server_addr, sin, sin_len); +		sox_close(udpfd); +		return (rfcreply); +	} + +	/* +	** Return a fake server failure reply, when we couldn't contact +	** any name server. +	*/ +	sox_close(udpfd); +	return (rfc1035_replyparse(fakereply, sizeof(fakereply))); +} + +struct rfc1035_reply *rfc1035_resolve( +	struct rfc1035_res *res, +	int opcode, +	const char *name, +	unsigned qtype, +	unsigned qclass) +{ +struct rfc1035_query q; + +	q.name=name; +	q.qtype=qtype; +	q.qclass=qclass; +	return (rfc1035_resolve_multiple(res, opcode, &q, 1)); +} | 
