1/*-
2 * SPDX-License-Identifier: BSD-3-Clause
3 *
4 * Copyright (c) 1985, 1988, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 *    may be used to endorse or promote products derived from this software
17 *    without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
30 * -
31 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
32 *
33 * Permission to use, copy, modify, and distribute this software for any
34 * purpose with or without fee is hereby granted, provided that the above
35 * copyright notice and this permission notice appear in all copies, and that
36 * the name of Digital Equipment Corporation not be used in advertising or
37 * publicity pertaining to distribution of the document or software without
38 * specific, written prior permission.
39 *
40 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
41 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
42 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
43 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
44 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
45 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
46 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
47 * SOFTWARE.
48 * -
49 * --Copyright--
50 */
51/* Portions Copyright (c) 1993 Carlos Leandro and Rui Salgueiro
52 *	Dep. Matematica Universidade de Coimbra, Portugal, Europe
53 *
54 * Permission to use, copy, modify, and distribute this software for any
55 * purpose with or without fee is hereby granted, provided that the above
56 * copyright notice and this permission notice appear in all copies.
57 */
58
59#include <sys/param.h>
60#include <sys/socket.h>
61#include <netinet/in.h>
62#include <arpa/inet.h>
63#include <arpa/nameser.h>
64
65#include <errno.h>
66#include <stdio.h>
67#include <stdlib.h>
68#include <netdb.h>
69#include <resolv.h>
70#include <ctype.h>
71#include <string.h>
72#include <unistd.h>
73#include <syslog.h>
74#include <stdarg.h>
75#include <nsswitch.h>
76
77#include "netdb_private.h"
78#include "res_config.h"
79
80#define BYADDR 0
81#define BYNAME 1
82
83#define MAXPACKET	(64*1024)
84
85typedef union {
86	HEADER	hdr;
87	u_char	buf[MAXPACKET];
88} querybuf;
89
90typedef union {
91	long	al;
92	char	ac;
93} align;
94
95/*
96 * Reverse the order of first four dotted entries of in.
97 * Out must contain space for at least strlen(in) characters.
98 * The result does not include any leading 0s of in.
99 */
100static void
101ipreverse(char *in, char *out)
102{
103	char *pos[4];
104	int len[4];
105	char *p, *start;
106	int i = 0;
107	int leading = 1;
108
109	/* Fill-in element positions and lengths: pos[], len[]. */
110	start = p = in;
111	for (;;) {
112		if (*p == '.' || *p == '\0') {
113			/* Leading 0? */
114			if (leading && p - start == 1 && *start == '0')
115				len[i] = 0;
116			else {
117				len[i] = p - start;
118				leading = 0;
119			}
120			pos[i] = start;
121			start = p + 1;
122			i++;
123		}
124		if (i == 4)
125			break;
126		if (*p == 0) {
127			for (; i < 4; i++) {
128				pos[i] = p;
129				len[i] = 0;
130			}
131			break;
132		}
133		p++;
134	}
135
136	/* Copy the entries in reverse order */
137	p = out;
138	leading = 1;
139	for (i = 3; i >= 0; i--) {
140		memcpy(p, pos[i], len[i]);
141		if (len[i])
142			leading = 0;
143		p += len[i];
144		/* Need a . separator? */
145		if (!leading && i > 0 && len[i - 1])
146			*p++ = '.';
147	}
148	*p = '\0';
149}
150
151static int
152getnetanswer(querybuf *answer, int anslen, int net_i, struct netent *ne,
153    struct netent_data *ned, res_state statp)
154{
155
156	HEADER *hp;
157	u_char *cp;
158	int n;
159	u_char *eom;
160	int type, class, ancount, qdcount, haveanswer;
161	char aux[MAXHOSTNAMELEN];
162	char ans[MAXHOSTNAMELEN];
163	char *in, *bp, *ep, **ap;
164
165	/*
166	 * find first satisfactory answer
167	 *
168	 *      answer --> +------------+  ( MESSAGE )
169	 *		   |   Header   |
170	 *		   +------------+
171	 *		   |  Question  | the question for the name server
172	 *		   +------------+
173	 *		   |   Answer   | RRs answering the question
174	 *		   +------------+
175	 *		   | Authority  | RRs pointing toward an authority
176	 *		   | Additional | RRs holding additional information
177	 *		   +------------+
178	 */
179	eom = answer->buf + anslen;
180	hp = &answer->hdr;
181	ancount = ntohs(hp->ancount); /* #/records in the answer section */
182	qdcount = ntohs(hp->qdcount); /* #/entries in the question section */
183	bp = ned->netbuf;
184	ep = ned->netbuf + sizeof(ned->netbuf);
185	cp = answer->buf + HFIXEDSZ;
186	if (!qdcount) {
187		if (hp->aa)
188			RES_SET_H_ERRNO(statp, HOST_NOT_FOUND);
189		else
190			RES_SET_H_ERRNO(statp, TRY_AGAIN);
191		return (-1);
192	}
193	while (qdcount-- > 0)
194		cp += __dn_skipname(cp, eom) + QFIXEDSZ;
195	ap = ned->net_aliases;
196	*ap = NULL;
197	ne->n_aliases = ned->net_aliases;
198	haveanswer = 0;
199	while (--ancount >= 0 && cp < eom) {
200		n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
201		if ((n < 0) || !res_dnok(bp))
202			break;
203		cp += n;
204		ans[0] = '\0';
205		(void)strncpy(&ans[0], bp, sizeof(ans) - 1);
206		ans[sizeof(ans) - 1] = '\0';
207		GETSHORT(type, cp);
208		GETSHORT(class, cp);
209		cp += INT32SZ;		/* TTL */
210		GETSHORT(n, cp);
211		if (class == C_IN && type == T_PTR) {
212			n = dn_expand(answer->buf, eom, cp, bp, ep - bp);
213			if ((n < 0) || !res_hnok(bp)) {
214				cp += n;
215				return (-1);
216			}
217			cp += n;
218			*ap++ = bp;
219			n = strlen(bp) + 1;
220			bp += n;
221			ne->n_addrtype = (class == C_IN) ? AF_INET : AF_UNSPEC;
222			haveanswer++;
223		}
224	}
225	if (haveanswer) {
226		*ap = NULL;
227		switch (net_i) {
228		case BYADDR:
229			ne->n_name = *ne->n_aliases;
230			ne->n_net = 0L;
231			break;
232		case BYNAME:
233			in = *ne->n_aliases;
234			n = strlen(ans) + 1;
235			if (ep - bp < n) {
236				RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
237				errno = ENOBUFS;
238				return (-1);
239			}
240			strlcpy(bp, ans, ep - bp);
241			ne->n_name = bp;
242			if (strlen(in) + 1 > sizeof(aux)) {
243				RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
244				errno = ENOBUFS;
245				return (-1);
246			}
247			ipreverse(in, aux);
248			ne->n_net = inet_network(aux);
249			break;
250		}
251		ne->n_aliases++;
252		return (0);
253	}
254	RES_SET_H_ERRNO(statp, TRY_AGAIN);
255	return (-1);
256}
257
258int
259_dns_getnetbyaddr(void *rval, void *cb_data, va_list ap)
260{
261	uint32_t net;
262	int net_type;
263	char *buffer;
264	size_t buflen;
265	int *errnop, *h_errnop;
266	struct netent *nptr, ne;
267	struct netent_data *ned;
268	unsigned int netbr[4];
269	int nn, anslen, error;
270	querybuf *buf;
271	char qbuf[MAXDNAME];
272	uint32_t net2;
273	res_state statp;
274
275	net = va_arg(ap, uint32_t);
276	net_type = va_arg(ap, int);
277	nptr = va_arg(ap, struct netent *);
278	buffer = va_arg(ap, char *);
279	buflen = va_arg(ap, size_t);
280	errnop = va_arg(ap, int *);
281	h_errnop = va_arg(ap, int *);
282
283	statp = __res_state();
284	if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
285		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
286		*h_errnop = statp->res_h_errno;
287		return (NS_UNAVAIL);
288	}
289
290	if ((ned = __netent_data_init()) == NULL) {
291		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
292		*h_errnop = statp->res_h_errno;
293		return (NS_UNAVAIL);
294	}
295
296	*((struct netent **)rval) = NULL;
297
298	if (net_type != AF_INET) {
299		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
300		*h_errnop = statp->res_h_errno;
301		return (NS_UNAVAIL);
302	}
303
304	for (nn = 4, net2 = net; net2; net2 >>= 8)
305		netbr[--nn] = net2 & 0xff;
306	switch (nn) {
307	case 3: 	/* Class A */
308		sprintf(qbuf, "0.0.0.%u.in-addr.arpa", netbr[3]);
309		break;
310	case 2: 	/* Class B */
311		sprintf(qbuf, "0.0.%u.%u.in-addr.arpa", netbr[3], netbr[2]);
312		break;
313	case 1: 	/* Class C */
314		sprintf(qbuf, "0.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
315		    netbr[1]);
316		break;
317	case 0: 	/* Class D - E */
318		sprintf(qbuf, "%u.%u.%u.%u.in-addr.arpa", netbr[3], netbr[2],
319		    netbr[1], netbr[0]);
320		break;
321	}
322	if ((buf = malloc(sizeof(*buf))) == NULL) {
323		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
324		*h_errnop = statp->res_h_errno;
325		return (NS_NOTFOUND);
326	}
327	anslen = res_nquery(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
328	    sizeof(*buf));
329	if (anslen < 0) {
330		free(buf);
331#ifdef DEBUG
332		if (statp->options & RES_DEBUG)
333			printf("res_nsearch failed\n");
334#endif
335		*h_errnop = statp->res_h_errno;
336		return (NS_UNAVAIL);
337	} else if (anslen > sizeof(*buf)) {
338		free(buf);
339#ifdef DEBUG
340		if (statp->options & RES_DEBUG)
341			printf("res_nsearch static buffer too small\n");
342#endif
343		*h_errnop = statp->res_h_errno;
344		return (NS_UNAVAIL);
345	}
346	error = getnetanswer(buf, anslen, BYADDR, &ne, ned, statp);
347	free(buf);
348	if (error == 0) {
349		/* Strip trailing zeros */
350		while ((net & 0xff) == 0 && net != 0)
351			net >>= 8;
352		ne.n_net = net;
353		if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
354			*errnop = errno;
355			RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
356			*h_errnop = statp->res_h_errno;
357			return (NS_RETURN);
358		}
359		*((struct netent **)rval) = nptr;
360		return (NS_SUCCESS);
361	}
362	*h_errnop = statp->res_h_errno;
363	return (NS_NOTFOUND);
364}
365
366int
367_dns_getnetbyname(void *rval, void *cb_data, va_list ap)
368{
369	const char *net;
370	char *buffer;
371	size_t buflen;
372	int *errnop, *h_errnop;
373	struct netent *nptr, ne;
374	struct netent_data *ned;
375	int anslen, error;
376	querybuf *buf;
377	char qbuf[MAXDNAME];
378	res_state statp;
379
380	net = va_arg(ap, const char *);
381	nptr = va_arg(ap, struct netent *);
382	buffer = va_arg(ap, char *);
383	buflen = va_arg(ap, size_t);
384	errnop = va_arg(ap, int *);
385	h_errnop = va_arg(ap, int *);
386
387	statp = __res_state();
388	if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1) {
389		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
390		*h_errnop = statp->res_h_errno;
391		return (NS_UNAVAIL);
392	}
393	if ((ned = __netent_data_init()) == NULL) {
394		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
395		*h_errnop = statp->res_h_errno;
396		return (NS_UNAVAIL);
397	}
398	if ((buf = malloc(sizeof(*buf))) == NULL) {
399		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
400		*h_errnop = statp->res_h_errno;
401		return (NS_NOTFOUND);
402	}
403
404	*((struct netent **)rval) = NULL;
405
406	strncpy(qbuf, net, sizeof(qbuf) - 1);
407	qbuf[sizeof(qbuf) - 1] = '\0';
408	anslen = res_nsearch(statp, qbuf, C_IN, T_PTR, (u_char *)buf,
409	    sizeof(*buf));
410	if (anslen < 0) {
411		free(buf);
412#ifdef DEBUG
413		if (statp->options & RES_DEBUG)
414			printf("res_nsearch failed\n");
415#endif
416		return (NS_UNAVAIL);
417	} else if (anslen > sizeof(*buf)) {
418		free(buf);
419#ifdef DEBUG
420		if (statp->options & RES_DEBUG)
421			printf("res_search static buffer too small\n");
422#endif
423		return (NS_UNAVAIL);
424	}
425	error = getnetanswer(buf, anslen, BYNAME, &ne, ned, statp);
426	free(buf);
427	if (error != 0) {
428		*h_errnop = statp->res_h_errno;
429		return (NS_NOTFOUND);
430	}
431	if (__copy_netent(&ne, nptr, buffer, buflen) != 0) {
432		*errnop = errno;
433		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
434		*h_errnop = statp->res_h_errno;
435		return (NS_RETURN);
436	}
437	*((struct netent **)rval) = nptr;
438	return (NS_SUCCESS);
439}
440
441void
442_setnetdnsent(int stayopen)
443{
444	res_state statp;
445
446	statp = __res_state();
447	if ((statp->options & RES_INIT) == 0 && res_ninit(statp) == -1)
448		return;
449	if (stayopen)
450		statp->options |= RES_STAYOPEN | RES_USEVC;
451}
452
453void
454_endnetdnsent(void)
455{
456	res_state statp;
457
458	statp = __res_state();
459	statp->options &= ~(RES_STAYOPEN | RES_USEVC);
460	res_nclose(statp);
461}
462