tst-bug18665-tcp.c 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /* Test __libc_res_nsend buffer mismanagement, basic TCP coverage.
  2. Copyright (C) 2016-2019 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  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 <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21. #include <support/check.h>
  22. #include <support/check_nss.h>
  23. #include <support/resolv_test.h>
  24. #include <support/xthread.h>
  25. #include <support/xmemstream.h>
  26. static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
  27. static int initial_address_count = 1;
  28. static int subsequent_address_count = 2000;
  29. static int response_number = 0;
  30. static void
  31. response (const struct resolv_response_context *ctx,
  32. struct resolv_response_builder *b,
  33. const char *qname, uint16_t qclass, uint16_t qtype)
  34. {
  35. TEST_VERIFY_EXIT (qname != NULL);
  36. /* If not using TCP, just force its use. */
  37. if (!ctx->tcp)
  38. {
  39. struct resolv_response_flags flags = {.tc = true};
  40. resolv_response_init (b, flags);
  41. resolv_response_add_question (b, qname, qclass, qtype);
  42. return;
  43. }
  44. struct resolv_response_flags flags = {};
  45. resolv_response_init (b, flags);
  46. resolv_response_add_question (b, qname, qclass, qtype);
  47. resolv_response_section (b, ns_s_an);
  48. /* The number of addresses (in the additional section) for the name
  49. server record (in the authoritative section). */
  50. int address_count;
  51. xpthread_mutex_lock (&lock);
  52. ++response_number;
  53. if (response_number == 1)
  54. address_count = initial_address_count;
  55. else if (response_number == 2)
  56. {
  57. address_count = 0;
  58. resolv_response_drop (b);
  59. resolv_response_close (b);
  60. }
  61. else
  62. address_count = subsequent_address_count;
  63. xpthread_mutex_unlock (&lock);
  64. /* Only add the address record to the answer section if we requested
  65. any name server addresses. */
  66. if (address_count > 0)
  67. {
  68. resolv_response_open_record (b, qname, qclass, qtype, 0);
  69. switch (qtype)
  70. {
  71. case T_A:
  72. {
  73. char ipv4[4] = {10, response_number >> 8, response_number, 0};
  74. ipv4[3] = 2 * ctx->tcp + 4 * ctx->server_index;
  75. resolv_response_add_data (b, &ipv4, sizeof (ipv4));
  76. }
  77. break;
  78. case T_AAAA:
  79. {
  80. char ipv6[16]
  81. = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0,
  82. response_number >> 8, response_number, 0, 0};
  83. ipv6[15] = 2 * ctx->tcp + 4 * ctx->server_index;
  84. resolv_response_add_data (b, &ipv6, sizeof (ipv6));
  85. }
  86. break;
  87. default:
  88. support_record_failure ();
  89. printf ("error: unexpected QTYPE: %s/%u/%u\n",
  90. qname, qclass, qtype);
  91. }
  92. resolv_response_close_record (b);
  93. /* Add the name server record. */
  94. resolv_response_section (b, ns_s_ns);
  95. resolv_response_open_record (b, "example", C_IN, T_NS, 0);
  96. resolv_response_add_name (b, "ns.example");
  97. resolv_response_close_record (b);
  98. /* Increase the response size with name server addresses. These
  99. addresses are not copied out of nss_dns, and thus do not
  100. trigger getaddrinfo retries with a larger buffer, making
  101. testing more predictable. */
  102. resolv_response_section (b, ns_s_ar);
  103. for (int i = 1; i <= address_count; ++i)
  104. {
  105. resolv_response_open_record (b, "ns.example", qclass, qtype, 0);
  106. switch (qtype)
  107. {
  108. case T_A:
  109. {
  110. char ipv4[4] = {response_number, i >> 8, i, 0};
  111. ipv4[3] = 2 * ctx->tcp + 4 * ctx->server_index;
  112. resolv_response_add_data (b, &ipv4, sizeof (ipv4));
  113. }
  114. break;
  115. case T_AAAA:
  116. {
  117. char ipv6[16]
  118. = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
  119. response_number >> 8, response_number,
  120. i >> 8, i, 0, 0};
  121. ipv6[15] = 2 * ctx->tcp + 4 * ctx->server_index;
  122. resolv_response_add_data (b, &ipv6, sizeof (ipv6));
  123. }
  124. break;
  125. default:
  126. support_record_failure ();
  127. printf ("error: unexpected QTYPE: %s/%u/%u\n",
  128. qname, qclass, qtype);
  129. }
  130. resolv_response_close_record (b);
  131. }
  132. }
  133. }
  134. static char *
  135. expected_result (unsigned port, unsigned response_number)
  136. {
  137. struct xmemstream mem;
  138. xopen_memstream (&mem);
  139. /* We fail the second TCP query to the first server by closing the
  140. connection immediately, without returning any data. This should
  141. cause failover to the second server. */
  142. int server_index = 1;
  143. fprintf (mem.out, "address: STREAM/TCP 10.%u.%u.%u %u\n",
  144. (response_number >> 8) & 0xff, response_number & 0xff,
  145. 2 + 4 * server_index, port);
  146. fprintf (mem.out, "address: STREAM/TCP 2001:db8::%x:%x %u\n",
  147. (response_number + 1) & 0xffff,
  148. 2 + 4 * server_index, port);
  149. xfclose_memstream (&mem);
  150. return mem.buffer;
  151. }
  152. static void
  153. test_different_sizes (void)
  154. {
  155. struct addrinfo hints =
  156. {
  157. .ai_family = AF_UNSPEC,
  158. .ai_socktype = SOCK_STREAM,
  159. .ai_protocol = IPPROTO_TCP,
  160. };
  161. struct addrinfo *ai;
  162. char *expected;
  163. int ret;
  164. /* This magic number produces a response size close to 2048
  165. bytes. */
  166. initial_address_count = 124;
  167. response_number = 0;
  168. ret = getaddrinfo ("www.example", "80", &hints, &ai);
  169. expected = expected_result (80, 3);
  170. check_addrinfo ("www.example:80", ai, ret, expected);
  171. if (ret == 0)
  172. freeaddrinfo (ai);
  173. free (expected);
  174. response_number = 0;
  175. ret = getaddrinfo ("www123.example", "80", &hints, &ai);
  176. if (ret == 0)
  177. freeaddrinfo (ai);
  178. response_number = 0;
  179. ret = getaddrinfo ("www1234.example", "80", &hints, &ai);
  180. if (ret == 0)
  181. freeaddrinfo (ai);
  182. response_number = 0;
  183. ret = getaddrinfo ("www12345.example", "80", &hints, &ai);
  184. if (ret == 0)
  185. freeaddrinfo (ai);
  186. }
  187. static int
  188. do_test (void)
  189. {
  190. struct resolv_test *obj = resolv_test_start
  191. ((struct resolv_redirect_config)
  192. {
  193. .response_callback = response
  194. });
  195. test_different_sizes ();
  196. _res.options |= RES_SNGLKUP;
  197. test_different_sizes ();
  198. _res.options |= RES_SNGLKUPREOP;
  199. test_different_sizes ();
  200. resolv_test_end (obj);
  201. return 0;
  202. }
  203. #include <support/test-driver.c>