1  /* Creation of DNS query packets.
       2     Copyright (C) 1995-2023 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
      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  }
     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
     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
     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
     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)