xref: /plan9/sys/src/cmd/ndb/dnresolve.c (revision 219b2ee8daee37f4aad58d63f21287faa8e4ffdc)
13e12c5d1SDavid du Colombier #include <u.h>
23e12c5d1SDavid du Colombier #include <libc.h>
3*219b2ee8SDavid du Colombier #include <lock.h>
43e12c5d1SDavid du Colombier #include "dns.h"
53e12c5d1SDavid du Colombier #include "ip.h"
63e12c5d1SDavid du Colombier 
73e12c5d1SDavid du Colombier enum
83e12c5d1SDavid du Colombier {
93e12c5d1SDavid du Colombier 	Maxdest=	32,	/* maximum destinations for a request message */
103e12c5d1SDavid du Colombier 	Maxtrans=	3,	/* maximum transmissions to a server */
113e12c5d1SDavid du Colombier };
123e12c5d1SDavid du Colombier 
133e12c5d1SDavid du Colombier typedef struct Dest	Dest;
143e12c5d1SDavid du Colombier struct Dest
153e12c5d1SDavid du Colombier {
163e12c5d1SDavid du Colombier 	uchar	a[4];	/* ip address */
173e12c5d1SDavid du Colombier 	DN	*s;	/* name server */
183e12c5d1SDavid du Colombier 	int	nx;	/* number of transmissions */
193e12c5d1SDavid du Colombier };
203e12c5d1SDavid du Colombier 
213e12c5d1SDavid du Colombier static ulong reqno;	/* request id */
223e12c5d1SDavid du Colombier 
233e12c5d1SDavid du Colombier static int	netquery(DN*, int, RR*, Request*);
243e12c5d1SDavid du Colombier static RR*	dnresolve1(char*, int, int, Request*);
253e12c5d1SDavid du Colombier 
263e12c5d1SDavid du Colombier /*
273e12c5d1SDavid du Colombier  *  lookup 'type' info for domain name 'name'.  If it doesn't exist, try
283e12c5d1SDavid du Colombier  *  looking it up as a canonical name.
293e12c5d1SDavid du Colombier  */
303e12c5d1SDavid du Colombier RR*
313e12c5d1SDavid du Colombier dnresolve(char *name, int class, int type, Request *req, RR **cn)
323e12c5d1SDavid du Colombier {
333e12c5d1SDavid du Colombier 	RR *rp;
343e12c5d1SDavid du Colombier 	DN *dp;
353e12c5d1SDavid du Colombier 
363e12c5d1SDavid du Colombier 	/* try the name directly */
373e12c5d1SDavid du Colombier 	rp = dnresolve1(name, class, type, req);
383e12c5d1SDavid du Colombier 	if(rp)
393e12c5d1SDavid du Colombier 		return rp;
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier 	/* try it as a canonical name */
423e12c5d1SDavid du Colombier 	rp = dnresolve1(name, class, Tcname, req);
433e12c5d1SDavid du Colombier 	if(rp == 0)
443e12c5d1SDavid du Colombier 		return 0;
453e12c5d1SDavid du Colombier 	if(rp && cn)
463e12c5d1SDavid du Colombier 		*cn = rp;
473e12c5d1SDavid du Colombier 	dp = rp->host;
483e12c5d1SDavid du Colombier 	return dnresolve1(dp->name, class, type, req);
493e12c5d1SDavid du Colombier }
503e12c5d1SDavid du Colombier 
513e12c5d1SDavid du Colombier static RR*
523e12c5d1SDavid du Colombier dnresolve1(char *name, int class, int type, Request *req)
533e12c5d1SDavid du Colombier {
543e12c5d1SDavid du Colombier 	DN *dp, *nsdp;
553e12c5d1SDavid du Colombier 	RR *rp, *nsrp;
563e12c5d1SDavid du Colombier 	char *cp;
573e12c5d1SDavid du Colombier 
583e12c5d1SDavid du Colombier 	/* only class Cin implemented so far */
593e12c5d1SDavid du Colombier 	if(class != Cin)
603e12c5d1SDavid du Colombier 		return 0;
613e12c5d1SDavid du Colombier 
623e12c5d1SDavid du Colombier 	dp = dnlookup(name, class, 1);
633e12c5d1SDavid du Colombier 
643e12c5d1SDavid du Colombier 	/* first try the cache */
653e12c5d1SDavid du Colombier 	rp = rrlookup(dp, type);
663e12c5d1SDavid du Colombier 	if(rp)
673e12c5d1SDavid du Colombier 		return rp;
683e12c5d1SDavid du Colombier 
69*219b2ee8SDavid du Colombier 	/* in-addr.arpa queries (and all) are special */
70*219b2ee8SDavid du Colombier 	if(tsame(type, Tptr)){
713e12c5d1SDavid du Colombier 		rp = dbinaddr(dp);
723e12c5d1SDavid du Colombier 		if(rp)
733e12c5d1SDavid du Colombier 			return rp;
743e12c5d1SDavid du Colombier 	}
753e12c5d1SDavid du Colombier 
763e12c5d1SDavid du Colombier 	/*
77*219b2ee8SDavid du Colombier 	 *  Quick grab, see if it's a 'relative to my domain' request.
78*219b2ee8SDavid du Colombier 	 *  I'm not sure this is a good idea but our x-terminals want it.
79*219b2ee8SDavid du Colombier 	 */
80*219b2ee8SDavid du Colombier 	if(strchr(name, '.') == 0){
81*219b2ee8SDavid du Colombier 		rp = dblookup(name, class, type, 1);
82*219b2ee8SDavid du Colombier 		if(rp)
83*219b2ee8SDavid du Colombier 			return rp;
84*219b2ee8SDavid du Colombier 	}
85*219b2ee8SDavid du Colombier 
86*219b2ee8SDavid du Colombier 	/*
873e12c5d1SDavid du Colombier  	 *  walk up the domain name looking for
883e12c5d1SDavid du Colombier 	 *  a name server for the domain.
893e12c5d1SDavid du Colombier 	 */
903e12c5d1SDavid du Colombier 	for(cp = name; cp; cp = walkup(cp)){
913e12c5d1SDavid du Colombier 		/* look for ns in cache and database */
923e12c5d1SDavid du Colombier 		nsdp = dnlookup(cp, class, 0);
933e12c5d1SDavid du Colombier 		nsrp = 0;
943e12c5d1SDavid du Colombier 		if(nsdp)
953e12c5d1SDavid du Colombier 			nsrp = rrlookup(nsdp, Tns);
963e12c5d1SDavid du Colombier 		if(nsrp == 0)
973e12c5d1SDavid du Colombier 			nsrp = dblookup(cp, class, Tns, 0);
983e12c5d1SDavid du Colombier 
993e12c5d1SDavid du Colombier 		if(nsrp){
1003e12c5d1SDavid du Colombier 			/* local domains resolved from this db */
1013e12c5d1SDavid du Colombier 			if(nsrp->local){
1023e12c5d1SDavid du Colombier 				if(nsrp->db)	/* free database rr's */
1033e12c5d1SDavid du Colombier 					rrfreelist(nsrp);
1043e12c5d1SDavid du Colombier 				return dblookup(name, class, type, 1);
1053e12c5d1SDavid du Colombier 			}
1063e12c5d1SDavid du Colombier 
1073e12c5d1SDavid du Colombier 			/* try the name servers */
1083e12c5d1SDavid du Colombier 			if(netquery(dp, type, nsrp, req)){
1093e12c5d1SDavid du Colombier 				/* we got an answer */
1103e12c5d1SDavid du Colombier 				if(nsrp->db)	/* free database rr's */
1113e12c5d1SDavid du Colombier 					rrfreelist(nsrp);
1123e12c5d1SDavid du Colombier 				return rrlookup(dp, type);
1133e12c5d1SDavid du Colombier 			}
1143e12c5d1SDavid du Colombier 		}
1153e12c5d1SDavid du Colombier 	}
1163e12c5d1SDavid du Colombier 
1173e12c5d1SDavid du Colombier 	/* noone answered */
1183e12c5d1SDavid du Colombier 	return 0;
1193e12c5d1SDavid du Colombier }
1203e12c5d1SDavid du Colombier 
1213e12c5d1SDavid du Colombier /*
1223e12c5d1SDavid du Colombier  *  walk a domain name one element to the right.  return a pointer to that element.
1233e12c5d1SDavid du Colombier  *  in other words, return a pointer to the parent domain name.
1243e12c5d1SDavid du Colombier  */
1253e12c5d1SDavid du Colombier char*
1263e12c5d1SDavid du Colombier walkup(char *name)
1273e12c5d1SDavid du Colombier {
1283e12c5d1SDavid du Colombier 	char *cp;
1293e12c5d1SDavid du Colombier 
1303e12c5d1SDavid du Colombier 	cp = strchr(name, '.');
1313e12c5d1SDavid du Colombier 	if(cp)
1323e12c5d1SDavid du Colombier 		return cp+1;
1333e12c5d1SDavid du Colombier 	else if(*name)
1343e12c5d1SDavid du Colombier 		return "";
1353e12c5d1SDavid du Colombier 	else
1363e12c5d1SDavid du Colombier 		return 0;
1373e12c5d1SDavid du Colombier }
1383e12c5d1SDavid du Colombier 
1393e12c5d1SDavid du Colombier /*
1403e12c5d1SDavid du Colombier  *  Get a udpport for requests and replies.  Put the port
1413e12c5d1SDavid du Colombier  *  into "headers" mode.
1423e12c5d1SDavid du Colombier  */
1433e12c5d1SDavid du Colombier static char *hmsg = "headers";
1443e12c5d1SDavid du Colombier 
1453e12c5d1SDavid du Colombier static int
1463e12c5d1SDavid du Colombier udpport(void)
1473e12c5d1SDavid du Colombier {
1483e12c5d1SDavid du Colombier 	int fd, ctl;
1493e12c5d1SDavid du Colombier 
1503e12c5d1SDavid du Colombier 	/* get a udp port */
1513e12c5d1SDavid du Colombier 	fd = dial("udp!0.0.0.0!0", 0, 0, &ctl);
152bd389b36SDavid du Colombier 	if(fd < 0){
153bd389b36SDavid du Colombier 		warning("can't get udp port");
154bd389b36SDavid du Colombier 		return -1;
155bd389b36SDavid du Colombier 	}
1563e12c5d1SDavid du Colombier 
1573e12c5d1SDavid du Colombier 	/* turn on header style interface */
158bd389b36SDavid du Colombier 	if(write(ctl, hmsg, strlen(hmsg)) , 0){
159bd389b36SDavid du Colombier 		warning(hmsg);
160bd389b36SDavid du Colombier 		return -1;
161bd389b36SDavid du Colombier 	}
1623e12c5d1SDavid du Colombier 
1633e12c5d1SDavid du Colombier 	close(ctl);
1643e12c5d1SDavid du Colombier 	return fd;
1653e12c5d1SDavid du Colombier }
1663e12c5d1SDavid du Colombier 
1673e12c5d1SDavid du Colombier static int
1683e12c5d1SDavid du Colombier mkreq(DN *dp, int type, uchar *buf, int reqno)
1693e12c5d1SDavid du Colombier {
1703e12c5d1SDavid du Colombier 	DNSmsg m;
1713e12c5d1SDavid du Colombier 	int len;
1723e12c5d1SDavid du Colombier 
1733e12c5d1SDavid du Colombier 	/* stuff port number into output buffer */
1743e12c5d1SDavid du Colombier 	buf[4] = 0;
1753e12c5d1SDavid du Colombier 	buf[5] = 53;
1763e12c5d1SDavid du Colombier 
1773e12c5d1SDavid du Colombier 	/* make request and convert it to output format */
1783e12c5d1SDavid du Colombier 	memset(&m, 0, sizeof(m));
179*219b2ee8SDavid du Colombier 	m.flags = Frecurse;
1803e12c5d1SDavid du Colombier 	m.id = reqno;
1813e12c5d1SDavid du Colombier 	m.qd = rralloc(type);
1823e12c5d1SDavid du Colombier 	m.qd->owner = dp;
1833e12c5d1SDavid du Colombier 	m.qd->type = type;
184*219b2ee8SDavid du Colombier 	len = convDNS2M(&m, &buf[Udphdrsize], Maxudp);
1853e12c5d1SDavid du Colombier 	if(len < 0)
1863e12c5d1SDavid du Colombier 		fatal("can't convert");
1873e12c5d1SDavid du Colombier 	return len;
1883e12c5d1SDavid du Colombier }
1893e12c5d1SDavid du Colombier 
1903e12c5d1SDavid du Colombier /*
1913e12c5d1SDavid du Colombier  *  read replies to a request.  ignore any of the wrong type.
1923e12c5d1SDavid du Colombier  */
1933e12c5d1SDavid du Colombier static int
1943e12c5d1SDavid du Colombier readreq(int fd, DN *dp, int type, int req, uchar *ibuf, DNSmsg *mp)
1953e12c5d1SDavid du Colombier {
1963e12c5d1SDavid du Colombier 	char *err;
1973e12c5d1SDavid du Colombier 	int len;
1983e12c5d1SDavid du Colombier 
1993e12c5d1SDavid du Colombier 	for(;;){
200*219b2ee8SDavid du Colombier 		len = read(fd, ibuf, Udphdrsize+Maxudp);
201*219b2ee8SDavid du Colombier 		len -= Udphdrsize;
2023e12c5d1SDavid du Colombier 		if(len < 0)
2033e12c5d1SDavid du Colombier 			return -1;	/* timed out */
2043e12c5d1SDavid du Colombier 
2053e12c5d1SDavid du Colombier 		/* convert into internal format  */
206*219b2ee8SDavid du Colombier 		err = convM2DNS(&ibuf[Udphdrsize], len, mp);
2073e12c5d1SDavid du Colombier 		if(err){
2083e12c5d1SDavid du Colombier 			syslog(0, "dns", "input err %s", err);
2093e12c5d1SDavid du Colombier 			continue;
2103e12c5d1SDavid du Colombier 		}
211*219b2ee8SDavid du Colombier 		if(debug){
212*219b2ee8SDavid du Colombier 			if(mp->qd)
213*219b2ee8SDavid du Colombier 				syslog(0, "dns", "rcvd %I qd %s", ibuf, mp->qd->owner->name);
214*219b2ee8SDavid du Colombier 			if(mp->an)
215*219b2ee8SDavid du Colombier 				syslog(0, "dns", "rcvd %I an %R", ibuf, mp->an);
216*219b2ee8SDavid du Colombier 			if(mp->ns)
217*219b2ee8SDavid du Colombier 				syslog(0, "dns", "rcvd %I ns %R", ibuf, mp->ns);
218*219b2ee8SDavid du Colombier 			if(mp->ar)
219*219b2ee8SDavid du Colombier 				syslog(0, "dns", "rcvd %I ar %R", ibuf, mp->ar);
220*219b2ee8SDavid du Colombier 		}
2213e12c5d1SDavid du Colombier 
2223e12c5d1SDavid du Colombier 		/* answering the right question? */
2233e12c5d1SDavid du Colombier 		if(mp->id != req){
2243e12c5d1SDavid du Colombier 			syslog(0, "dns", "id %d instead of %d", mp->id, req);
2253e12c5d1SDavid du Colombier 			continue;
2263e12c5d1SDavid du Colombier 		}
2273e12c5d1SDavid du Colombier 		if(mp->qd == 0){
2283e12c5d1SDavid du Colombier 			syslog(0, "dns", "no question RR");
2293e12c5d1SDavid du Colombier 			continue;
2303e12c5d1SDavid du Colombier 		}
2313e12c5d1SDavid du Colombier 		if(mp->qd->owner != dp){
2323e12c5d1SDavid du Colombier 			syslog(0, "dns", "owner %s instead of %s", mp->qd->owner->name,
2333e12c5d1SDavid du Colombier 				dp->name);
2343e12c5d1SDavid du Colombier 			continue;
2353e12c5d1SDavid du Colombier 		}
2363e12c5d1SDavid du Colombier 		if(mp->qd->type != type){
2373e12c5d1SDavid du Colombier 			syslog(0, "dns", "type %d instead of %d", mp->qd->type, type);
2383e12c5d1SDavid du Colombier 			continue;
2393e12c5d1SDavid du Colombier 		}
2403e12c5d1SDavid du Colombier 		return 0;
2413e12c5d1SDavid du Colombier 	}
2423e12c5d1SDavid du Colombier 
2433e12c5d1SDavid du Colombier 	return 0;	/* never reached */
2443e12c5d1SDavid du Colombier }
2453e12c5d1SDavid du Colombier 
2463e12c5d1SDavid du Colombier /*
2473e12c5d1SDavid du Colombier  *  query name servers.  If the name server returns a pointer to another
2483e12c5d1SDavid du Colombier  *  name server, recurse.
2493e12c5d1SDavid du Colombier  */
2503e12c5d1SDavid du Colombier static void
2513e12c5d1SDavid du Colombier ding(void *x, char *msg)
2523e12c5d1SDavid du Colombier {
2533e12c5d1SDavid du Colombier 	USED(x);
2543e12c5d1SDavid du Colombier 	if(strcmp(msg, "alarm") == 0)
2553e12c5d1SDavid du Colombier 		noted(NCONT);
2563e12c5d1SDavid du Colombier 	else
2573e12c5d1SDavid du Colombier 		noted(NDFLT);
2583e12c5d1SDavid du Colombier }
2593e12c5d1SDavid du Colombier static int
2603e12c5d1SDavid du Colombier netquery(DN *dp, int type, RR *nsrp, Request *reqp)
2613e12c5d1SDavid du Colombier {
2623e12c5d1SDavid du Colombier 	int fd, i, j, len;
2633e12c5d1SDavid du Colombier 	ulong req;
2643e12c5d1SDavid du Colombier 	RR *rp;
2653e12c5d1SDavid du Colombier 	Dest *p, *l;
2663e12c5d1SDavid du Colombier 	DN *ndp;
2673e12c5d1SDavid du Colombier 	Dest dest[Maxdest];
2683e12c5d1SDavid du Colombier 	DNSmsg m;
269*219b2ee8SDavid du Colombier 	uchar obuf[Maxudp+Udphdrsize];
270*219b2ee8SDavid du Colombier 	uchar ibuf[Maxudp+Udphdrsize];
2713e12c5d1SDavid du Colombier 
2723e12c5d1SDavid du Colombier 	slave(reqp);
2733e12c5d1SDavid du Colombier 
2743e12c5d1SDavid du Colombier 	/* get the addresses */
2753e12c5d1SDavid du Colombier 	l = dest;
2763e12c5d1SDavid du Colombier 	for(; nsrp && nsrp->type == Tns; nsrp = nsrp->next){
2773e12c5d1SDavid du Colombier 		rp = rrlookup(nsrp->host, Ta);
2783e12c5d1SDavid du Colombier 		if(rp == 0)
2793e12c5d1SDavid du Colombier 			rp = dblookup(nsrp->host->name, Cin, Ta, 0);
2803e12c5d1SDavid du Colombier 		for(; rp && rp->type == Ta; rp = rp->next){
2813e12c5d1SDavid du Colombier 			if(l >= &dest[Maxdest])
2823e12c5d1SDavid du Colombier 				break;
2833e12c5d1SDavid du Colombier 			parseip(l->a, rp->ip->name);
2843e12c5d1SDavid du Colombier 			l->nx = 0;
2853e12c5d1SDavid du Colombier 			l->s = nsrp->host;
2863e12c5d1SDavid du Colombier 			l++;
2873e12c5d1SDavid du Colombier 		}
2883e12c5d1SDavid du Colombier 	}
2893e12c5d1SDavid du Colombier 
2903e12c5d1SDavid du Colombier 	/* pack request into a message */
2913e12c5d1SDavid du Colombier 	req = reqno++;
2923e12c5d1SDavid du Colombier 	len = mkreq(dp, type, obuf, req);
2933e12c5d1SDavid du Colombier 
2943e12c5d1SDavid du Colombier 	/*
2953e12c5d1SDavid du Colombier 	 *  transmit requests and wait for answers.
296*219b2ee8SDavid du Colombier 	 *  at most Maxtrans attempts to each address.
2973e12c5d1SDavid du Colombier 	 *  each cycle send one more message than the previous.
2983e12c5d1SDavid du Colombier 	 */
2993e12c5d1SDavid du Colombier 	fd = udpport();
300bd389b36SDavid du Colombier 	if(fd < 0)
301bd389b36SDavid du Colombier 		return 0;
3023e12c5d1SDavid du Colombier 	notify(ding);
3033e12c5d1SDavid du Colombier 	for(i = 1;; i++){
3043e12c5d1SDavid du Colombier 		/* send to i destinations */
3053e12c5d1SDavid du Colombier 		p = dest;
3063e12c5d1SDavid du Colombier 		for(j = 0; j < i; j++){
3073e12c5d1SDavid du Colombier 			/* skip destinations we've finished with */
3083e12c5d1SDavid du Colombier 			for(; p < l; p++)
3093e12c5d1SDavid du Colombier 				if(p->nx < Maxtrans)
3103e12c5d1SDavid du Colombier 					break;
3113e12c5d1SDavid du Colombier 			if(p >= l)
3123e12c5d1SDavid du Colombier 				break;
3133e12c5d1SDavid du Colombier 
3143e12c5d1SDavid du Colombier 			p->nx++;
3153e12c5d1SDavid du Colombier 			memmove(obuf, p->a, sizeof(p->a));
316*219b2ee8SDavid du Colombier 			if(debug)
317*219b2ee8SDavid du Colombier 				syslog(0, "dns", "sending to %I", obuf);
318*219b2ee8SDavid du Colombier 			if(write(fd, obuf, len + Udphdrsize) < 0)
319bd389b36SDavid du Colombier 				warning("sending udp msg %r");
3203e12c5d1SDavid du Colombier 			p++;
3213e12c5d1SDavid du Colombier 		}
3223e12c5d1SDavid du Colombier 		if(j == 0)
3233e12c5d1SDavid du Colombier 			break;		/* no destinations left */
3243e12c5d1SDavid du Colombier 
3253e12c5d1SDavid du Colombier 		/* wait a fixed time for replies */
3263e12c5d1SDavid du Colombier 		alarm(1000);
3273e12c5d1SDavid du Colombier 		for(;;){
3283e12c5d1SDavid du Colombier 			if(readreq(fd, dp, type, req, ibuf, &m) < 0)
3293e12c5d1SDavid du Colombier 				break;		/* timed out */
3303e12c5d1SDavid du Colombier 
3313e12c5d1SDavid du Colombier 			/* remove all addrs of responding server from list */
3323e12c5d1SDavid du Colombier 			for(p = dest; p < l; p++)
3333e12c5d1SDavid du Colombier 				if(memcmp(p->a, ibuf, sizeof(p->a)) == 0){
3343e12c5d1SDavid du Colombier 					ndp = p->s;
3353e12c5d1SDavid du Colombier 					for(p = dest; p < l; p++)
3363e12c5d1SDavid du Colombier 						if(p->s == ndp)
3373e12c5d1SDavid du Colombier 							p->nx = Maxtrans;
3383e12c5d1SDavid du Colombier 					break;
3393e12c5d1SDavid du Colombier 				}
3403e12c5d1SDavid du Colombier 
3413e12c5d1SDavid du Colombier 			/* incorporate answers */
3423e12c5d1SDavid du Colombier 			if(m.an)
3433e12c5d1SDavid du Colombier 				rrattach(m.an, m.flags & Fauth);
3443e12c5d1SDavid du Colombier 			if(m.ar)
3453e12c5d1SDavid du Colombier 				rrattach(m.ar, 0);
3463e12c5d1SDavid du Colombier 
3473e12c5d1SDavid du Colombier 			/*
3483e12c5d1SDavid du Colombier 			 *  Any reply from an authoritative server,
3493e12c5d1SDavid du Colombier 			 *  or a positive reply terminates the search
3503e12c5d1SDavid du Colombier 			 */
3513e12c5d1SDavid du Colombier 			if(m.an || (m.flags & Fauth)){
3523e12c5d1SDavid du Colombier 				alarm(0);
3533e12c5d1SDavid du Colombier 				close(fd);
3543e12c5d1SDavid du Colombier 				return 1;
3553e12c5d1SDavid du Colombier 			}
3563e12c5d1SDavid du Colombier 
3573e12c5d1SDavid du Colombier 			/*
3583e12c5d1SDavid du Colombier 			 *  if we've been given better name servers
3593e12c5d1SDavid du Colombier 			 *  recurse
3603e12c5d1SDavid du Colombier 			 */
3613e12c5d1SDavid du Colombier 			if(m.ns){
3623e12c5d1SDavid du Colombier 				alarm(0);
3633e12c5d1SDavid du Colombier 				close(fd);
3643e12c5d1SDavid du Colombier 				ndp = m.ns->owner;
3653e12c5d1SDavid du Colombier 				rrattach(m.ns, 0);
3663e12c5d1SDavid du Colombier 				return netquery(dp, type, rrlookup(ndp, Tns), reqp);
3673e12c5d1SDavid du Colombier 			}
3683e12c5d1SDavid du Colombier 		}
3693e12c5d1SDavid du Colombier 		alarm(0);
3703e12c5d1SDavid du Colombier 	}
3713e12c5d1SDavid du Colombier 	alarm(0);
3723e12c5d1SDavid du Colombier 	close(fd);
3733e12c5d1SDavid du Colombier 	return 0;
3743e12c5d1SDavid du Colombier }
375