1/*-
2 * SPDX-License-Identifier: ISC
3 *
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1995-1999 by Internet Software Consortium.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#if defined(LIBC_SCCS) && !defined(lint)
21static const char rcsid[] = "$Id: res_data.c,v 1.7 2008/12/11 09:59:00 marka Exp $";
22#endif /* LIBC_SCCS and not lint */
23#include <sys/cdefs.h>
24__FBSDID("$FreeBSD$");
25
26#include "port_before.h"
27
28#include <sys/param.h>
29#include <sys/socket.h>
30#include <sys/time.h>
31
32#include <netinet/in.h>
33#include <arpa/inet.h>
34#include <arpa/nameser.h>
35
36#include <ctype.h>
37#include <netdb.h>
38#include <resolv.h>
39#include <res_update.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <unistd.h>
44
45#include "port_after.h"
46
47const char *_res_opcodes[] = {
48	"QUERY",
49	"IQUERY",
50	"CQUERYM",
51	"CQUERYU",	/*%< experimental */
52	"NOTIFY",	/*%< experimental */
53	"UPDATE",
54	"6",
55	"7",
56	"8",
57	"9",
58	"10",
59	"11",
60	"12",
61	"13",
62	"ZONEINIT",
63	"ZONEREF",
64};
65
66#ifdef BIND_UPDATE
67const char *_res_sectioncodes[] = {
68	"ZONE",
69	"PREREQUISITES",
70	"UPDATE",
71	"ADDITIONAL",
72};
73#endif
74
75#ifndef __BIND_NOSTATIC
76
77/* Proto. */
78
79int  res_ourserver_p(const res_state, const struct sockaddr_in *);
80
81__noinline int
82res_init(void) {
83	extern int __res_vinit(res_state, int);
84	res_state statp = &_res;
85
86	/*
87	 * These three fields used to be statically initialized.  This made
88	 * it hard to use this code in a shared library.  It is necessary,
89	 * now that we're doing dynamic initialization here, that we preserve
90	 * the old semantics: if an application modifies one of these three
91	 * fields of _res before res_init() is called, res_init() will not
92	 * alter them.  Of course, if an application is setting them to
93	 * _zero_ before calling res_init(), hoping to override what used
94	 * to be the static default, we can't detect it and unexpected results
95	 * will follow.  Zero for any of these fields would make no sense,
96	 * so one can safely assume that the applications were already getting
97	 * unexpected results.
98	 *
99	 * _res.options is tricky since some apps were known to diddle the bits
100	 * before res_init() was first called. We can't replicate that semantic
101	 * with dynamic initialization (they may have turned bits off that are
102	 * set in RES_DEFAULT).  Our solution is to declare such applications
103	 * "broken".  They could fool us by setting RES_INIT but none do (yet).
104	 */
105	if (!statp->retrans)
106		statp->retrans = RES_TIMEOUT;
107	if (!statp->retry)
108		statp->retry = RES_DFLRETRY;
109	if (!(statp->options & RES_INIT))
110		statp->options = RES_DEFAULT;
111
112	return (__res_vinit(statp, 1));
113}
114
115void
116p_query(const u_char *msg) {
117	fp_query(msg, stdout);
118}
119
120void
121fp_query(const u_char *msg, FILE *file) {
122	fp_nquery(msg, PACKETSZ, file);
123}
124
125void
126fp_nquery(const u_char *msg, int len, FILE *file) {
127	res_state statp = &_res;
128	if ((statp->options & RES_INIT) == 0U && res_init() == -1)
129		return;
130
131	res_pquery(statp, msg, len, file);
132}
133
134int
135res_mkquery(int op,			/*!< opcode of query  */
136	    const char *dname,		/*!< domain name  */
137	    int class, int type,	/*!< class and type of query  */
138	    const u_char *data,		/*!< resource record data  */
139	    int datalen,		/*!< length of data  */
140	    const u_char *newrr_in,	/*!< new rr for modify or append  */
141	    u_char *buf,		/*!< buffer to put query  */
142	    int buflen)			/*!< size of buffer  */
143{
144	res_state statp = &_res;
145	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
146		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
147		return (-1);
148	}
149	return (res_nmkquery(statp, op, dname, class, type,
150			     data, datalen,
151			     newrr_in, buf, buflen));
152}
153
154int
155res_mkupdate(ns_updrec *rrecp_in, u_char *buf, int buflen) {
156	res_state statp = &_res;
157	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
158		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
159		return (-1);
160	}
161
162	return (res_nmkupdate(statp, rrecp_in, buf, buflen));
163}
164
165int
166res_query(const char *name,	/*!< domain name  */
167	  int class, int type,	/*!< class and type of query  */
168	  u_char *answer,	/*!< buffer to put answer  */
169	  int anslen)		/*!< size of answer buffer  */
170{
171	res_state statp = &_res;
172	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
173		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
174		return (-1);
175	}
176	return (res_nquery(statp, name, class, type, answer, anslen));
177}
178
179#ifndef _LIBC
180void
181res_send_setqhook(res_send_qhook hook) {
182	_res.qhook = hook;
183}
184
185void
186res_send_setrhook(res_send_rhook hook) {
187	_res.rhook = hook;
188}
189#endif
190
191int
192res_isourserver(const struct sockaddr_in *inp) {
193	return (res_ourserver_p(&_res, inp));
194}
195
196int
197res_send(const u_char *buf, int buflen, u_char *ans, int anssiz) {
198	res_state statp = &_res;
199	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
200		/* errno should have been set by res_init() in this case. */
201		return (-1);
202	}
203
204	return (res_nsend(statp, buf, buflen, ans, anssiz));
205}
206
207#ifndef _LIBC
208int
209res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key,
210	       u_char *ans, int anssiz)
211{
212	res_state statp = &_res;
213	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
214		/* errno should have been set by res_init() in this case. */
215		return (-1);
216	}
217
218	return (res_nsendsigned(statp, buf, buflen, key, ans, anssiz));
219}
220#endif
221
222void
223res_close(void) {
224	res_nclose(&_res);
225}
226
227int
228res_update(ns_updrec *rrecp_in) {
229	res_state statp = &_res;
230	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
231		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
232		return (-1);
233	}
234
235	return (res_nupdate(statp, rrecp_in, NULL));
236}
237
238int
239res_search(const char *name,	/*!< domain name  */
240	   int class, int type,	/*!< class and type of query  */
241	   u_char *answer,	/*!< buffer to put answer  */
242	   int anslen)		/*!< size of answer  */
243{
244	res_state statp = &_res;
245	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
246		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
247		return (-1);
248	}
249
250	return (res_nsearch(statp, name, class, type, answer, anslen));
251}
252
253int
254res_querydomain(const char *name,
255		const char *domain,
256		int class, int type,	/*!< class and type of query  */
257		u_char *answer,		/*!< buffer to put answer  */
258		int anslen)		/*!< size of answer  */
259{
260	res_state statp = &_res;
261	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
262		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
263		return (-1);
264	}
265
266	return (res_nquerydomain(statp, name, domain,
267				 class, type,
268				 answer, anslen));
269}
270
271u_int
272res_randomid(void) {
273	res_state statp = &_res;
274	if ((statp->options & RES_INIT) == 0U && res_init() == -1) {
275		RES_SET_H_ERRNO(statp, NETDB_INTERNAL);
276		return (-1);
277	}
278
279	return (res_nrandomid(statp));
280}
281
282int
283res_opt(int n0, u_char *buf, int buflen, int anslen)
284{
285	return (res_nopt(&_res, n0, buf, buflen, anslen));
286}
287
288const char *
289hostalias(const char *name) {
290	static char abuf[MAXDNAME];
291
292	return (res_hostalias(&_res, name, abuf, sizeof abuf));
293}
294
295#ifdef ultrix
296int
297local_hostname_length(const char *hostname) {
298	int len_host, len_domain;
299	res_state statp;
300
301	statp = &_res;
302	if (!*statp->defdname)
303		res_init();
304	len_host = strlen(hostname);
305	len_domain = strlen(statp->defdname);
306	if (len_host > len_domain &&
307	    !strcasecmp(hostname + len_host - len_domain, statp->defdname) &&
308	    hostname[len_host - len_domain - 1] == '.')
309		return (len_host - len_domain - 1);
310	return (0);
311}
312#endif /*ultrix*/
313
314/*
315 * Weak aliases for applications that use certain private entry points,
316 * and fail to include <resolv.h>.
317 */
318#undef res_init
319__weak_reference(__res_init, res_init);
320#undef p_query
321__weak_reference(__p_query, p_query);
322#undef res_mkquery
323__weak_reference(__res_mkquery, res_mkquery);
324#undef res_query
325__weak_reference(__res_query, res_query);
326#undef res_send
327__weak_reference(__res_send, res_send);
328#undef res_close
329__weak_reference(__res_close, _res_close);
330#undef res_search
331__weak_reference(__res_search, res_search);
332#undef res_querydomain
333__weak_reference(__res_querydomain, res_querydomain);
334
335#endif
336
337/*! \file */
338