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