xref: /freebsd/lib/libc/resolv/res_data.c (revision 22cf89c938886d14f5796fc49f9f020c23ea8eaf)
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)
21 static 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 #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 
45 const 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
65 const char *_res_sectioncodes[] = {
66 	"ZONE",
67 	"PREREQUISITES",
68 	"UPDATE",
69 	"ADDITIONAL",
70 };
71 #endif
72 
73 #ifndef __BIND_NOSTATIC
74 
75 /* Proto. */
76 
77 int  res_ourserver_p(const res_state, const struct sockaddr_in *);
78 
79 __noinline int
80 res_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 
113 void
114 p_query(const u_char *msg) {
115 	fp_query(msg, stdout);
116 }
117 
118 void
119 fp_query(const u_char *msg, FILE *file) {
120 	fp_nquery(msg, PACKETSZ, file);
121 }
122 
123 void
124 fp_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 
132 int
133 res_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 
152 int
153 res_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 
163 int
164 res_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
178 void
179 res_send_setqhook(res_send_qhook hook) {
180 	_res.qhook = hook;
181 }
182 
183 void
184 res_send_setrhook(res_send_rhook hook) {
185 	_res.rhook = hook;
186 }
187 #endif
188 
189 int
190 res_isourserver(const struct sockaddr_in *inp) {
191 	return (res_ourserver_p(&_res, inp));
192 }
193 
194 int
195 res_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
206 int
207 res_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 
220 void
221 res_close(void) {
222 	res_nclose(&_res);
223 }
224 
225 int
226 res_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 
236 int
237 res_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 
251 int
252 res_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 
269 u_int
270 res_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 
280 int
281 res_opt(int n0, u_char *buf, int buflen, int anslen)
282 {
283 	return (res_nopt(&_res, n0, buf, buflen, anslen));
284 }
285 
286 const char *
287 hostalias(const char *name) {
288 	static char abuf[MAXDNAME];
289 
290 	return (res_hostalias(&_res, name, abuf, sizeof abuf));
291 }
292 
293 #ifdef ultrix
294 int
295 local_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