Blame ares_expand_name.c

Packit 514978
Packit 514978
/* Copyright 1998, 2011 by the Massachusetts Institute of Technology.
Packit 514978
 *
Packit 514978
 * Permission to use, copy, modify, and distribute this
Packit 514978
 * software and its documentation for any purpose and without
Packit 514978
 * fee is hereby granted, provided that the above copyright
Packit 514978
 * notice appear in all copies and that both that copyright
Packit 514978
 * notice and this permission notice appear in supporting
Packit 514978
 * documentation, and that the name of M.I.T. not be used in
Packit 514978
 * advertising or publicity pertaining to distribution of the
Packit 514978
 * software without specific, written prior permission.
Packit 514978
 * M.I.T. makes no representations about the suitability of
Packit 514978
 * this software for any purpose.  It is provided "as is"
Packit 514978
 * without express or implied warranty.
Packit 514978
 */
Packit 514978
Packit 514978
#include "ares_setup.h"
Packit 514978
Packit 514978
#ifdef HAVE_NETINET_IN_H
Packit 514978
#  include <netinet/in.h>
Packit 514978
#endif
Packit 514978
#ifdef HAVE_ARPA_NAMESER_H
Packit 514978
#  include <arpa/nameser.h>
Packit 514978
#else
Packit 514978
#  include "nameser.h"
Packit 514978
#endif
Packit 514978
#ifdef HAVE_ARPA_NAMESER_COMPAT_H
Packit 514978
#  include <arpa/nameser_compat.h>
Packit 514978
#endif
Packit 514978
Packit 514978
#include "ares.h"
Packit 514978
#include "ares_nowarn.h"
Packit 514978
#include "ares_private.h" /* for the memdebug */
Packit 514978
Packit 514978
/* Maximum number of indirections allowed for a name */
Packit 514978
#define MAX_INDIRS 50
Packit 514978
Packit 514978
static int name_length(const unsigned char *encoded, const unsigned char *abuf,
Packit 514978
                       int alen);
Packit 514978
Packit 514978
/* Expand an RFC1035-encoded domain name given by encoded.  The
Packit 514978
 * containing message is given by abuf and alen.  The result given by
Packit 514978
 * *s, which is set to a NUL-terminated allocated buffer.  *enclen is
Packit 514978
 * set to the length of the encoded name (not the length of the
Packit 514978
 * expanded name; the goal is to tell the caller how many bytes to
Packit 514978
 * move forward to get past the encoded name).
Packit 514978
 *
Packit 514978
 * In the simple case, an encoded name is a series of labels, each
Packit 514978
 * composed of a one-byte length (limited to values between 0 and 63
Packit 514978
 * inclusive) followed by the label contents.  The name is terminated
Packit 514978
 * by a zero-length label.
Packit 514978
 *
Packit 514978
 * In the more complicated case, a label may be terminated by an
Packit 514978
 * indirection pointer, specified by two bytes with the high bits of
Packit 514978
 * the first byte (corresponding to INDIR_MASK) set to 11.  With the
Packit 514978
 * two high bits of the first byte stripped off, the indirection
Packit 514978
 * pointer gives an offset from the beginning of the containing
Packit 514978
 * message with more labels to decode.  Indirection can happen an
Packit 514978
 * arbitrary number of times, so we have to detect loops.
Packit 514978
 *
Packit 514978
 * Since the expanded name uses '.' as a label separator, we use
Packit 514978
 * backslashes to escape periods or backslashes in the expanded name.
Packit 514978
 */
Packit 514978
Packit 514978
int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf,
Packit 514978
                     int alen, char **s, long *enclen)
Packit 514978
{
Packit 514978
  int len, indir = 0;
Packit 514978
  char *q;
Packit 514978
  const unsigned char *p;
Packit 514978
  union {
Packit 514978
    ares_ssize_t sig;
Packit 514978
     size_t uns;
Packit 514978
  } nlen;
Packit 514978
Packit 514978
  nlen.sig = name_length(encoded, abuf, alen);
Packit 514978
  if (nlen.sig < 0)
Packit 514978
    return ARES_EBADNAME;
Packit 514978
Packit 514978
  *s = ares_malloc(nlen.uns + 1);
Packit 514978
  if (!*s)
Packit 514978
    return ARES_ENOMEM;
Packit 514978
  q = *s;
Packit 514978
Packit 514978
  if (nlen.uns == 0) {
Packit 514978
    /* RFC2181 says this should be ".": the root of the DNS tree.
Packit 514978
     * Since this function strips trailing dots though, it becomes ""
Packit 514978
     */
Packit 514978
    q[0] = '\0';
Packit 514978
Packit 514978
    /* indirect root label (like 0xc0 0x0c) is 2 bytes long (stupid, but
Packit 514978
       valid) */
Packit 514978
    if ((*encoded & INDIR_MASK) == INDIR_MASK)
Packit 514978
      *enclen = 2L;
Packit 514978
    else
Packit 514978
      *enclen = 1L;  /* the caller should move one byte to get past this */
Packit 514978
Packit 514978
    return ARES_SUCCESS;
Packit 514978
  }
Packit 514978
Packit 514978
  /* No error-checking necessary; it was all done by name_length(). */
Packit 514978
  p = encoded;
Packit 514978
  while (*p)
Packit 514978
    {
Packit 514978
      if ((*p & INDIR_MASK) == INDIR_MASK)
Packit 514978
        {
Packit 514978
          if (!indir)
Packit 514978
            {
Packit 514978
              *enclen = aresx_uztosl(p + 2U - encoded);
Packit 514978
              indir = 1;
Packit 514978
            }
Packit 514978
          p = abuf + ((*p & ~INDIR_MASK) << 8 | *(p + 1));
Packit 514978
        }
Packit 514978
      else
Packit 514978
        {
Packit 514978
          len = *p;
Packit 514978
          p++;
Packit 514978
          while (len--)
Packit 514978
            {
Packit 514978
              if (*p == '.' || *p == '\\')
Packit 514978
                *q++ = '\\';
Packit 514978
              *q++ = *p;
Packit 514978
              p++;
Packit 514978
            }
Packit 514978
          *q++ = '.';
Packit 514978
        }
Packit 514978
    }
Packit 514978
  if (!indir)
Packit 514978
    *enclen = aresx_uztosl(p + 1U - encoded);
Packit 514978
Packit 514978
  /* Nuke the trailing period if we wrote one. */
Packit 514978
  if (q > *s)
Packit 514978
    *(q - 1) = 0;
Packit 514978
  else
Packit 514978
    *q = 0; /* zero terminate; LCOV_EXCL_LINE: empty names exit above */
Packit 514978
Packit 514978
  return ARES_SUCCESS;
Packit 514978
}
Packit 514978
Packit 514978
/* Return the length of the expansion of an encoded domain name, or
Packit 514978
 * -1 if the encoding is invalid.
Packit 514978
 */
Packit 514978
static int name_length(const unsigned char *encoded, const unsigned char *abuf,
Packit 514978
                       int alen)
Packit 514978
{
Packit 514978
  int n = 0, offset, indir = 0, top;
Packit 514978
Packit 514978
  /* Allow the caller to pass us abuf + alen and have us check for it. */
Packit 514978
  if (encoded >= abuf + alen)
Packit 514978
    return -1;
Packit 514978
Packit 514978
  while (*encoded)
Packit 514978
    {
Packit 514978
      top = (*encoded & INDIR_MASK);
Packit 514978
      if (top == INDIR_MASK)
Packit 514978
        {
Packit 514978
          /* Check the offset and go there. */
Packit 514978
          if (encoded + 1 >= abuf + alen)
Packit 514978
            return -1;
Packit 514978
          offset = (*encoded & ~INDIR_MASK) << 8 | *(encoded + 1);
Packit 514978
          if (offset >= alen)
Packit 514978
            return -1;
Packit 514978
          encoded = abuf + offset;
Packit 514978
Packit 514978
          /* If we've seen more indirects than the message length,
Packit 514978
           * then there's a loop.
Packit 514978
           */
Packit 514978
          ++indir;
Packit 514978
          if (indir > alen || indir > MAX_INDIRS)
Packit 514978
            return -1;
Packit 514978
        }
Packit 514978
      else if (top == 0x00)
Packit 514978
        {
Packit 514978
          offset = *encoded;
Packit 514978
          if (encoded + offset + 1 >= abuf + alen)
Packit 514978
            return -1;
Packit 514978
          encoded++;
Packit 514978
          while (offset--)
Packit 514978
            {
Packit 514978
              n += (*encoded == '.' || *encoded == '\\') ? 2 : 1;
Packit 514978
              encoded++;
Packit 514978
            }
Packit 514978
          n++;
Packit 514978
        }
Packit 514978
      else
Packit 514978
        {
Packit 514978
          /* RFC 1035 4.1.4 says other options (01, 10) for top 2
Packit 514978
           * bits are reserved.
Packit 514978
           */
Packit 514978
          return -1;
Packit 514978
        }
Packit 514978
    }
Packit 514978
Packit 514978
  /* If there were any labels at all, then the number of dots is one
Packit 514978
   * less than the number of labels, so subtract one.
Packit 514978
   */
Packit 514978
  return (n) ? n - 1 : n;
Packit 514978
}
Packit 514978
Packit 514978
/* Like ares_expand_name but returns EBADRESP in case of invalid input. */
Packit 514978
int ares__expand_name_for_response(const unsigned char *encoded,
Packit 514978
                                   const unsigned char *abuf, int alen,
Packit 514978
                                   char **s, long *enclen)
Packit 514978
{
Packit 514978
  int status = ares_expand_name(encoded, abuf, alen, s, enclen);
Packit 514978
  if (status == ARES_EBADNAME)
Packit 514978
    status = ARES_EBADRESP;
Packit 514978
  return status;
Packit 514978
}