1/*
2 * Portions Copyright (C) 2004, 2005, 2008  Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 1996, 1997, 1988, 1999, 2001, 2003  Internet Software Consortium.
4 *
5 * Permission to use, copy, modify, and/or 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 WITH
10 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15 * PERFORMANCE OF THIS SOFTWARE.
16 */
17
18/*
19 * Copyright (c) 1985, 1993
20 *    The Regents of the University of California.  All rights reserved.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the above copyright
26 *    notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 *    notice, this list of conditions and the following disclaimer in the
29 *    documentation and/or other materials provided with the distribution.
30 * 4. Neither the name of the University nor the names of its contributors
31 *    may be used to endorse or promote products derived from this software
32 *    without specific prior written permission.
33 *
34 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
35 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
36 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
37 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
38 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
39 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
40 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
41 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
42 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
43 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
44 * SUCH DAMAGE.
45 */
46
47/*
48 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
49 *
50 * Permission to use, copy, modify, and distribute this software for any
51 * purpose with or without fee is hereby granted, provided that the above
52 * copyright notice and this permission notice appear in all copies, and that
53 * the name of Digital Equipment Corporation not be used in advertising or
54 * publicity pertaining to distribution of the document or software without
55 * specific, written prior permission.
56 *
57 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
58 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL EQUIPMENT
60 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
61 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
62 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
63 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
64 * SOFTWARE.
65 */
66
67#if defined(LIBC_SCCS) && !defined(lint)
68static const char sccsid[] = "@(#)res_mkquery.c	8.1 (Berkeley) 6/4/93";
69static const char rcsid[] = "$Id: res_mkquery.c,v 1.10 2008/12/11 09:59:00 marka Exp $";
70#endif /* LIBC_SCCS and not lint */
71#include <sys/cdefs.h>
72__FBSDID("$FreeBSD$");
73
74#include "port_before.h"
75#include <sys/param.h>
76#include <netinet/in.h>
77#include <arpa/nameser.h>
78#include <netdb.h>
79#include <resolv.h>
80#include <stdio.h>
81#include <string.h>
82#include "port_after.h"
83
84/* Options.  Leave them on. */
85#ifndef	DEBUG
86#define	DEBUG
87#endif
88
89extern const char *_res_opcodes[];
90
91/*%
92 * Form all types of queries.
93 * Returns the size of the result or -1.
94 */
95int
96res_nmkquery(res_state statp,
97	     int op,			/*!< opcode of query  */
98	     const char *dname,		/*!< domain name  */
99	     int class, int type,	/*!< class and type of query  */
100	     const u_char *data,	/*!< resource record data  */
101	     int datalen,		/*!< length of data  */
102	     const u_char *newrr_in,	/*!< new rr for modify or append  */
103	     u_char *buf,		/*!< buffer to put query  */
104	     int buflen)		/*!< size of buffer  */
105{
106	HEADER *hp;
107	u_char *cp, *ep;
108	int n;
109	u_char *dnptrs[20], **dpp, **lastdnptr;
110
111	UNUSED(newrr_in);
112
113#ifdef DEBUG
114	if (statp->options & RES_DEBUG)
115		printf(";; res_nmkquery(%s, %s, %s, %s)\n",
116		       _res_opcodes[op], dname, p_class(class), p_type(type));
117#endif
118	/*
119	 * Initialize header fields.
120	 */
121	if ((buf == NULL) || (buflen < HFIXEDSZ))
122		return (-1);
123	memset(buf, 0, HFIXEDSZ);
124	hp = (HEADER *) buf;
125	statp->id = res_nrandomid(statp);
126	hp->id = htons(statp->id);
127	hp->opcode = op;
128	hp->rd = (statp->options & RES_RECURSE) != 0U;
129	hp->rcode = NOERROR;
130	cp = buf + HFIXEDSZ;
131	ep = buf + buflen;
132	dpp = dnptrs;
133	*dpp++ = buf;
134	*dpp++ = NULL;
135	lastdnptr = dnptrs + nitems(dnptrs);
136	/*
137	 * perform opcode specific processing
138	 */
139	switch (op) {
140	case QUERY:	/*FALLTHROUGH*/
141	case NS_NOTIFY_OP:
142		if (ep - cp < QFIXEDSZ)
143			return (-1);
144		if ((n = dn_comp(dname, cp, ep - cp - QFIXEDSZ, dnptrs,
145		    lastdnptr)) < 0)
146			return (-1);
147		cp += n;
148		ns_put16(type, cp);
149		cp += INT16SZ;
150		ns_put16(class, cp);
151		cp += INT16SZ;
152		hp->qdcount = htons(1);
153		if (op == QUERY || data == NULL)
154			break;
155		/*
156		 * Make an additional record for completion domain.
157		 */
158		if ((ep - cp) < RRFIXEDSZ)
159			return (-1);
160		n = dn_comp((const char *)data, cp, ep - cp - RRFIXEDSZ,
161			    dnptrs, lastdnptr);
162		if (n < 0)
163			return (-1);
164		cp += n;
165		ns_put16(T_NULL, cp);
166		cp += INT16SZ;
167		ns_put16(class, cp);
168		cp += INT16SZ;
169		ns_put32(0, cp);
170		cp += INT32SZ;
171		ns_put16(0, cp);
172		cp += INT16SZ;
173		hp->arcount = htons(1);
174		break;
175
176	case IQUERY:
177		/*
178		 * Initialize answer section
179		 */
180		if (ep - cp < 1 + RRFIXEDSZ + datalen)
181			return (-1);
182		*cp++ = '\0';	/*%< no domain name */
183		ns_put16(type, cp);
184		cp += INT16SZ;
185		ns_put16(class, cp);
186		cp += INT16SZ;
187		ns_put32(0, cp);
188		cp += INT32SZ;
189		ns_put16(datalen, cp);
190		cp += INT16SZ;
191		if (datalen) {
192			memcpy(cp, data, datalen);
193			cp += datalen;
194		}
195		hp->ancount = htons(1);
196		break;
197
198	default:
199		return (-1);
200	}
201	return (cp - buf);
202}
203
204#ifdef RES_USE_EDNS0
205/* attach OPT pseudo-RR, as documented in RFC2671 (EDNS0). */
206
207int
208res_nopt(res_state statp,
209	 int n0,		/*%< current offset in buffer */
210	 u_char *buf,		/*%< buffer to put query */
211	 int buflen,		/*%< size of buffer */
212	 int anslen)		/*%< UDP answer buffer size */
213{
214	HEADER *hp;
215	u_char *cp, *ep;
216	u_int16_t flags = 0;
217
218#ifdef DEBUG
219	if ((statp->options & RES_DEBUG) != 0U)
220		printf(";; res_nopt()\n");
221#endif
222
223	hp = (HEADER *) buf;
224	cp = buf + n0;
225	ep = buf + buflen;
226
227	if ((ep - cp) < 1 + RRFIXEDSZ)
228		return (-1);
229
230	*cp++ = 0;				/*%< "." */
231	ns_put16(ns_t_opt, cp);			/*%< TYPE */
232	cp += INT16SZ;
233	if (anslen > 0xffff)
234		anslen = 0xffff;		/* limit to 16bit value */
235	ns_put16(anslen & 0xffff, cp);		/*%< CLASS = UDP payload size */
236	cp += INT16SZ;
237	*cp++ = NOERROR;			/*%< extended RCODE */
238	*cp++ = 0;				/*%< EDNS version */
239
240	if (statp->options & RES_USE_DNSSEC) {
241#ifdef DEBUG
242		if (statp->options & RES_DEBUG)
243			printf(";; res_opt()... ENDS0 DNSSEC\n");
244#endif
245		flags |= NS_OPT_DNSSEC_OK;
246	}
247	ns_put16(flags, cp);
248	cp += INT16SZ;
249
250	ns_put16(0U, cp);			/*%< RDLEN */
251	cp += INT16SZ;
252
253	hp->arcount = htons(ntohs(hp->arcount) + 1);
254
255	return (cp - buf);
256}
257
258/*
259 * Construct variable data (RDATA) block for OPT psuedo-RR, append it
260 * to the buffer, then update the RDLEN field (previously set to zero by
261 * res_nopt()) with the new RDATA length.
262 */
263int
264res_nopt_rdata(res_state statp,
265	  int n0,	 	/*%< current offset in buffer */
266	  u_char *buf,	 	/*%< buffer to put query */
267	  int buflen,		/*%< size of buffer */
268	  u_char *rdata,	/*%< ptr to start of opt rdata */
269	  u_short code,		/*%< OPTION-CODE */
270	  u_short len,		/*%< OPTION-LENGTH */
271	  u_char *data)		/*%< OPTION_DATA */
272{
273	register u_char *cp, *ep;
274
275#ifdef DEBUG
276	if ((statp->options & RES_DEBUG) != 0U)
277		printf(";; res_nopt_rdata()\n");
278#endif
279
280	cp = buf + n0;
281	ep = buf + buflen;
282
283	if ((ep - cp) < (4 + len))
284		return (-1);
285
286	if (rdata < (buf + 2) || rdata >= ep)
287		return (-1);
288
289	ns_put16(code, cp);
290	cp += INT16SZ;
291
292	ns_put16(len, cp);
293	cp += INT16SZ;
294
295	memcpy(cp, data, len);
296	cp += len;
297
298	len = cp - rdata;
299	ns_put16(len, rdata - 2);	/* Update RDLEN field */
300
301	return (cp - buf);
302}
303#endif
304
305/*! \file */
306