(root)/
glibc-2.38/
resolv/
nss_dns/
dns-canon.c
       1  /* Copyright (C) 2004-2023 Free Software Foundation, Inc.
       2     This file is part of the GNU C Library.
       3  
       4     The GNU C Library is free software; you can redistribute it and/or
       5     modify it under the terms of the GNU Lesser General Public
       6     License as published by the Free Software Foundation; either
       7     version 2.1 of the License, or (at your option) any later version.
       8  
       9     The GNU C Library is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12     Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public
      15     License along with the GNU C Library; if not, see
      16     <https://www.gnu.org/licenses/>.  */
      17  
      18  #include <errno.h>
      19  #include <netdb.h>
      20  #include <resolv.h>
      21  #include <stdlib.h>
      22  #include <stdint.h>
      23  #include <arpa/nameser.h>
      24  #include <nsswitch.h>
      25  #include <resolv/resolv_context.h>
      26  #include <resolv/resolv-internal.h>
      27  #include <nss_dns.h>
      28  
      29  #if PACKETSZ > 65536
      30  # define MAXPACKET	PACKETSZ
      31  #else
      32  # define MAXPACKET	65536
      33  #endif
      34  
      35  
      36  /* We need this time later.  */
      37  typedef union querybuf
      38  {
      39    HEADER hdr;
      40    unsigned char buf[MAXPACKET];
      41  } querybuf;
      42  
      43  
      44  static const short int qtypes[] = { ns_t_a, ns_t_aaaa };
      45  #define nqtypes (sizeof (qtypes) / sizeof (qtypes[0]))
      46  
      47  
      48  enum nss_status
      49  _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
      50  			 char **result,int *errnop, int *h_errnop)
      51  {
      52    /* Just an alibi buffer, res_nquery will allocate a real buffer for
      53       us.  */
      54    unsigned char buf[20];
      55    union
      56    {
      57      querybuf *buf;
      58      unsigned char *ptr;
      59    } ansp = { .ptr = buf };
      60    enum nss_status status = NSS_STATUS_UNAVAIL;
      61  
      62    struct resolv_context *ctx = __resolv_context_get ();
      63    if (ctx == NULL)
      64      {
      65        *errnop = errno;
      66        *h_errnop = NETDB_INTERNAL;
      67        return NSS_STATUS_UNAVAIL;
      68      }
      69  
      70    for (int i = 0; i < nqtypes; ++i)
      71      {
      72        int r = __res_context_query (ctx, name, ns_c_in, qtypes[i],
      73  				   buf, sizeof (buf), &ansp.ptr, NULL, NULL,
      74  				   NULL, NULL);
      75        if (r > 0)
      76  	{
      77  	  /* We need to decode the response.  Just one question record.
      78  	     And if we got no answers we bail out, too.  */
      79  	  if (ansp.buf->hdr.qdcount != htons (1))
      80  	    continue;
      81  
      82  	  /* Number of answers.   */
      83  	  unsigned int ancount = ntohs (ansp.buf->hdr.ancount);
      84  
      85  	  /* Beginning and end of the buffer with query, answer, and the
      86  	     rest.  */
      87  	  unsigned char *ptr = &ansp.buf->buf[sizeof (HEADER)];
      88  	  unsigned char *endptr = ansp.ptr + r;
      89  
      90  	  /* Skip over the query.  This is the name, type, and class.  */
      91  	  int s = __libc_dn_skipname (ptr, endptr);
      92  	  if (s < 0)
      93  	    {
      94  	    unavail:
      95  	      status = NSS_STATUS_UNAVAIL;
      96  	      break;
      97  	    }
      98  
      99  	  /* Skip over the name and the two 16-bit values containing type
     100  	     and class.  */
     101  	  ptr += s + 2 * sizeof (uint16_t);
     102  
     103  	  while (ancount-- > 0)
     104  	    {
     105  	      /* Now the reply.  First again the name from the query,
     106  		 then type, class, TTL, and the length of the RDATA.
     107  		 We remember the name start.  */
     108  	      unsigned char *namestart = ptr;
     109  	      s = __libc_dn_skipname (ptr, endptr);
     110  	      if (s < 0)
     111  		goto unavail;
     112  
     113  	      ptr += s;
     114  
     115  	      /* Check that there are enough bytes for the RR
     116  		 metadata.  */
     117  	      if (endptr - ptr < 10)
     118  		goto unavail;
     119  
     120  	      /* Check whether type and class match.  */
     121  	      short int type;
     122  	      NS_GET16 (type, ptr);
     123  	      if (type == qtypes[i])
     124  		{
     125  		  /* We found the record.  */
     126  		  s = __libc_dn_expand (ansp.buf->buf, endptr, namestart,
     127  					buffer, buflen);
     128  		  if (s < 0)
     129  		    {
     130  		      if (errno != EMSGSIZE)
     131  			goto unavail;
     132  
     133  		      /* The buffer is too small.  */
     134  		      *errnop = ERANGE;
     135  		      status = NSS_STATUS_TRYAGAIN;
     136  		      h_errno = NETDB_INTERNAL;
     137  		    }
     138  		  else
     139  		    {
     140  		      /* Success.  */
     141  		      *result = buffer;
     142  		      status = NSS_STATUS_SUCCESS;
     143  		    }
     144  
     145  		  goto out;
     146  		}
     147  
     148  	      if (type != ns_t_cname)
     149  		goto unavail;
     150  
     151  	      uint16_t rrclass;
     152  	      NS_GET16 (rrclass, ptr);
     153  	      if (rrclass != ns_c_in)
     154  		goto unavail;
     155  
     156  	      /* Skip over TTL.  */
     157  	      ptr += sizeof (uint32_t);
     158  
     159  	      /* Skip over RDATA length and RDATA itself.  */
     160  	      uint16_t rdatalen;
     161  	      NS_GET16 (rdatalen, ptr);
     162  
     163  	      /* Not enough room for RDATA.  */
     164  	      if (endptr - ptr < rdatalen)
     165  		goto unavail;
     166  	      ptr += rdatalen;
     167  	    }
     168  	}
     169  
     170        /* Restore original buffer before retry.  */
     171        if (ansp.ptr != buf)
     172  	{
     173  	  free (ansp.ptr);
     174  	  ansp.ptr = buf;
     175  	}
     176      }
     177  
     178   out:
     179    *h_errnop = h_errno;
     180  
     181    if (ansp.ptr != buf)
     182      free (ansp.ptr);
     183    __resolv_context_put (ctx);
     184    return status;
     185  }
     186  libc_hidden_def (_nss_dns_getcanonname_r)