13070Spst/*-
23070Spst * Copyright (c) 1985, 1988, 1993
33070Spst *	The Regents of the University of California.  All rights reserved.
43070Spst *
53070Spst * Redistribution and use in source and binary forms, with or without
63070Spst * modification, are permitted provided that the following conditions
73070Spst * are met:
83070Spst * 1. Redistributions of source code must retain the above copyright
93070Spst *    notice, this list of conditions and the following disclaimer.
103070Spst * 2. Redistributions in binary form must reproduce the above copyright
113070Spst *    notice, this list of conditions and the following disclaimer in the
123070Spst *    documentation and/or other materials provided with the distribution.
133070Spst * 4. Neither the name of the University nor the names of its contributors
143070Spst *    may be used to endorse or promote products derived from this software
153070Spst *    without specific prior written permission.
163070Spst *
173070Spst * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
183070Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
193070Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
203070Spst * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
213070Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
223070Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
233070Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
243070Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
253070Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
263070Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
273070Spst * SUCH DAMAGE.
283070Spst * -
293070Spst * Portions Copyright (c) 1993 by Digital Equipment Corporation.
308870Srgrimes *
313070Spst * Permission to use, copy, modify, and distribute this software for any
323070Spst * purpose with or without fee is hereby granted, provided that the above
333070Spst * copyright notice and this permission notice appear in all copies, and that
343070Spst * the name of Digital Equipment Corporation not be used in advertising or
353070Spst * publicity pertaining to distribution of the document or software without
363070Spst * specific, written prior permission.
378870Srgrimes *
383070Spst * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
393070Spst * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
403070Spst * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
413070Spst * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
423070Spst * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
433070Spst * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
443070Spst * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
453070Spst * SOFTWARE.
463070Spst * -
473070Spst * --Copyright--
483070Spst */
4913408Speter/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
5013408Speter *	Dep. Matematica Universidade de Coimbra, Portugal, Europe
5113408Speter *
5213408Speter * Permission to use, copy, modify, and distribute this software for any
5313408Speter * purpose with or without fee is hereby granted, provided that the above
5413408Speter * copyright notice and this permission notice appear in all copies.
5513408Speter */
563070Spst
573070Spst#if defined(LIBC_SCCS) && !defined(lint)
583070Spststatic char sccsid[] = "@(#)gethostnamadr.c	8.1 (Berkeley) 6/4/93";
593070Spst#endif /* LIBC_SCCS and not lint */
6092986Sobrien#include <sys/cdefs.h>
6192986Sobrien__FBSDID("$FreeBSD$");
623070Spst
633070Spst#include <sys/param.h>
643070Spst#include <sys/socket.h>
653070Spst#include <netinet/in.h>
663070Spst#include <arpa/inet.h>
673070Spst#include <arpa/nameser.h>
6813408Speter
69125555Sdds#include <errno.h>
7013408Speter#include <stdio.h>
71104415Sume#include <stdlib.h>
723070Spst#include <netdb.h>
733070Spst#include <resolv.h>
743070Spst#include <ctype.h>
753070Spst#include <string.h>
7613408Speter#include <unistd.h>
773070Spst#include <syslog.h>
7865532Snectar#include <stdarg.h>
7965532Snectar#include <nsswitch.h>
803070Spst
81145626Sume#include "netdb_private.h"
8213408Speter#include "res_config.h"
833070Spst
8413408Speter#define BYADDR 0
8513408Speter#define BYNAME 1
863070Spst
87104415Sume#define MAXPACKET	(64*1024)
883070Spst
893070Spsttypedef union {
9013408Speter	HEADER	hdr;
9113408Speter	u_char	buf[MAXPACKET];
923070Spst} querybuf;
933070Spst
943070Spsttypedef union {
9513408Speter	long	al;
9613408Speter	char	ac;
973070Spst} align;
983070Spst
99125555Sdds/*
100125555Sdds * Reverse the order of first four dotted entries of in.
101125555Sdds * Out must contain space for at least strlen(in) characters.
102125555Sdds * The result does not include any leading 0s of in.
103125555Sdds */
104125562Srustatic void
105125555Sddsipreverse(char *in, char *out)
106125555Sdds{
107125555Sdds	char *pos[4];
108125555Sdds	int len[4];
109125555Sdds	char *p, *start;
110125555Sdds	int i = 0;
111125555Sdds	int leading = 1;
112125555Sdds
113125555Sdds	/* Fill-in element positions and lengths: pos[], len[]. */
114125555Sdds	start = p = in;
115125555Sdds	for (;;) {
116125555Sdds		if (*p == '.' || *p == '\0') {
117125555Sdds			/* Leading 0? */
118125555Sdds			if (leading && p - start == 1 && *start == '0')
119125555Sdds				len[i] = 0;
120125555Sdds			else {
121125555Sdds				len[i] = p - start;
122125555Sdds				leading = 0;
123125555Sdds			}
124125555Sdds			pos[i] = start;
125125555Sdds			start = p + 1;
126125555Sdds			i++;
127125555Sdds		}
128125555Sdds		if (i == 4)
129125555Sdds			break;
130125555Sdds		if (*p == 0) {
131125555Sdds			for (; i < 4; i++) {
132125555Sdds				pos[i] = p;
133125555Sdds				len[i] = 0;
134125555Sdds			}
135125555Sdds			break;
136125555Sdds		}
137125555Sdds		p++;
138125555Sdds	}
139125555Sdds
140125555Sdds	/* Copy the entries in reverse order */
141125555Sdds	p = out;
142125555Sdds	leading = 1;
143125555Sdds	for (i = 3; i >= 0; i--) {
144125555Sdds		memcpy(p, pos[i], len[i]);
145125555Sdds		if (len[i])
146125555Sdds			leading = 0;
147125555Sdds		p += len[i];
148125555Sdds		/* Need a . separator? */
149125555Sdds		if (!leading && i > 0 && len[i - 1])
150125555Sdds			*p++ = '.';
151125555Sdds	}
152125555Sdds	*p = '\0';
153125555Sdds}
154125555Sdds
155145626Sumestatic int
156145626Sumegetnetanswer(querybuf *answer, int anslen, int net_i, struct netent *ne,
157156960Sume    struct netent_data *ned, res_state statp)
1583070Spst{
1593070Spst
16092889Sobrien	HEADER *hp;
16192889Sobrien	u_char *cp;
16292889Sobrien	int n;
16313408Speter	u_char *eom;
164125562Sru	int type, class, ancount, qdcount, haveanswer;
165125555Sdds	char aux[MAXHOSTNAMELEN];
166145626Sume	char ans[MAXHOSTNAMELEN];
167125555Sdds	char *in, *bp, *ep, **ap;
1683070Spst
1693070Spst	/*
1703070Spst	 * find first satisfactory answer
1713070Spst	 *
1723070Spst	 *      answer --> +------------+  ( MESSAGE )
1733070Spst	 *		   |   Header   |
1743070Spst	 *		   +------------+
1753070Spst	 *		   |  Question  | the question for the name server
1763070Spst	 *		   +------------+
1773070Spst	 *		   |   Answer   | RRs answering the question
1783070Spst	 *		   +------------+
1793070Spst	 *		   | Authority  | RRs pointing toward an authority
1803070Spst	 *		   | Additional | RRs holding additional information
1813070Spst	 *		   +------------+
1823070Spst	 */
1833070Spst	eom = answer->buf + anslen;
1843070Spst	hp = &answer->hdr;
1853070Spst	ancount = ntohs(hp->ancount); /* #/records in the answer section */
1863070Spst	qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
187145626Sume	bp = ned->netbuf;
188145626Sume	ep = ned->netbuf + sizeof(ned->netbuf);
1893070Spst	cp = answer->buf + HFIXEDSZ;
1903070Spst	if (!qdcount) {
1913070Spst		if (hp->aa)
192156960Sume			RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
1933070Spst		else
194156960Sume			RES_SET_H_ERRNO(statp, TRY_AGAIN);
195157779Sume		return (-1);
1963070Spst	}
19713408Speter	while (qdcount-- > 0)
1983070Spst		cp += __dn_skipname(cp, eom) + QFIXEDSZ;
199145626Sume	ap = ned->net_aliases;
2003070Spst	*ap = NULL;
201145626Sume	ne->n_aliases = ned->net_aliases;
2023070Spst	haveanswer = 0;
2033070Spst	while (--ancount >= 0 && cp < eom) {
20498865Simp		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
20517903Speter		if ((n < 0) || !res_dnok(bp))
2063070Spst			break;
2073070Spst		cp += n;
2083070Spst		ans[0] = '\0';
20932299Simp		(void)strncpy(&ans[0], bp, sizeof(ans) - 1);
21032299Simp		ans[sizeof(ans) - 1] = '\0';
2113070Spst		GETSHORT(type, cp);
2123070Spst		GETSHORT(class, cp);
2133070Spst		cp += INT32SZ;		/* TTL */
2143070Spst		GETSHORT(n, cp);
2153070Spst		if (class == C_IN && type == T_PTR) {
21698865Simp			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
21717903Speter			if ((n < 0) || !res_hnok(bp)) {
2183070Spst				cp += n;
219157779Sume				return (-1);
2203070Spst			}
221157779Sume			cp += n;
2223070Spst			*ap++ = bp;
22398860Simp			n = strlen(bp) + 1;
22498860Simp			bp += n;
225145626Sume			ne->n_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
2263070Spst			haveanswer++;
2273070Spst		}
2283070Spst	}
2293070Spst	if (haveanswer) {
2303070Spst		*ap = NULL;
2313070Spst		switch (net_i) {
23213408Speter		case BYADDR:
233145626Sume			ne->n_name = *ne->n_aliases;
234145626Sume			ne->n_net = 0L;
2353070Spst			break;
23613408Speter		case BYNAME:
237145626Sume			in = *ne->n_aliases;
238145626Sume			n = strlen(ans) + 1;
239145626Sume			if (ep - bp < n) {
240156960Sume				RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
241145626Sume				errno = ENOBUFS;
242157779Sume				return (-1);
243145626Sume			}
244145626Sume			strlcpy(bp, ans, ep - bp);
245145626Sume			ne->n_name = bp;
246125555Sdds			if (strlen(in) + 1 > sizeof(aux)) {
247156960Sume				RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
248125555Sdds				errno = ENOBUFS;
249157779Sume				return (-1);
250125555Sdds			}
251125555Sdds			ipreverse(in, aux);
252145626Sume			ne->n_net = inet_network(aux);
25313408Speter			break;
2543070Spst		}
255145626Sume		ne->n_aliases++;
256157779Sume		return (0);
2573070Spst	}
258156960Sume	RES_SET_H_ERRNO(statp, TRY_AGAIN);
259157779Sume	return (-1);
2603070Spst}
2613070Spst
26265532Snectarint
26365532Snectar_dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
2643070Spst{
265146244Sume	uint32_t net;
26665532Snectar	int net_type;
267157779Sume	char *buffer;
268157779Sume	size_t buflen;
269157779Sume	int *errnop, *h_errnop;
270157779Sume	struct netent *nptr, ne;
271145626Sume	struct netent_data *ned;
27213408Speter	unsigned int netbr[4];
273145626Sume	int nn, anslen, error;
274104415Sume	querybuf *buf;
27513408Speter	char qbuf[MAXDNAME];
276146244Sume	uint32_t net2;
277156960Sume	res_state statp;
2783070Spst
279146244Sume	net = va_arg(ap, uint32_t);
28065532Snectar	net_type = va_arg(ap, int);
281157779Sume	nptr = va_arg(ap, struct netent *);
282157779Sume	buffer = va_arg(ap, char *);
283157779Sume	buflen = va_arg(ap, size_t);
284157779Sume	errnop = va_arg(ap, int *);
285157779Sume	h_errnop = va_arg(ap, int *);
28665532Snectar
287156960Sume	statp = __res_state();
288156960Sume	if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
289156960Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
290157779Sume		*h_errnop = statp->res_h_errno;
291157779Sume		return (NS_UNAVAIL);
292156960Sume	}
293156960Sume
294157779Sume	if ((ned = __netent_data_init()) == NULL) {
295157779Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
296157779Sume		*h_errnop = statp->res_h_errno;
297157779Sume		return (NS_UNAVAIL);
298157779Sume	}
299157779Sume
300157779Sume	*((struct netent **)rval) = NULL;
301157779Sume
302157779Sume	if (net_type != AF_INET) {
303157779Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
304157779Sume		*h_errnop = statp->res_h_errno;
305157779Sume		return (NS_UNAVAIL);
306157779Sume	}
307157779Sume
30813408Speter	for (nn = 4, net2 = net; net2; net2 >>= 8)
3093070Spst		netbr[--nn] = net2 & 0xff;
3103070Spst	switch (nn) {
31113408Speter	case 3: 	/* Class A */
31213408Speter		sprintf(qbuf, "0.0.0.%u.in-addr.arpa", netbr[3]);
31313408Speter		break;
31413408Speter	case 2: 	/* Class B */
31513408Speter		sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", netbr[3], netbr[2]);
31613408Speter		break;
31713408Speter	case 1: 	/* Class C */
31813408Speter		sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
31913408Speter		    netbr[1]);
32013408Speter		break;
32113408Speter	case 0: 	/* Class D - E */
32213408Speter		sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
32313408Speter		    netbr[1], netbr[0]);
32413408Speter		break;
3253070Spst	}
326104415Sume	if ((buf = malloc(sizeof(*buf))) == NULL) {
327156960Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
328157779Sume		*h_errnop = statp->res_h_errno;
329157779Sume		return (NS_NOTFOUND);
330104415Sume	}
331156960Sume	anslen = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
332156960Sume	    sizeof(*buf));
3333070Spst	if (anslen < 0) {
334104415Sume		free(buf);
33513408Speter#ifdef DEBUG
336156960Sume		if (statp->options & RES_DEBUG)
337156960Sume			printf("res_nsearch failed\n");
33813408Speter#endif
339157779Sume		*h_errnop = statp->res_h_errno;
340157779Sume		return (NS_UNAVAIL);
341104415Sume	} else if (anslen > sizeof(*buf)) {
342104415Sume		free(buf);
343103350Snectar#ifdef DEBUG
344156960Sume		if (statp->options & RES_DEBUG)
345156960Sume			printf("res_nsearch static buffer too small\n");
346103350Snectar#endif
347157779Sume		*h_errnop = statp->res_h_errno;
348157779Sume		return (NS_UNAVAIL);
3493070Spst	}
350157779Sume	error = getnetanswer(buf, anslen, BYADDR, &ne, ned, statp);
351104415Sume	free(buf);
352145626Sume	if (error == 0) {
3533070Spst		/* Strip trailing zeros */
354146244Sume		while ((net & 0xff) == 0 && net != 0)
355146244Sume			net >>= 8;
356157779Sume		ne.n_net = net;
357157779Sume		if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
358211276Sume			*errnop = errno;
359211276Sume			RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
360157779Sume			*h_errnop = statp->res_h_errno;
361211276Sume			return (NS_RETURN);
362157779Sume		}
363157779Sume		*((struct netent **)rval) = nptr;
364157779Sume		return (NS_SUCCESS);
3653070Spst	}
366157779Sume	*h_errnop = statp->res_h_errno;
367157779Sume	return (NS_NOTFOUND);
3683070Spst}
3693070Spst
37065532Snectarint
37165532Snectar_dns_getnetbyname(void *rval, void *cb_data, va_list ap)
3723070Spst{
37365532Snectar	const char *net;
374157779Sume	char *buffer;
375157779Sume	size_t buflen;
376157779Sume	int *errnop, *h_errnop;
377157779Sume	struct netent *nptr, ne;
378145626Sume	struct netent_data *ned;
379145626Sume	int anslen, error;
380104415Sume	querybuf *buf;
38113408Speter	char qbuf[MAXDNAME];
382156960Sume	res_state statp;
3838870Srgrimes
38465532Snectar	net = va_arg(ap, const char *);
385157779Sume	nptr = va_arg(ap, struct netent *);
386157779Sume	buffer = va_arg(ap, char *);
387157779Sume	buflen = va_arg(ap, size_t);
388157779Sume	errnop = va_arg(ap, int *);
389157779Sume	h_errnop = va_arg(ap, int *);
39065532Snectar
391156960Sume	statp = __res_state();
392156960Sume	if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
393156960Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
394157779Sume		*h_errnop = statp->res_h_errno;
395157779Sume		return (NS_UNAVAIL);
39613408Speter	}
397157779Sume	if ((ned = __netent_data_init()) == NULL) {
398157779Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
399157779Sume		*h_errnop = statp->res_h_errno;
400157779Sume		return (NS_UNAVAIL);
401157779Sume	}
402104415Sume	if ((buf = malloc(sizeof(*buf))) == NULL) {
403156960Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
404157779Sume		*h_errnop = statp->res_h_errno;
405157779Sume		return (NS_NOTFOUND);
406104415Sume	}
407157779Sume
408157779Sume	*((struct netent **)rval) = NULL;
409157779Sume
41032299Simp	strncpy(qbuf, net, sizeof(qbuf) - 1);
41132299Simp	qbuf[sizeof(qbuf) - 1] = '\0';
412156960Sume	anslen = res_nsearch(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
413156960Sume	    sizeof(*buf));
4143070Spst	if (anslen < 0) {
415104415Sume		free(buf);
41613408Speter#ifdef DEBUG
417156960Sume		if (statp->options & RES_DEBUG)
418156960Sume			printf("res_nsearch failed\n");
41913408Speter#endif
420157779Sume		return (NS_UNAVAIL);
421104415Sume	} else if (anslen > sizeof(*buf)) {
422104415Sume		free(buf);
423103350Snectar#ifdef DEBUG
424156960Sume		if (statp->options & RES_DEBUG)
425103630Snectar			printf("res_search static buffer too small\n");
426103350Snectar#endif
427157779Sume		return (NS_UNAVAIL);
4283070Spst	}
429157779Sume	error = getnetanswer(buf, anslen, BYNAME, &ne, ned, statp);
430104415Sume	free(buf);
431157779Sume	if (error != 0) {
432157779Sume		*h_errnop = statp->res_h_errno;
433157779Sume		return (NS_NOTFOUND);
434157779Sume	}
435157779Sume	if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
436211276Sume		*errnop = errno;
437211276Sume		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
438157779Sume		*h_errnop = statp->res_h_errno;
439211276Sume		return (NS_RETURN);
440157779Sume	}
441157779Sume	*((struct netent **)rval) = nptr;
442157779Sume	return (NS_SUCCESS);
4433070Spst}
4443070Spst
4453070Spstvoid
446157779Sume_setnetdnsent(int stayopen)
4473070Spst{
448156960Sume	res_state statp;
449156960Sume
450156960Sume	statp = __res_state();
451156960Sume	if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)
452156960Sume		return;
4533070Spst	if (stayopen)
454156960Sume		statp->options |= RES_STAYOPEN | RES_USEVC;
4553070Spst}
4563070Spst
4573070Spstvoid
4583070Spst_endnetdnsent()
4593070Spst{
460156960Sume	res_state statp;
461156960Sume
462156960Sume	statp = __res_state();
463156960Sume	statp->options &= ~(RES_STAYOPEN | RES_USEVC);
464156960Sume	res_nclose(statp);
4653070Spst}
466