Blame resolv/nss_dns/dns-canon.c

Packit Service 82fcde
/* Copyright (C) 2004-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
   Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <netdb.h>
Packit Service 82fcde
#include <resolv.h>
Packit Service 82fcde
#include <stdlib.h>
Packit Service 82fcde
#include <stdint.h>
Packit Service 82fcde
#include <arpa/nameser.h>
Packit Service 82fcde
#include <nsswitch.h>
Packit Service 82fcde
#include <resolv/resolv_context.h>
Packit Service 82fcde
#include <resolv/resolv-internal.h>
Packit Service 82fcde
Packit Service 82fcde
#if PACKETSZ > 65536
Packit Service 82fcde
# define MAXPACKET	PACKETSZ
Packit Service 82fcde
#else
Packit Service 82fcde
# define MAXPACKET	65536
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
/* We need this time later.  */
Packit Service 82fcde
typedef union querybuf
Packit Service 82fcde
{
Packit Service 82fcde
  HEADER hdr;
Packit Service 82fcde
  unsigned char buf[MAXPACKET];
Packit Service 82fcde
} querybuf;
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
static const short int qtypes[] = { ns_t_a, ns_t_aaaa };
Packit Service 82fcde
#define nqtypes (sizeof (qtypes) / sizeof (qtypes[0]))
Packit Service 82fcde
Packit Service 82fcde
Packit Service 82fcde
enum nss_status
Packit Service 82fcde
_nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
Packit Service 82fcde
			 char **result,int *errnop, int *h_errnop)
Packit Service 82fcde
{
Packit Service 82fcde
  /* Just an alibi buffer, res_nquery will allocate a real buffer for
Packit Service 82fcde
     us.  */
Packit Service 82fcde
  unsigned char buf[20];
Packit Service 82fcde
  union
Packit Service 82fcde
  {
Packit Service 82fcde
    querybuf *buf;
Packit Service 82fcde
    unsigned char *ptr;
Packit Service 82fcde
  } ansp = { .ptr = buf };
Packit Service 82fcde
  enum nss_status status = NSS_STATUS_UNAVAIL;
Packit Service 82fcde
Packit Service 82fcde
  struct resolv_context *ctx = __resolv_context_get ();
Packit Service 82fcde
  if (ctx == NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      *errnop = errno;
Packit Service 82fcde
      *h_errnop = NETDB_INTERNAL;
Packit Service 82fcde
      return NSS_STATUS_UNAVAIL;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  for (int i = 0; i < nqtypes; ++i)
Packit Service 82fcde
    {
Packit Service 82fcde
      int r = __res_context_query (ctx, name, ns_c_in, qtypes[i],
Packit Service 82fcde
				   buf, sizeof (buf), &ansp.ptr, NULL, NULL,
Packit Service 82fcde
				   NULL, NULL);
Packit Service 82fcde
      if (r > 0)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We need to decode the response.  Just one question record.
Packit Service 82fcde
	     And if we got no answers we bail out, too.  */
Packit Service 82fcde
	  if (ansp.buf->hdr.qdcount != htons (1))
Packit Service 82fcde
	    continue;
Packit Service 82fcde
Packit Service 82fcde
	  /* Number of answers.   */
Packit Service 82fcde
	  unsigned int ancount = ntohs (ansp.buf->hdr.ancount);
Packit Service 82fcde
Packit Service 82fcde
	  /* Beginning and end of the buffer with query, answer, and the
Packit Service 82fcde
	     rest.  */
Packit Service 82fcde
	  unsigned char *ptr = &ansp.buf->buf[sizeof (HEADER)];
Packit Service 82fcde
	  unsigned char *endptr = ansp.ptr + r;
Packit Service 82fcde
Packit Service 82fcde
	  /* Skip over the query.  This is the name, type, and class.  */
Packit Service 82fcde
	  int s = __dn_skipname (ptr, endptr);
Packit Service 82fcde
	  if (s < 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	    unavail:
Packit Service 82fcde
	      status = NSS_STATUS_UNAVAIL;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    }
Packit Service 82fcde
Packit Service 82fcde
	  /* Skip over the name and the two 16-bit values containing type
Packit Service 82fcde
	     and class.  */
Packit Service 82fcde
	  ptr += s + 2 * sizeof (uint16_t);
Packit Service 82fcde
Packit Service 82fcde
	  while (ancount-- > 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* Now the reply.  First again the name from the query,
Packit Service 82fcde
		 then type, class, TTL, and the length of the RDATA.
Packit Service 82fcde
		 We remember the name start.  */
Packit Service 82fcde
	      unsigned char *namestart = ptr;
Packit Service 82fcde
	      s = __dn_skipname (ptr, endptr);
Packit Service 82fcde
	      if (s < 0)
Packit Service 82fcde
		goto unavail;
Packit Service 82fcde
Packit Service 82fcde
	      ptr += s;
Packit Service 82fcde
Packit Service 82fcde
	      /* Check that there are enough bytes for the RR
Packit Service 82fcde
		 metadata.  */
Packit Service 82fcde
	      if (endptr - ptr < 10)
Packit Service 82fcde
		goto unavail;
Packit Service 82fcde
Packit Service 82fcde
	      /* Check whether type and class match.  */
Packit Service 82fcde
	      uint_fast16_t type;
Packit Service 82fcde
	      NS_GET16 (type, ptr);
Packit Service 82fcde
	      if (type == qtypes[i])
Packit Service 82fcde
		{
Packit Service 82fcde
		  /* We found the record.  */
Packit Service 82fcde
		  s = __dn_expand (ansp.buf->buf, endptr, namestart,
Packit Service 82fcde
				   buffer, buflen);
Packit Service 82fcde
		  if (s < 0)
Packit Service 82fcde
		    {
Packit Service 82fcde
		      if (errno != EMSGSIZE)
Packit Service 82fcde
			goto unavail;
Packit Service 82fcde
Packit Service 82fcde
		      /* The buffer is too small.  */
Packit Service 82fcde
		      *errnop = ERANGE;
Packit Service 82fcde
		      status = NSS_STATUS_TRYAGAIN;
Packit Service 82fcde
		      h_errno = NETDB_INTERNAL;
Packit Service 82fcde
		    }
Packit Service 82fcde
		  else
Packit Service 82fcde
		    {
Packit Service 82fcde
		      /* Success.  */
Packit Service 82fcde
		      *result = buffer;
Packit Service 82fcde
		      status = NSS_STATUS_SUCCESS;
Packit Service 82fcde
		    }
Packit Service 82fcde
Packit Service 82fcde
		  goto out;
Packit Service 82fcde
		}
Packit Service 82fcde
Packit Service 82fcde
	      if (type != ns_t_cname)
Packit Service 82fcde
		goto unavail;
Packit Service 82fcde
Packit Service 82fcde
	      if (__ns_get16 (ptr) != ns_c_in)
Packit Service 82fcde
		goto unavail;
Packit Service 82fcde
Packit Service 82fcde
	      /* Also skip over class and TTL.  */
Packit Service 82fcde
	      ptr += sizeof (uint16_t) + sizeof (uint32_t);
Packit Service 82fcde
Packit Service 82fcde
	      /* Skip over RDATA length and RDATA itself.  */
Packit Service 82fcde
	      uint16_t rdatalen = __ns_get16 (ptr);
Packit Service 82fcde
	      ptr += sizeof (uint16_t);
Packit Service 82fcde
	      /* Not enough room for RDATA.  */
Packit Service 82fcde
	      if (endptr - ptr < rdatalen)
Packit Service 82fcde
		goto unavail;
Packit Service 82fcde
	      ptr += rdatalen;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      /* Restore original buffer before retry.  */
Packit Service 82fcde
      if (ansp.ptr != buf)
Packit Service 82fcde
	{
Packit Service 82fcde
	  free (ansp.ptr);
Packit Service 82fcde
	  ansp.ptr = buf;
Packit Service 82fcde
	}
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
 out:
Packit Service 82fcde
  *h_errnop = h_errno;
Packit Service 82fcde
Packit Service 82fcde
  if (ansp.ptr != buf)
Packit Service 82fcde
    free (ansp.ptr);
Packit Service 82fcde
  __resolv_context_put (ctx);
Packit Service 82fcde
  return status;
Packit Service 82fcde
}