1 /* Test __libc_res_nsend buffer mismanagement, basic TCP coverage.
2 Copyright (C) 2016-2017 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
25 #include <support/check.h>
26 #include <support/check_nss.h>
27 #include <support/resolv_test.h>
28 #include <support/xthread.h>
29 #include <support/xmemstream.h>
31 static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
33 static int initial_address_count = 1;
34 static int subsequent_address_count = 2000;
35 static int response_number = 0;
38 response (const struct resolv_response_context *ctx,
39 struct resolv_response_builder *b,
40 const char *qname, uint16_t qclass, uint16_t qtype)
42 TEST_VERIFY_EXIT (qname != NULL);
44 /* If not using TCP, just force its use. */
47 struct resolv_response_flags flags = {.tc = true};
48 resolv_response_init (b, flags);
49 resolv_response_add_question (b, qname, qclass, qtype);
53 struct resolv_response_flags flags = {};
54 resolv_response_init (b, flags);
55 resolv_response_add_question (b, qname, qclass, qtype);
57 resolv_response_section (b, ns_s_an);
59 /* The number of addresses (in the additional section) for the name
60 server record (in the authoritative section). */
62 xpthread_mutex_lock (&lock);
64 if (response_number == 1)
65 address_count = initial_address_count;
66 else if (response_number == 2)
69 resolv_response_drop (b);
70 resolv_response_close (b);
73 address_count = subsequent_address_count;
74 xpthread_mutex_unlock (&lock);
76 /* Only add the address record to the answer section if we requested
77 any name server addresses. */
78 if (address_count > 0)
80 resolv_response_open_record (b, qname, qclass, qtype, 0);
85 char ipv4[4] = {10, response_number >> 8, response_number, 0};
86 ipv4[3] = 2 * ctx->tcp + 4 * ctx->server_index;
87 resolv_response_add_data (b, &ipv4, sizeof (ipv4));
93 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0,
94 response_number >> 8, response_number, 0, 0};
95 ipv6[15] = 2 * ctx->tcp + 4 * ctx->server_index;
96 resolv_response_add_data (b, &ipv6, sizeof (ipv6));
100 support_record_failure ();
101 printf ("error: unexpected QTYPE: %s/%u/%u\n",
102 qname, qclass, qtype);
104 resolv_response_close_record (b);
106 /* Add the name server record. */
107 resolv_response_section (b, ns_s_ns);
108 resolv_response_open_record (b, "example", C_IN, T_NS, 0);
109 resolv_response_add_name (b, "ns.example");
110 resolv_response_close_record (b);
112 /* Increase the response size with name server addresses. These
113 addresses are not copied out of nss_dns, and thus do not
114 trigger getaddrinfo retries with a larger buffer, making
115 testing more predictable. */
116 resolv_response_section (b, ns_s_ar);
117 for (int i = 1; i <= address_count; ++i)
119 resolv_response_open_record (b, "ns.example", qclass, qtype, 0);
124 char ipv4[4] = {response_number, i >> 8, i, 0};
125 ipv4[3] = 2 * ctx->tcp + 4 * ctx->server_index;
126 resolv_response_add_data (b, &ipv4, sizeof (ipv4));
132 = {0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0,
133 response_number >> 8, response_number,
135 ipv6[15] = 2 * ctx->tcp + 4 * ctx->server_index;
136 resolv_response_add_data (b, &ipv6, sizeof (ipv6));
140 support_record_failure ();
141 printf ("error: unexpected QTYPE: %s/%u/%u\n",
142 qname, qclass, qtype);
144 resolv_response_close_record (b);
150 expected_result (unsigned port, unsigned response_number)
152 struct xmemstream mem;
153 xopen_memstream (&mem);
154 /* We fail the second TCP query to the first server by closing the
155 connection immediately, without returning any data. This should
156 cause failover to the second server. */
157 int server_index = 1;
158 fprintf (mem.out, "address: STREAM/TCP 10.%u.%u.%u %u\n",
159 (response_number >> 8) & 0xff, response_number & 0xff,
160 2 + 4 * server_index, port);
161 fprintf (mem.out, "address: STREAM/TCP 2001:db8::%x:%x %u\n",
162 (response_number + 1) & 0xffff,
163 2 + 4 * server_index, port);
164 xfclose_memstream (&mem);
169 test_different_sizes (void)
171 struct addrinfo hints =
173 .ai_family = AF_UNSPEC,
174 .ai_socktype = SOCK_STREAM,
175 .ai_protocol = IPPROTO_TCP,
181 /* This magic number produces a response size close to 2048
183 initial_address_count = 124;
186 ret = getaddrinfo ("www.example", "80", &hints, &ai);
187 expected = expected_result (80, 3);
188 check_addrinfo ("www.example:80", ai, ret, expected);
194 ret = getaddrinfo ("www123.example", "80", &hints, &ai);
199 ret = getaddrinfo ("www1234.example", "80", &hints, &ai);
204 ret = getaddrinfo ("www12345.example", "80", &hints, &ai);
212 struct resolv_test *obj = resolv_test_start
213 ((struct resolv_redirect_config)
215 .response_callback = response
218 test_different_sizes ();
220 _res.options |= RES_SNGLKUP;
221 test_different_sizes ();
223 _res.options |= RES_SNGLKUPREOP;
224 test_different_sizes ();
226 resolv_test_end (obj);
230 #include <support/test-driver.c>