Back to index

glibc  2.9
dns-canon.c
Go to the documentation of this file.
00001 /* Copyright (C) 2004, 2006, 2008 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2004.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <errno.h>
00021 #include <netdb.h>
00022 #include <resolv.h>
00023 #include <stdlib.h>
00024 #include <arpa/nameser.h>
00025 #include <nsswitch.h>
00026 
00027 
00028 #if PACKETSZ > 65536
00029 # define MAXPACKET   PACKETSZ
00030 #else
00031 # define MAXPACKET   65536
00032 #endif
00033 
00034 
00035 /* We need this time later.  */
00036 typedef union querybuf
00037 {
00038   HEADER hdr;
00039   unsigned char buf[MAXPACKET];
00040 } querybuf;
00041 
00042 
00043 static const short int qtypes[] = { ns_t_a, ns_t_aaaa };
00044 #define nqtypes (sizeof (qtypes) / sizeof (qtypes[0]))
00045 
00046 
00047 enum nss_status
00048 _nss_dns_getcanonname_r (const char *name, char *buffer, size_t buflen,
00049                       char **result,int *errnop, int *h_errnop)
00050 {
00051   /* Just an alibi buffer, res_nquery will allocate a real buffer for
00052      us.  */
00053   unsigned char buf[20];
00054   union
00055   {
00056     querybuf *buf;
00057     unsigned char *ptr;
00058   } ansp = { .ptr = buf };
00059   enum nss_status status = NSS_STATUS_UNAVAIL;
00060 
00061   for (int i = 0; i < nqtypes; ++i)
00062     {
00063       int r = __libc_res_nquery (&_res, name, ns_c_in, qtypes[i],
00064                              buf, sizeof (buf), &ansp.ptr, NULL, NULL,
00065                              NULL);
00066       if (r > 0)
00067        {
00068          /* We need to decode the response.  Just one question record.
00069             And if we got no answers we bail out, too.  */
00070          if (ansp.buf->hdr.qdcount != htons (1))
00071            continue;
00072 
00073          /* Number of answers.   */
00074          unsigned int ancount = ntohs (ansp.buf->hdr.ancount);
00075 
00076          /* Beginning and end of the buffer with query, answer, and the
00077             rest.  */
00078          unsigned char *ptr = &ansp.buf->buf[sizeof (HEADER)];
00079          unsigned char *endptr = ansp.ptr + r;
00080 
00081          /* Skip over the query.  This is the name, type, and class.  */
00082          int s = __dn_skipname (ptr, endptr);
00083          if (s < 0)
00084            {
00085            unavail:
00086              status = NSS_STATUS_UNAVAIL;
00087              break;
00088            }
00089 
00090          /* Skip over the name and the two 16-bit values containing type
00091             and class.  */
00092          ptr += s + 2 * sizeof (uint16_t);
00093 
00094          while (ancount-- > 0)
00095            {
00096              /* Now the reply.  First again the name from the query,
00097                then type, class, TTL, and the length of the RDATA.
00098                We remember the name start.  */
00099              unsigned char *namestart = ptr;
00100              s = __dn_skipname (ptr, endptr);
00101              if (s < 0)
00102               goto unavail;
00103 
00104              ptr += s;
00105 
00106              /* Check whether type and class match.  */
00107              uint_fast16_t type;
00108              NS_GET16 (type, ptr);
00109              if (type == qtypes[i])
00110               {
00111                 /* We found the record.  */
00112                 s = __dn_expand (ansp.buf->buf, endptr, namestart,
00113                                buffer, buflen);
00114                 if (s < 0)
00115                   {
00116                     if (errno != EMSGSIZE)
00117                      goto unavail;
00118 
00119                     /* The buffer is too small.  */
00120                     *errnop = ERANGE;
00121                     status = NSS_STATUS_TRYAGAIN;
00122                     h_errno = NETDB_INTERNAL;
00123                   }
00124                 else
00125                   {
00126                     /* Success.  */
00127                     *result = buffer;
00128                     status = NSS_STATUS_SUCCESS;
00129                   }
00130 
00131                 goto out;
00132               }
00133 
00134              if (type != ns_t_cname)
00135               goto unavail;
00136 
00137              if (__ns_get16 (ptr) != ns_c_in)
00138               goto unavail;
00139 
00140              /* Also skip over the TTL.  */
00141              ptr += sizeof (uint16_t) + sizeof (uint32_t);
00142 
00143              /* Skip over the data length and data.  */
00144              ptr += sizeof (uint16_t) + __ns_get16 (ptr);
00145            }
00146        }
00147     }
00148 
00149  out:
00150   *h_errnop = h_errno;
00151 
00152   if (ansp.ptr != buf)
00153     free (ansp.ptr);
00154 
00155   return status;
00156 }