1/*
2 * Copyright (c) 1995-1999 by Internet Software Consortium.
3 *
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
9 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
10 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
11 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
12 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
13 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
14 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
15 * SOFTWARE.
16 */
17
18#if defined(LIBC_SCCS) && !defined(lint)
19static const char rcsid[] = "$Id: res_data.c,v 1.1 2006/03/01 19:01:37 majka Exp $";
20#endif /* LIBC_SCCS and not lint */
21
22#include <sys/types.h>
23#include <sys/param.h>
24#include <sys/socket.h>
25#include <sys/time.h>
26
27#include <netinet/in.h>
28#include <arpa/inet.h>
29#include <arpa/nameser.h>
30
31#include <ctype.h>
32#include <netdb.h>
33#include <resolv.h>
34#include <res_update.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38#include <unistd.h>
39
40#include "res_private.h"
41
42static struct __res_state *_res_static;
43
44#ifdef USE__RES_9
45struct __res_9_state _res_9;
46#endif
47
48extern int __res_vinit(res_state, int);
49
50const char *__res_opcodes[] = {
51	"QUERY",
52	"IQUERY",
53	"CQUERYM",
54	"CQUERYU",	/* experimental */
55	"NOTIFY",	/* experimental */
56	"UPDATE",
57	"6",
58	"7",
59	"8",
60	"9",
61	"10",
62	"11",
63	"12",
64	"13",
65	"ZONEINIT",
66	"ZONEREF",
67};
68
69void
70__h_errno_set(struct __res_state *res, int err)
71{
72	h_errno = res->res_h_errno = err;
73}
74
75void
76res_client_close(res_state res)
77{
78	if (res == NULL) return;
79
80	if (res->_u._ext.ext != NULL) free(res->_u._ext.ext);
81	free(res);
82}
83
84res_state
85res_state_new()
86{
87	res_state x;
88
89	x = (res_state)calloc(1, sizeof(struct __res_state));
90	if (x == NULL) return NULL;
91
92	/*
93	 * We use _pad (normally unused) to hold a version number.
94	 * We use it provide limited compatibility between versions.
95	 */
96	x->_pad = 9;
97
98	x->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext));
99	if (x->_u._ext.ext == NULL)
100	{
101		free(x);
102		return NULL;
103	}
104
105	return x;
106}
107
108int
109res_init(void)
110{
111	extern int __res_vinit(res_state, int);
112	unsigned int save_retrans, save_retry, save_options, save_id;
113	struct __res_state_ext *save_ext;
114
115#ifdef USE__RES_9
116	_res_static = &_res_9;
117#else
118	_res_static = &_res;
119#endif
120
121	save_retrans = RES_TIMEOUT;
122	save_retry = RES_DFLRETRY;
123	save_options = RES_DEFAULT;
124	save_id = res_randomid();
125	save_ext = _res_static->_u._ext.ext;
126
127	if (_res_static->options & RES_INIT)
128	{
129		/* Caller wants to override default options */
130		save_options = _res_static->options;
131		if (_res_static->retrans != 0) save_retrans = _res_static->retrans;
132		if (_res_static->retry != 0) save_retry = _res_static->retry;
133		if (_res_static->id != 0) save_id = _res_static->id;
134	}
135
136	memset(_res_static, 0, sizeof(struct __res_state));
137	_res_static->_vcsock = -1;
138
139	_res_static->retrans = save_retrans;
140	_res_static->retry = save_retry;
141	_res_static->id = save_id;
142	_res_static->options = save_options;
143	_res_static->_u._ext.ext = save_ext;
144
145	_res_static->_pad = 9;
146
147	if (_res_static->_u._ext.ext == NULL) _res_static->_u._ext.ext = (struct __res_state_ext *)calloc(1, sizeof(struct __res_state_ext));
148
149	return (__res_vinit(_res_static, 1));
150}
151
152int
153res_query(const char *name, int class, int type, u_char *answer, int anslen)
154{
155#ifdef USE__RES_9
156	_res_static = &_res_9;
157#else
158	_res_static = &_res;
159#endif
160
161	if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
162	{
163		RES_SET_H_ERRNO(_res_static, NETDB_INTERNAL);
164		return -1;
165	}
166	return (res_nquery(_res_static, name, class, type, answer, anslen));
167}
168
169void
170fp_nquery(const u_char *msg, int len, FILE *file)
171{
172#ifdef USE__RES_9
173	_res_static = &_res_9;
174#else
175	_res_static = &_res;
176#endif
177
178	if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1)) return;
179
180	res_pquery(_res_static, msg, len, file);
181}
182
183void
184fp_query(const u_char *msg, FILE *file)
185{
186	fp_nquery(msg, NS_PACKETSZ, file);
187}
188
189void
190p_query(const u_char *msg)
191{
192	fp_query(msg, stdout);
193}
194
195const char *
196hostalias(const char *name)
197{
198	static char abuf[NS_MAXDNAME];
199
200#ifdef USE__RES_9
201	_res_static = &_res_9;
202#else
203	_res_static = &_res;
204#endif
205
206	return (res_hostalias(_res_static, name, abuf, sizeof abuf));
207}
208
209void
210res_close(void)
211{
212#ifdef USE__RES_9
213	_res_static = &_res_9;
214#else
215	_res_static = &_res;
216#endif
217
218	res_nclose(_res_static);
219}
220
221int
222res_isourserver(const struct sockaddr_in *inp)
223{
224#ifdef USE__RES_9
225	_res_static = &_res_9;
226#else
227	_res_static = &_res;
228#endif
229
230	return (res_ourserver_p(_res_static, (const struct sockaddr *)inp));
231}
232
233int
234res_nisourserver(const res_state res, const struct sockaddr_in *inp)
235{
236	return (res_ourserver_p(res, (const struct sockaddr *)inp));
237}
238
239int
240res_mkquery(int op, const char *dname, int class, int type, const u_char *data, int datalen, const u_char *newrr_in, u_char *buf, int buflen)
241{
242#ifdef USE__RES_9
243	_res_static = &_res_9;
244#else
245	_res_static = &_res;
246#endif
247
248	if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
249	{
250		RES_SET_H_ERRNO(_res_static, NETDB_INTERNAL);
251		return -1;
252	}
253
254	return res_nmkquery(_res_static, op, dname, class, type, data, datalen, newrr_in, buf, buflen);
255}
256
257int
258res_querydomain(const char *name, const char *domain, int class, int type, u_char *answer, int anslen)
259{
260#ifdef USE__RES_9
261	_res_static = &_res_9;
262#else
263	_res_static = &_res;
264#endif
265
266	if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
267	{
268		RES_SET_H_ERRNO(_res_static, NETDB_INTERNAL);
269		return -1;
270	}
271
272	return res_nquerydomain(_res_static, name, domain, class, type, answer, anslen);
273}
274
275int
276res_search(const char *name, int class, int type, u_char *answer, int anslen)
277{
278#ifdef USE__RES_9
279	_res_static = &_res_9;
280#else
281	_res_static = &_res;
282#endif
283
284	if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
285	{
286		RES_SET_H_ERRNO(_res_static, NETDB_INTERNAL);
287		return -1;
288	}
289
290	return res_nsearch(_res_static, name, class, type, answer, anslen);
291}
292
293int
294res_send(const u_char *buf, int buflen, u_char *ans, int anssiz)
295{
296#ifdef USE__RES_9
297	_res_static = &_res_9;
298#else
299	_res_static = &_res;
300#endif
301
302	if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
303	{
304		/* errno should have been set by res_init() in this case. */
305		return -1;
306	}
307
308	return res_nsend(_res_static, buf, buflen, ans, anssiz);
309}
310
311int
312res_sendsigned(const u_char *buf, int buflen, ns_tsig_key *key, u_char *ans, int anssiz)
313{
314#ifdef USE__RES_9
315	_res_static = &_res_9;
316#else
317	_res_static = &_res;
318#endif
319
320	if (((_res_static->options & RES_INIT) == 0) && (res_init() == -1))
321	{
322		/* errno should have been set by res_init() in this case. */
323		return -1;
324	}
325
326	return res_nsendsigned(_res_static, buf, buflen, key, ans, anssiz);
327}
328