1/* Creation of DNS query packets.
2 Copyright (C) 1995-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
9
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
18
19/*
20 * Copyright (c) 1985, 1993
21 * The Regents of the University of California. All rights reserved.
22 *
23 * Redistribution and use in source and binary forms, with or without
24 * modification, are permitted provided that the following conditions
25 * are met:
26 * 1. Redistributions of source code must retain the above copyright
27 * notice, this list of conditions and the following disclaimer.
28 * 2. Redistributions in binary form must reproduce the above copyright
29 * notice, this list of conditions and the following disclaimer in the
30 * documentation and/or other materials provided with the distribution.
31 * 4. Neither the name of the University nor the names of its contributors
32 * may be used to endorse or promote products derived from this software
33 * without specific prior written permission.
34 *
35 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
36 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
37 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
38 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
39 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
40 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
41 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
42 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
43 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
44 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 * SUCH DAMAGE.
46 */
47
48/*
49 * Portions Copyright (c) 1993 by Digital Equipment Corporation.
50 *
51 * Permission to use, copy, modify, and distribute this software for any
52 * purpose with or without fee is hereby granted, provided that the above
53 * copyright notice and this permission notice appear in all copies, and that
54 * the name of Digital Equipment Corporation not be used in advertising or
55 * publicity pertaining to distribution of the document or software without
56 * specific, written prior permission.
57 *
58 * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS ALL
59 * WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
60 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL DIGITAL EQUIPMENT
61 * CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
62 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
63 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
64 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
65 * SOFTWARE.
66 */
67
68/*
69 * Portions Copyright (c) 1996-1999 by Internet Software Consortium.
70 *
71 * Permission to use, copy, modify, and distribute this software for any
72 * purpose with or without fee is hereby granted, provided that the above
73 * copyright notice and this permission notice appear in all copies.
74 *
75 * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
76 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
77 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
78 * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
79 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
80 * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
81 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
82 * SOFTWARE.
83 */
84
85#include <sys/types.h>
86#include <sys/param.h>
87#include <netinet/in.h>
88#include <arpa/nameser.h>
89#include <netdb.h>
90#include <resolv/resolv-internal.h>
91#include <resolv/resolv_context.h>
92#include <string.h>
93#include <sys/time.h>
94#include <shlib-compat.h>
95
96#include <hp-timing.h>
97#include <stdint.h>
98#if HP_TIMING_AVAIL
99# define RANDOM_BITS(Var) { uint64_t v64; HP_TIMING_NOW (v64); Var = v64; }
100#endif
101
102int
103__res_context_mkquery (struct resolv_context *ctx, int op, const char *dname,
104 int class, int type, const unsigned char *data,
105 unsigned char *buf, int buflen)
106{
107 HEADER *hp;
108 unsigned char *cp;
109 int n;
110 unsigned char *dnptrs[20], **dpp, **lastdnptr;
111
112 if (class < 0 || class > 65535 || type < 0 || type > 65535)
113 return -1;
114
115 /* Initialize header fields. */
116 if ((buf == NULL) || (buflen < HFIXEDSZ))
117 return -1;
118 memset (buf, 0, HFIXEDSZ);
119 hp = (HEADER *) buf;
120 /* We randomize the IDs every time. The old code just incremented
121 by one after the initial randomization which still predictable if
122 the application does multiple requests. */
123 int randombits;
124#ifdef RANDOM_BITS
125 RANDOM_BITS (randombits);
126#else
127 struct timeval tv;
128 __gettimeofday (&tv, NULL);
129 randombits = (tv.tv_sec << 8) ^ tv.tv_usec;
130#endif
131
132 hp->id = randombits;
133 hp->opcode = op;
134 hp->rd = (ctx->resp->options & RES_RECURSE) != 0;
135 hp->rcode = NOERROR;
136 cp = buf + HFIXEDSZ;
137 buflen -= HFIXEDSZ;
138 dpp = dnptrs;
139 *dpp++ = buf;
140 *dpp++ = NULL;
141 lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
142
143 /* Perform opcode specific processing. */
144 switch (op)
145 {
146 case NS_NOTIFY_OP:
147 if ((buflen -= QFIXEDSZ + (data == NULL ? 0 : RRFIXEDSZ)) < 0)
148 return -1;
149 goto compose;
150
151 case QUERY:
152 if ((buflen -= QFIXEDSZ) < 0)
153 return -1;
154 compose:
155 n = ns_name_compress (dname, cp, buflen,
156 (const unsigned char **) dnptrs,
157 (const unsigned char **) lastdnptr);
158 if (n < 0)
159 return -1;
160 cp += n;
161 buflen -= n;
162 NS_PUT16 (type, cp);
163 NS_PUT16 (class, cp);
164 hp->qdcount = htons (1);
165 if (op == QUERY || data == NULL)
166 break;
167
168 /* Make an additional record for completion domain. */
169 n = ns_name_compress ((char *)data, cp, buflen,
170 (const unsigned char **) dnptrs,
171 (const unsigned char **) lastdnptr);
172 if (__glibc_unlikely (n < 0))
173 return -1;
174 cp += n;
175 buflen -= n;
176 NS_PUT16 (T_NULL, cp);
177 NS_PUT16 (class, cp);
178 NS_PUT32 (0, cp);
179 NS_PUT16 (0, cp);
180 hp->arcount = htons (1);
181 break;
182
183 default:
184 return -1;
185 }
186 return cp - buf;
187}
188
189/* Common part of res_nmkquery and res_mkquery. */
190static int
191context_mkquery_common (struct resolv_context *ctx,
192 int op, const char *dname, int class, int type,
193 const unsigned char *data,
194 unsigned char *buf, int buflen)
195{
196 if (ctx == NULL)
197 return -1;
198 int result = __res_context_mkquery
199 (ctx, op, dname, class, type, data, buf, buflen);
200 if (result >= 2)
201 memcpy (&ctx->resp->id, buf, 2);
202 __resolv_context_put (ctx);
203 return result;
204}
205
206/* Form all types of queries. Returns the size of the result or -1 on
207 error.
208
209 STATP points to an initialized resolver state. OP is the opcode of
210 the query. DNAME is the domain. CLASS and TYPE are the DNS query
211 class and type. DATA can be NULL; otherwise, it is a pointer to a
212 domain name which is included in the generated packet (if op ==
213 NS_NOTIFY_OP). BUF must point to the out buffer of BUFLEN bytes.
214
215 DATALEN and NEWRR_IN are currently ignored. */
216int
217res_nmkquery (res_state statp, int op, const char *dname,
218 int class, int type,
219 const unsigned char *data, int datalen,
220 const unsigned char *newrr_in,
221 unsigned char *buf, int buflen)
222{
223 return context_mkquery_common
224 (__resolv_context_get_override (statp),
225 op, dname, class, type, data, buf, buflen);
226}
227
228int
229res_mkquery (int op, const char *dname, int class, int type,
230 const unsigned char *data, int datalen,
231 const unsigned char *newrr_in,
232 unsigned char *buf, int buflen)
233{
234 return context_mkquery_common
235 (__resolv_context_get_preinit (),
236 op, dname, class, type, data, buf, buflen);
237}
238
239/* Create an OPT resource record. Return the length of the final
240 packet, or -1 on error.
241
242 STATP must be an initialized resolver state. N0 is the current
243 number of bytes of the packet (already written to BUF by the
244 aller). BUF is the packet being constructed. The array it
245 pointers to must be BUFLEN bytes long. ANSLEN is the advertised
246 EDNS buffer size (to be included in the OPT resource record). */
247int
248__res_nopt (struct resolv_context *ctx,
249 int n0, unsigned char *buf, int buflen, int anslen)
250{
251 uint16_t flags = 0;
252 HEADER *hp = (HEADER *) buf;
253 unsigned char *cp = buf + n0;
254 unsigned char *ep = buf + buflen;
255
256 if ((ep - cp) < 1 + RRFIXEDSZ)
257 return -1;
258
259 /* Add the root label. */
260 *cp++ = 0;
261
262 NS_PUT16 (T_OPT, cp); /* Record type. */
263
264 /* Lowering the advertised buffer size based on the actual
265 answer buffer size is desirable because the server will
266 minimize the reply to fit into the UDP packet (and A
267 non-minimal response might not fit the buffer).
268
269 The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP
270 fallback and a non-minimal response which has to be
271 hard-truncated in the stub resolver, but this is price to
272 pay for avoiding fragmentation. (This issue does not
273 affect the nss_dns functions because they use the stub
274 resolver in such a way that it allocates a properly sized
275 response buffer.) */
276 {
277 uint16_t buffer_size;
278 if (anslen < 512)
279 buffer_size = 512;
280 else if (anslen > RESOLV_EDNS_BUFFER_SIZE)
281 buffer_size = RESOLV_EDNS_BUFFER_SIZE;
282 else
283 buffer_size = anslen;
284 NS_PUT16 (buffer_size, cp);
285 }
286
287 *cp++ = NOERROR; /* Extended RCODE. */
288 *cp++ = 0; /* EDNS version. */
289
290 if (ctx->resp->options & RES_USE_DNSSEC)
291 flags |= NS_OPT_DNSSEC_OK;
292
293 NS_PUT16 (flags, cp);
294 NS_PUT16 (0, cp); /* RDATA length (no options are preent). */
295 hp->arcount = htons (ntohs (hp->arcount) + 1);
296
297 return cp - buf;
298}
299
300#if SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
301# undef res_mkquery
302weak_alias (__res_mkquery, res_mkquery);
303#endif
304