xref: /illumos-gate/usr/src/lib/libresolv2/common/resolv/res_mkquery.c (revision aedf2b3bb56b025fcaf87b49ec6c8aeea07f16d7)
1 /*
2  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 
7 /*
8  * Portions Copyright (C) 2004, 2005, 2008  Internet Systems Consortium, Inc. ("ISC")
9  * Portions Copyright (C) 1996, 1997, 1988, 1999, 2001, 2003  Internet Software Consortium.
10  *
11  * Permission to use, copy, modify, and/or distribute this software for any
12  * purpose with or without fee is hereby granted, provided that the above
13  * copyright notice and this permission notice appear in all copies.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
16  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
17  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
18  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
19  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
20  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
21  * PERFORMANCE OF THIS SOFTWARE.
22  */
23 
24 /*
25  * Copyright (c) 1985, 1993
26  *    The Regents of the University of California.  All rights reserved.
27  *
28  * Redistribution and use in source and binary forms, with or without
29  * modification, are permitted provided that the following conditions
30  * are met:
31  * 1. Redistributions of source code must retain the above copyright
32  *    notice, this list of conditions and the following disclaimer.
33  * 2. Redistributions in binary form must reproduce the above copyright
34  *    notice, this list of conditions and the following disclaimer in the
35  *    documentation and/or other materials provided with the distribution.
36  * 3. All advertising materials mentioning features or use of this software
37  *    must display the following acknowledgement:
38  * 	This product includes software developed by the University of
39  * 	California, Berkeley and its contributors.
40  * 4. Neither the name of the University nor the names of its contributors
41  *    may be used to endorse or promote products derived from this software
42  *    without specific prior written permission.
43  *
44  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
45  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
48  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54  * SUCH DAMAGE.
55  */
56 
57 /*
58  * Portions Copyright (c) 1993 by Digital Equipment Corporation.
59  *
60  * Permission to use, copy, modify, and distribute this software for any
61  * purpose with or without fee is hereby granted, provided that the above
62  * copyright notice and this permission notice appear in all copies, and that
63  * the name of Digital Equipment Corporation not be used in advertising or
64  * publicity pertaining to distribution of the document or software without
65  * specific, written prior permission.
66  *
67  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
68  * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
69  * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
70  * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
71  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
72  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
73  * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
74  * SOFTWARE.
75  */
76 
77 #if defined(LIBC_SCCS) && !defined(lint)
78 static const char sccsid[] = "@(#)res_mkquery.c	8.1 (Berkeley) 6/4/93";
79 static const char rcsid[] = "$Id: res_mkquery.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
80 #endif /* LIBC_SCCS and not lint */
81 
82 #include "port_before.h"
83 #include <sys/types.h>
84 #include <sys/param.h>
85 #include <netinet/in.h>
86 #include <arpa/nameser.h>
87 
88 #ifdef SUNW_CONFCHECK
89 #include <sys/socket.h>
90 #include <errno.h>
91 #include <sys/stat.h>
92 #endif /* SUNW_CONFCHECK */
93 
94 
95 #include <netdb.h>
96 #include <resolv.h>
97 #include <stdio.h>
98 #include <string.h>
99 #include "port_after.h"
100 
101 /* Options.  Leave them on. */
102 #define DEBUG
103 
104 extern const char *_res_opcodes[];
105 
106 #ifdef SUNW_CONFCHECK
107 static int      _confcheck(res_state statp);
108 #endif /* SUNW_CONFCHECK */
109 
110 
111 /*%
112  * Form all types of queries.
113  * Returns the size of the result or -1.
114  */
115 int
116 res_nmkquery(res_state statp,
117 	     int op,			/*!< opcode of query  */
118 	     const char *dname,		/*!< domain name  */
119 	     int class, int type,	/*!< class and type of query  */
120 	     const u_char *data,	/*!< resource record data  */
121 	     int datalen,		/*!< length of data  */
122 	     const u_char *newrr_in,	/*!< new rr for modify or append  */
123 	     u_char *buf,		/*!< buffer to put query  */
124 	     int buflen)		/*!< size of buffer  */
125 {
126 	register HEADER *hp;
127 	register u_char *cp, *ep;
128 	register int n;
129 	u_char *dnptrs[20], **dpp, **lastdnptr;
130 
131 	UNUSED(newrr_in);
132 
133 #ifdef DEBUG
134 	if (statp->options & RES_DEBUG)
135 		printf(";; res_nmkquery(%s, %s, %s, %s)\n",
136 		       _res_opcodes[op], dname, p_class(class), p_type(type));
137 #endif
138 
139 #ifdef SUNW_CONFCHECK
140         /*
141          * 1247019, 1265838, and 4034368: Check to see if we can
142          * bailout quickly.
143          */
144         if (_confcheck(statp) == -1) {
145                 RES_SET_H_ERRNO(statp, NO_RECOVERY);
146                 return(-1);
147         }
148 #endif /* SUNW_CONFCHECK */
149 
150 	/*
151 	 * Initialize header fields.
152 	 */
153 	if ((buf == NULL) || (buflen < HFIXEDSZ))
154 		return (-1);
155 	memset(buf, 0, HFIXEDSZ);
156 	hp = (HEADER *) buf;
157 	statp->id = res_nrandomid(statp);
158 	hp->id = htons(statp->id);
159 	hp->opcode = op;
160 	hp->rd = (statp->options & RES_RECURSE) != 0U;
161 	hp->rcode = NOERROR;
162 	cp = buf + HFIXEDSZ;
163 	ep = buf + buflen;
164 	dpp = dnptrs;
165 	*dpp++ = buf;
166 	*dpp++ = NULL;
167 	lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
168 	/*
169 	 * perform opcode specific processing
170 	 */
171 	switch (op) {
172 	case QUERY:	/*FALLTHROUGH*/
173 	case NS_NOTIFY_OP:
174 		if (ep - cp < QFIXEDSZ)
175 			return (-1);
176 		if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs,
177 		    lastdnptr)) < 0)
178 			return (-1);
179 		cp += n;
180 		ns_put16(type, cp);
181 		cp += INT16SZ;
182 		ns_put16(class, cp);
183 		cp += INT16SZ;
184 		hp->qdcount = htons(1);
185 		if (op == QUERY || data == NULL)
186 			break;
187 		/*
188 		 * Make an additional record for completion domain.
189 		 */
190 		if ((ep - cp) < RRFIXEDSZ)
191 			return (-1);
192 		n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
193 			    dnptrs, lastdnptr);
194 		if (n < 0)
195 			return (-1);
196 		cp += n;
197 		ns_put16(T_NULL, cp);
198 		cp += INT16SZ;
199 		ns_put16(class, cp);
200 		cp += INT16SZ;
201 		ns_put32(0, cp);
202 		cp += INT32SZ;
203 		ns_put16(0, cp);
204 		cp += INT16SZ;
205 		hp->arcount = htons(1);
206 		break;
207 
208 	case IQUERY:
209 		/*
210 		 * Initialize answer section
211 		 */
212 		if (ep - cp < 1 + RRFIXEDSZ + datalen)
213 			return (-1);
214 		*cp++ = '\0';	/*%< no domain name */
215 		ns_put16(type, cp);
216 		cp += INT16SZ;
217 		ns_put16(class, cp);
218 		cp += INT16SZ;
219 		ns_put32(0, cp);
220 		cp += INT32SZ;
221 		ns_put16(datalen, cp);
222 		cp += INT16SZ;
223 		if (datalen) {
224 			memcpy(cp, data, datalen);
225 			cp += datalen;
226 		}
227 		hp->ancount = htons(1);
228 		break;
229 
230 	default:
231 		return (-1);
232 	}
233 	return (cp - buf);
234 }
235 
236 #ifdef RES_USE_EDNS0
237 /* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
238 
239 int
240 res_nopt(res_state statp,
241 	 int n0,		/*%< current offset in buffer */
242 	 u_char *buf,		/*%< buffer to put query */
243 	 int buflen,		/*%< size of buffer */
244 	 int anslen)		/*%< UDP answer buffer size */
245 {
246 	register HEADER *hp;
247 	register u_char *cp, *ep;
248 	u_int16_t flags = 0;
249 
250 #ifdef DEBUG
251 	if ((statp->options & RES_DEBUG) != 0U)
252 		printf(";; res_nopt()\n");
253 #endif
254 
255 	hp = (HEADER *) buf;
256 	cp = buf + n0;
257 	ep = buf + buflen;
258 
259 	if ((ep - cp) < 1 + RRFIXEDSZ)
260 		return (-1);
261 
262 	*cp++ = 0;				/*%< "." */
263 	ns_put16(ns_t_opt, cp);			/*%< TYPE */
264 	cp += INT16SZ;
265 	ns_put16(anslen & 0xffff, cp);		/*%< CLASS = UDP payload size */
266 	cp += INT16SZ;
267 	*cp++ = NOERROR;			/*%< extended RCODE */
268 	*cp++ = 0;				/*%< EDNS version */
269 
270 	if (statp->options & RES_USE_DNSSEC) {
271 #ifdef DEBUG
272 		if (statp->options & RES_DEBUG)
273 			printf(";; res_opt()... ENDS0 DNSSEC\n");
274 #endif
275 		flags |= NS_OPT_DNSSEC_OK;
276 	}
277 	ns_put16(flags, cp);
278 	cp += INT16SZ;
279 
280 	ns_put16(0U, cp);			/*%< RDLEN */
281 	cp += INT16SZ;
282 
283 	hp->arcount = htons(ntohs(hp->arcount) + 1);
284 
285 	return (cp - buf);
286 }
287 
288 /*
289  * Construct variable data (RDATA) block for OPT psuedo-RR, append it
290  * to the buffer, then update the RDLEN field (previously set to zero by
291  * res_nopt()) with the new RDATA length.
292  */
293 int
294 res_nopt_rdata(res_state statp,
295 	  int n0,	 	/*%< current offset in buffer */
296 	  u_char *buf,	 	/*%< buffer to put query */
297 	  int buflen,		/*%< size of buffer */
298 	  u_char *rdata,	/*%< ptr to start of opt rdata */
299 	  u_short code,		/*%< OPTION-CODE */
300 	  u_short len,		/*%< OPTION-LENGTH */
301 	  u_char *data)		/*%< OPTION_DATA */
302 {
303 	register u_char *cp, *ep;
304 
305 #ifdef DEBUG
306 	if ((statp->options & RES_DEBUG) != 0U)
307 		printf(";; res_nopt_rdata()\n");
308 #endif
309 
310 	cp = buf + n0;
311 	ep = buf + buflen;
312 
313 	if ((ep - cp) < (4 + len))
314 		return (-1);
315 
316 	if (rdata < (buf + 2) || rdata >= ep)
317 		return (-1);
318 
319 	ns_put16(code, cp);
320 	cp += INT16SZ;
321 
322 	ns_put16(len, cp);
323 	cp += INT16SZ;
324 
325 	memcpy(cp, data, len);
326 	cp += len;
327 
328 	len = cp - rdata;
329 	ns_put16(len, rdata - 2);	/* Update RDLEN field */
330 
331 	return (cp - buf);
332 }
333 #endif
334 
335 #ifdef SUNW_CONFCHECK
336 
337 /*
338  * Time out quickly if there is no /etc/resolv.conf and a TCP connection
339  * to the local DNS server fails.
340  */
341 static int _confcheck(res_state statp)
342 {
343         int ns;
344         struct stat rc_stat;
345         struct sockaddr_in ns_sin;
346 
347         /* First, we check to see if /etc/resolv.conf exists.
348          * If it doesn't, then it is likely that the localhost is
349          * the nameserver.
350          */
351         if (stat(_PATH_RESCONF, &rc_stat) == -1 && errno == ENOENT) {
352 
353                 /* Next, we check to see if _res.nsaddr is set to loopback.
354                  * If it isn't, it has been altered by the application
355                  * explicitly and we then want to bail with success.
356                  */
357                 if (statp->nsaddr.sin_addr.S_un.S_addr ==
358 				htonl(INADDR_LOOPBACK)) {
359 
360                         /* Lastly, we try to connect to the TCP port of the
361                          * nameserver.  If this fails, then we know that
362                          * DNS is misconfigured and we can quickly exit.
363                          */
364                         ns = socket(AF_INET, SOCK_STREAM, 0);
365                         IN_SET_LOOPBACK_ADDR(&ns_sin);
366                         ns_sin.sin_port = htons(NAMESERVER_PORT);
367                         if (connect(ns, (struct sockaddr *) &ns_sin,
368                                     sizeof ns_sin) == -1) {
369                                 close(ns);
370                                 return(-1);
371                         }
372                         else {
373                                 close(ns);
374 
375                                 return(0);
376                         }
377                 }
378 
379                 return(0);
380         }
381 
382         return (0);
383 }
384 #endif /* SUNW_CONFCHECK */
385 
386 /*! \file */
387