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