dns-canon.c 4.6 KB

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