1 /* Creation of DNS query packets.
2    Copyright (C) 1995-2022 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    <https://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 <stdint.h>
86 #include <sys/types.h>
87 #include <sys/param.h>
88 #include <netinet/in.h>
89 #include <arpa/nameser.h>
90 #include <netdb.h>
91 #include <resolv/resolv-internal.h>
92 #include <resolv/resolv_context.h>
93 #include <string.h>
94 #include <sys/time.h>
95 #include <shlib-compat.h>
96 #include <random-bits.h>
97 
98 int
__res_context_mkquery(struct resolv_context * ctx,int op,const char * dname,int class,int type,const unsigned char * data,unsigned char * buf,int buflen)99 __res_context_mkquery (struct resolv_context *ctx, int op, const char *dname,
100                        int class, int type, const unsigned char *data,
101                        unsigned char *buf, int buflen)
102 {
103   HEADER *hp;
104   unsigned char *cp;
105   int n;
106   unsigned char *dnptrs[20], **dpp, **lastdnptr;
107 
108   if (class < 0 || class > 65535 || type < 0 || type > 65535)
109     return -1;
110 
111   /* Initialize header fields.  */
112   if ((buf == NULL) || (buflen < HFIXEDSZ))
113     return -1;
114   memset (buf, 0, HFIXEDSZ);
115   hp = (HEADER *) buf;
116   /* We randomize the IDs every time.  The old code just incremented
117      by one after the initial randomization which still predictable if
118      the application does multiple requests.  */
119   hp->id = random_bits ();
120   hp->opcode = op;
121   if (ctx->resp->options & RES_TRUSTAD)
122     hp->ad = 1;
123   hp->rd = (ctx->resp->options & RES_RECURSE) != 0;
124   hp->rcode = NOERROR;
125   cp = buf + HFIXEDSZ;
126   buflen -= HFIXEDSZ;
127   dpp = dnptrs;
128   *dpp++ = buf;
129   *dpp++ = NULL;
130   lastdnptr = dnptrs + sizeof dnptrs / sizeof dnptrs[0];
131 
132   /* Perform opcode specific processing.  */
133   switch (op)
134     {
135     case NS_NOTIFY_OP:
136       if ((buflen -= QFIXEDSZ + (data == NULL ? 0 : RRFIXEDSZ)) < 0)
137         return -1;
138       goto compose;
139 
140     case QUERY:
141       if ((buflen -= QFIXEDSZ) < 0)
142         return -1;
143     compose:
144       n = __ns_name_compress (dname, cp, buflen,
145                               (const unsigned char **) dnptrs,
146                               (const unsigned char **) lastdnptr);
147       if (n < 0)
148         return -1;
149       cp += n;
150       buflen -= n;
151       NS_PUT16 (type, cp);
152       NS_PUT16 (class, cp);
153       hp->qdcount = htons (1);
154       if (op == QUERY || data == NULL)
155         break;
156 
157       /* Make an additional record for completion domain.  */
158       n = __ns_name_compress ((char *)data, cp, buflen,
159                               (const unsigned char **) dnptrs,
160                               (const unsigned char **) lastdnptr);
161       if (__glibc_unlikely (n < 0))
162         return -1;
163       cp += n;
164       buflen -= n;
165       NS_PUT16 (T_NULL, cp);
166       NS_PUT16 (class, cp);
167       NS_PUT32 (0, cp);
168       NS_PUT16 (0, cp);
169       hp->arcount = htons (1);
170       break;
171 
172     default:
173       return -1;
174     }
175   return cp - buf;
176 }
libc_hidden_def(__res_context_mkquery)177 libc_hidden_def (__res_context_mkquery)
178 
179 /* Common part of res_nmkquery and res_mkquery.  */
180 static int
181 context_mkquery_common (struct resolv_context *ctx,
182                         int op, const char *dname, int class, int type,
183                         const unsigned char *data,
184                         unsigned char *buf, int buflen)
185 {
186   if (ctx == NULL)
187     return -1;
188   int result = __res_context_mkquery
189     (ctx, op, dname, class, type, data, buf, buflen);
190   if (result >= 2)
191     memcpy (&ctx->resp->id, buf, 2);
192   __resolv_context_put (ctx);
193   return result;
194 }
195 
196 /* Form all types of queries.  Returns the size of the result or -1 on
197    error.
198 
199    STATP points to an initialized resolver state.  OP is the opcode of
200    the query.  DNAME is the domain.  CLASS and TYPE are the DNS query
201    class and type.  DATA can be NULL; otherwise, it is a pointer to a
202    domain name which is included in the generated packet (if op ==
203    NS_NOTIFY_OP).  BUF must point to the out buffer of BUFLEN bytes.
204 
205    DATALEN and NEWRR_IN are currently ignored.  */
206 int
___res_nmkquery(res_state statp,int op,const char * dname,int class,int type,const unsigned char * data,int datalen,const unsigned char * newrr_in,unsigned char * buf,int buflen)207 ___res_nmkquery (res_state statp, int op, const char *dname,
208                  int class, int type,
209                  const unsigned char *data, int datalen,
210                  const unsigned char *newrr_in,
211                  unsigned char *buf, int buflen)
212 {
213   return context_mkquery_common
214     (__resolv_context_get_override (statp),
215      op, dname, class, type, data, buf, buflen);
216 }
217 versioned_symbol (libc, ___res_nmkquery, res_nmkquery, GLIBC_2_34);
218 #if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_2, GLIBC_2_34)
219 compat_symbol (libresolv, ___res_nmkquery, __res_nmkquery, GLIBC_2_2);
220 #endif
221 
222 int
___res_mkquery(int op,const char * dname,int class,int type,const unsigned char * data,int datalen,const unsigned char * newrr_in,unsigned char * buf,int buflen)223 ___res_mkquery (int op, const char *dname, int class, int type,
224                 const unsigned char *data, int datalen,
225                 const unsigned char *newrr_in,
226                 unsigned char *buf, int buflen)
227 {
228   return context_mkquery_common
229     (__resolv_context_get_preinit (),
230      op, dname, class, type, data, buf, buflen);
231 }
232 versioned_symbol (libc, ___res_mkquery, res_mkquery, GLIBC_2_34);
233 #if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_0, GLIBC_2_2)
234 compat_symbol (libresolv, ___res_mkquery, res_mkquery, GLIBC_2_0);
235 #endif
236 #if OTHER_SHLIB_COMPAT (libresolv, GLIBC_2_2, GLIBC_2_34)
237 compat_symbol (libresolv, ___res_mkquery, __res_mkquery, GLIBC_2_2);
238 #endif
239 
240 /* Create an OPT resource record.  Return the length of the final
241    packet, or -1 on error.
242 
243    STATP must be an initialized resolver state.  N0 is the current
244    number of bytes of the packet (already written to BUF by the
245    aller).  BUF is the packet being constructed.  The array it
246    pointers to must be BUFLEN bytes long.  ANSLEN is the advertised
247    EDNS buffer size (to be included in the OPT resource record).  */
248 int
__res_nopt(struct resolv_context * ctx,int n0,unsigned char * buf,int buflen,int anslen)249 __res_nopt (struct resolv_context *ctx,
250             int n0, unsigned char *buf, int buflen, int anslen)
251 {
252   uint16_t flags = 0;
253   HEADER *hp = (HEADER *) buf;
254   unsigned char *cp = buf + n0;
255   unsigned char *ep = buf + buflen;
256 
257   if ((ep - cp) < 1 + RRFIXEDSZ)
258     return -1;
259 
260   /* Add the root label.  */
261   *cp++ = 0;
262 
263   NS_PUT16 (T_OPT, cp);         /* Record type.  */
264 
265   /* Lowering the advertised buffer size based on the actual
266      answer buffer size is desirable because the server will
267      minimize the reply to fit into the UDP packet (and A
268      non-minimal response might not fit the buffer).
269 
270      The RESOLV_EDNS_BUFFER_SIZE limit could still result in TCP
271      fallback and a non-minimal response which has to be
272      hard-truncated in the stub resolver, but this is price to
273      pay for avoiding fragmentation.  (This issue does not
274      affect the nss_dns functions because they use the stub
275      resolver in such a way that it allocates a properly sized
276      response buffer.)  */
277   {
278     uint16_t buffer_size;
279     if (anslen < 512)
280       buffer_size = 512;
281     else if (anslen > RESOLV_EDNS_BUFFER_SIZE)
282       buffer_size = RESOLV_EDNS_BUFFER_SIZE;
283     else
284       buffer_size = anslen;
285     NS_PUT16 (buffer_size, cp);
286   }
287 
288   *cp++ = NOERROR;              /* Extended RCODE.  */
289   *cp++ = 0;                    /* EDNS version.  */
290 
291   if (ctx->resp->options & RES_USE_DNSSEC)
292     flags |= NS_OPT_DNSSEC_OK;
293 
294   NS_PUT16 (flags, cp);
295   NS_PUT16 (0, cp);       /* RDATA length (no options are preent).  */
296   hp->arcount = htons (ntohs (hp->arcount) + 1);
297 
298   return cp - buf;
299 }
300 libc_hidden_def (__res_nopt)
301