1/* Common code for AI_IDN/NI_IDN tests.
2 Copyright (C) 2018-2022 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
4
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.
9
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.
14
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 <https://www.gnu.org/licenses/>. */
18
19/* Before including this file, TEST_USE_UTF8 must be defined to 1 or
20 0, depending on whether a UTF-8 locale is used or a Latin-1
21 locale. */
22
23#include <stdio.h>
24#include <stdlib.h>
25#include <string.h>
26#include <support/check.h>
27#include <support/check_nss.h>
28#include <support/resolv_test.h>
29#include <support/support.h>
30
31/* Name of the shared object for libidn2. */
32#define LIBIDN2_SONAME "libidn2.so.0"
33
34#if TEST_USE_UTF8
35/* UTF-8 encoding of "nämchen" (German for “namelet”). */
36# define NAEMCHEN "n\xC3\xA4mchen"
37
38/* UTF-8 encoding of "שם" (Hebrew for “name”). */
39# define SHEM "\xD7\xA9\xD7\x9D"
40
41/* UTF-8 encoding of "buße" (German for “penance”). This used to be
42 encoded as "busse" (“busses”) in IDNA2003. */
43# define BUSSE "bu\xC3\x9F""e"
44
45#else
46/* Latin-1 encodings, as far as they are available. */
47
48# define NAEMCHEN "n\xE4mchen"
49# define BUSSE "bu\xDF""e"
50
51#endif
52
53/* IDNA encoding of NAEMCHEN. */
54#define NAEMCHEN_IDNA "xn--nmchen-bua"
55
56/* IDNA encoding of NAEMCHEN "_zwo". */
57#define NAEMCHEN_ZWO_IDNA "xn--nmchen_zwo-q5a"
58
59/* IDNA encoding of SHEM. */
60#define SHEM_IDNA "xn--iebx"
61
62/* IDNA encoding of BUSSE. */
63#define BUSSE_IDNA "xn--bue-6ka"
64
65/* IDNA encoding of "שם1". */
66#define SHEM1_IDNA "xn--1-qic9a"
67
68/* Another IDNA name. */
69#define ANDERES_NAEMCHEN "anderes-" NAEMCHEN
70#define ANDERES_NAEMCHEN_IDNA "xn--anderes-nmchen-eib"
71
72/* Controls the kind of test data in a PTR lookup response. */
73enum gni_test
74 {
75 gni_non_idn_name,
76 gni_non_idn_cname_to_non_idn_name,
77 gni_non_idn_cname_to_idn_name,
78 gni_idn_name,
79 gni_idn_shem,
80 gni_idn_shem1,
81 gni_idn_cname_to_non_idn_name,
82 gni_idn_cname_to_idn_name,
83 gni_invalid_idn_1,
84 gni_invalid_idn_2,
85 };
86
87/* Called from response below. The LSB (first byte) controls what
88 goes into the response, see enum gni_test. */
89static void
90response_ptr (const struct resolv_response_context *ctx,
91 struct resolv_response_builder *b, const char *qname)
92{
93 int comp[4] = { 0 };
94 TEST_COMPARE (sscanf (qname, "%d.%d.%d.%d.in-addr.arpa",
95 &comp[0], &comp[1], &comp[2], &comp[3]), 4);
96 const char *next_name;
97 switch ((enum gni_test) comp[0])
98 {
99 /* First name in response is non-IDN name. */
100 case gni_non_idn_name:
101 resolv_response_open_record (b, name: qname, C_IN, T_PTR, ttl: 0);
102 resolv_response_add_name (b, name: "non-idn.example");
103 resolv_response_close_record (b);
104 return;
105 case gni_non_idn_cname_to_non_idn_name:
106 resolv_response_open_record (b, name: qname, C_IN, T_CNAME, ttl: 0);
107 next_name = "non-idn-cname.example";
108 resolv_response_add_name (b, name: next_name);
109 resolv_response_close_record (b);
110 resolv_response_open_record (b, name: next_name, C_IN, T_PTR, ttl: 0);
111 resolv_response_add_name (b, name: "non-idn-name.example");
112 resolv_response_close_record (b);
113 return;
114 case gni_non_idn_cname_to_idn_name:
115 resolv_response_open_record (b, name: qname, C_IN, T_CNAME, ttl: 0);
116 next_name = "non-idn-cname.example";
117 resolv_response_add_name (b, name: next_name);
118 resolv_response_close_record (b);
119 resolv_response_open_record (b, name: next_name, C_IN, T_PTR, ttl: 0);
120 resolv_response_add_name (b, NAEMCHEN_IDNA ".example");
121 resolv_response_close_record (b);
122 return;
123
124 /* First name in response is IDN name. */
125 case gni_idn_name:
126 resolv_response_open_record (b, name: qname, C_IN, T_PTR, ttl: 0);
127 resolv_response_add_name (b, name: "xn--nmchen-bua.example");
128 resolv_response_close_record (b);
129 return;
130 case gni_idn_shem:
131 resolv_response_open_record (b, name: qname, C_IN, T_PTR, ttl: 0);
132 resolv_response_add_name (b, SHEM_IDNA ".example");
133 resolv_response_close_record (b);
134 return;
135 case gni_idn_shem1:
136 resolv_response_open_record (b, name: qname, C_IN, T_PTR, ttl: 0);
137 resolv_response_add_name (b, SHEM1_IDNA ".example");
138 resolv_response_close_record (b);
139 return;
140 case gni_idn_cname_to_non_idn_name:
141 resolv_response_open_record (b, name: qname, C_IN, T_CNAME, ttl: 0);
142 next_name = NAEMCHEN_IDNA ".example";
143 resolv_response_add_name (b, name: next_name);
144 resolv_response_close_record (b);
145 resolv_response_open_record (b, name: next_name, C_IN, T_PTR, ttl: 0);
146 resolv_response_add_name (b, name: "non-idn-name.example");
147 resolv_response_close_record (b);
148 return;
149 case gni_idn_cname_to_idn_name:
150 resolv_response_open_record (b, name: qname, C_IN, T_CNAME, ttl: 0);
151 next_name = NAEMCHEN_IDNA ".example";
152 resolv_response_add_name (b, name: next_name);
153 resolv_response_close_record (b);
154 resolv_response_open_record (b, name: next_name, C_IN, T_PTR, ttl: 0);
155 resolv_response_add_name (b, ANDERES_NAEMCHEN_IDNA ".example");
156 resolv_response_close_record (b);
157 return;
158
159 /* Invalid IDN encodings. */
160 case gni_invalid_idn_1:
161 resolv_response_open_record (b, name: qname, C_IN, T_PTR, ttl: 0);
162 resolv_response_add_name (b, name: "xn---.example");
163 resolv_response_close_record (b);
164 return;
165 case gni_invalid_idn_2:
166 resolv_response_open_record (b, name: qname, C_IN, T_PTR, ttl: 0);
167 resolv_response_add_name (b, name: "xn--x.example");
168 resolv_response_close_record (b);
169 return;
170 }
171 FAIL_EXIT1 ("invalid PTR query: %s", qname);
172}
173
174/* For PTR responses, see above. A/AAAA queries can request
175 additional CNAMEs in the response by include ".cname." and
176 ".idn-cname." in the query. The LSB in the address contains the
177 first byte of the QNAME. */
178static void
179response (const struct resolv_response_context *ctx,
180 struct resolv_response_builder *b,
181 const char *qname, uint16_t qclass, uint16_t qtype)
182{
183 TEST_VERIFY_EXIT (qclass == C_IN);
184
185 for (const char *p = qname; *p != '\0'; ++p)
186 if (!(('0' <= *p && *p <= '9')
187 || ('a' <= *p && *p <= 'z')
188 || ('A' <= *p && *p <= 'Z')
189 || *p == '.' || *p == '-' || *p == '_'))
190 {
191 /* Non-ASCII query. Reply with NXDOMAIN. */
192 struct resolv_response_flags flags = { .rcode = 3 };
193 resolv_response_init (b, flags);
194 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
195 return;
196 }
197
198 struct resolv_response_flags flags = { 0 };
199 resolv_response_init (b, flags);
200 resolv_response_add_question (b, name: qname, class: qclass, type: qtype);
201 resolv_response_section (b, ns_s_an);
202
203 if (qtype == T_PTR)
204 {
205 response_ptr (ctx, b, qname);
206 return;
207 }
208
209 bool with_cname = strstr (haystack: qname, needle: ".cname.") != NULL;
210 bool with_idn_cname = strstr (haystack: qname, needle: ".idn-cname.") != NULL;
211
212 const char *next_name = qname;
213 if (with_cname)
214 {
215 next_name = "non-idn-cname.example";
216 resolv_response_open_record (b, name: qname, C_IN, T_CNAME, ttl: 0);
217 resolv_response_add_name (b, name: next_name);
218 resolv_response_close_record (b);
219 }
220 if (with_idn_cname)
221 {
222 const char *previous_name = next_name;
223 next_name = ANDERES_NAEMCHEN_IDNA ".example";
224 resolv_response_open_record (b, name: previous_name, C_IN, T_CNAME, ttl: 0);
225 resolv_response_add_name (b, name: next_name);
226 resolv_response_close_record (b);
227 }
228
229 resolv_response_open_record (b, name: next_name, C_IN, type: qtype, ttl: 0);
230 switch (qtype)
231 {
232 case T_A:
233 {
234 char addr[4] = { 192, 0, 2, qname[0] };
235 resolv_response_add_data (b, &addr, sizeof (addr));
236 }
237 break;
238 case T_AAAA:
239 {
240 char addr[16]
241 = { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
242 qname[0] };
243 resolv_response_add_data (b, &addr, sizeof (addr));
244 }
245 break;
246 default:
247 FAIL_EXIT1 ("invalid qtype: %d", qtype);
248 }
249 resolv_response_close_record (b);
250}
251
252/* Check the result of a getaddrinfo call. */
253static void
254check_ai (const char *name, int ai_flags, const char *expected)
255{
256 struct addrinfo hints =
257 {
258 .ai_flags = ai_flags,
259 .ai_family = AF_INET,
260 .ai_socktype = SOCK_STREAM,
261 };
262 struct addrinfo *ai;
263 char *query = xasprintf (format: "%s:80 AF_INET/0x%x", name, ai_flags);
264 int ret = getaddrinfo (name: name, service: "80", req: &hints, pai: &ai);
265 check_addrinfo (query_description: query, ai, ret, expected);
266 if (ret == 0)
267 freeaddrinfo (ai: ai);
268 free (ptr: query);
269}
270
271/* Run one getnameinfo test. FLAGS is automatically augmented with
272 NI_NUMERICSERV. */
273static void
274gni_test (enum gni_test code, unsigned int flags, const char *expected)
275{
276 struct sockaddr_in sin =
277 {
278 .sin_family = AF_INET,
279 .sin_port = htons (80),
280 .sin_addr = { htonl (0xc0000200 | code) }, /* 192.0.2.0/24 network. */
281 };
282 char host[1024];
283 char service[1024];
284 int ret = getnameinfo (sa: (const struct sockaddr *) &sin, salen: sizeof (sin),
285 host: host, hostlen: sizeof (host), serv: service, servlen: sizeof (service),
286 flags: flags| NI_NUMERICSERV);
287 if (ret != 0)
288 {
289 if (expected == NULL)
290 TEST_COMPARE (ret, EAI_IDN_ENCODE);
291 else
292 {
293 support_record_failure ();
294 printf (format: "error: getnameinfo failed (code %d, flags 0x%x): %s (%d)\n",
295 (int) code, flags, gai_strerror (ecode: ret), ret);
296 }
297 }
298 else if (ret == 0 && expected == NULL)
299 {
300 support_record_failure ();
301 printf (format: "error: getnameinfo unexpected success (code %d, flags 0x%x)\n",
302 (int) code, flags);
303 }
304 else if (strcmp (s1: host, s2: expected) != 0 || strcmp (s1: service, s2: "80") != 0)
305 {
306 support_record_failure ();
307 printf (format: "error: getnameinfo test failure (code %d, flags 0x%x)\n"
308 " expected host: \"%s\"\n"
309 " expected service: \"80\"\n"
310 " actual host: \"%s\"\n"
311 " actual service: \"%s\"\n",
312 (int) code, flags, expected, host, service);
313 }
314}
315
316/* Tests for getaddrinfo which assume a working libidn2 library. */
317__attribute__ ((unused))
318static void
319gai_tests_with_libidn2 (void)
320{
321 /* No CNAME. */
322 check_ai (name: "non-idn.example", ai_flags: 0,
323 expected: "address: STREAM/TCP 192.0.2.110 80\n");
324 check_ai (name: "non-idn.example", AI_IDN,
325 expected: "flags: AI_IDN\n"
326 "address: STREAM/TCP 192.0.2.110 80\n");
327 check_ai (name: "non-idn.example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
328 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
329 "canonname: non-idn.example\n"
330 "address: STREAM/TCP 192.0.2.110 80\n");
331
332 check_ai (NAEMCHEN ".example", ai_flags: 0,
333 expected: "error: Name or service not known\n");
334 check_ai (NAEMCHEN ".example", AI_IDN,
335 expected: "flags: AI_IDN\n"
336 "address: STREAM/TCP 192.0.2.120 80\n");
337 check_ai (NAEMCHEN ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
338 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
339 "canonname: " NAEMCHEN ".example\n"
340 "address: STREAM/TCP 192.0.2.120 80\n");
341
342#if TEST_USE_UTF8
343 check_ai (SHEM ".example", 0,
344 "error: Name or service not known\n");
345 check_ai (SHEM ".example", AI_IDN,
346 "flags: AI_IDN\n"
347 "address: STREAM/TCP 192.0.2.120 80\n");
348 check_ai (SHEM ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
349 "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
350 "canonname: " SHEM ".example\n"
351 "address: STREAM/TCP 192.0.2.120 80\n");
352 check_ai (SHEM ".example", AI_IDN | AI_CANONNAME,
353 "flags: AI_CANONNAME AI_IDN\n"
354 "canonname: " SHEM_IDNA ".example\n"
355 "address: STREAM/TCP 192.0.2.120 80\n");
356 check_ai (SHEM "1.example", AI_IDN,
357 "flags: AI_IDN\n"
358 "address: STREAM/TCP 192.0.2.120 80\n");
359 check_ai (SHEM "1.example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
360 "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
361 "canonname: " SHEM "1.example\n"
362 "address: STREAM/TCP 192.0.2.120 80\n");
363 check_ai (SHEM "1.example", AI_IDN | AI_CANONNAME,
364 "flags: AI_CANONNAME AI_IDN\n"
365 "canonname: " SHEM1_IDNA ".example\n"
366 "address: STREAM/TCP 192.0.2.120 80\n");
367#endif
368
369 /* Check that non-transitional mode is active. German sharp S
370 should not turn into SS. */
371 check_ai (BUSSE ".example", ai_flags: 0,
372 expected: "error: Name or service not known\n");
373 check_ai (BUSSE ".example", AI_IDN,
374 expected: "flags: AI_IDN\n"
375 "address: STREAM/TCP 192.0.2.120 80\n");
376 check_ai (BUSSE ".example", AI_IDN | AI_CANONNAME,
377 expected: "flags: AI_CANONNAME AI_IDN\n"
378 "canonname: " BUSSE_IDNA ".example\n"
379 "address: STREAM/TCP 192.0.2.120 80\n");
380 check_ai (BUSSE ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
381 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
382 "canonname: " BUSSE ".example\n"
383 "address: STREAM/TCP 192.0.2.120 80\n");
384
385 /* Check that Unicode TR 46 mode is active. Underscores should be
386 permitted in IDNA components. */
387 check_ai (NAEMCHEN "_zwo.example", ai_flags: 0,
388 expected: "error: Name or service not known\n");
389 check_ai (NAEMCHEN "_zwo.example", AI_IDN,
390 expected: "flags: AI_IDN\n"
391 "address: STREAM/TCP 192.0.2.120 80\n");
392 check_ai (NAEMCHEN "_zwo.example", AI_IDN | AI_CANONNAME,
393 expected: "flags: AI_CANONNAME AI_IDN\n"
394 "canonname: " NAEMCHEN_ZWO_IDNA ".example\n"
395 "address: STREAM/TCP 192.0.2.120 80\n");
396 check_ai (NAEMCHEN "_zwo.example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
397 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
398 "canonname: " NAEMCHEN "_zwo.example\n"
399 "address: STREAM/TCP 192.0.2.120 80\n");
400
401 /* No CNAME, but already IDN-encoded. */
402 check_ai (NAEMCHEN_IDNA ".example", ai_flags: 0,
403 expected: "address: STREAM/TCP 192.0.2.120 80\n");
404 check_ai (NAEMCHEN_IDNA ".example", AI_IDN,
405 expected: "flags: AI_IDN\n"
406 "address: STREAM/TCP 192.0.2.120 80\n");
407 check_ai (NAEMCHEN_IDNA ".example", AI_IDN | AI_CANONNAME,
408 expected: "flags: AI_CANONNAME AI_IDN\n"
409 "canonname: " NAEMCHEN_IDNA ".example\n"
410 "address: STREAM/TCP 192.0.2.120 80\n");
411 check_ai (NAEMCHEN_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
412 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
413 "canonname: " NAEMCHEN ".example\n"
414 "address: STREAM/TCP 192.0.2.120 80\n");
415 check_ai (SHEM_IDNA ".example", ai_flags: 0,
416 expected: "address: STREAM/TCP 192.0.2.120 80\n");
417 check_ai (SHEM_IDNA ".example", AI_IDN,
418 expected: "flags: AI_IDN\n"
419 "address: STREAM/TCP 192.0.2.120 80\n");
420 check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME,
421 expected: "flags: AI_CANONNAME AI_IDN\n"
422 "canonname: " SHEM_IDNA ".example\n"
423 "address: STREAM/TCP 192.0.2.120 80\n");
424#if TEST_USE_UTF8
425 check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
426 "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
427 "canonname: " SHEM ".example\n"
428 "address: STREAM/TCP 192.0.2.120 80\n");
429#else
430 check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
431 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
432 "canonname: " SHEM_IDNA ".example\n"
433 "address: STREAM/TCP 192.0.2.120 80\n");
434#endif
435
436 /* Invalid IDNA canonical name is returned as-is. */
437 check_ai (name: "xn---.example", AI_CANONNAME | AI_CANONIDN,
438 expected: "flags: AI_CANONNAME AI_CANONIDN\n"
439 "canonname: xn---.example\n"
440 "address: STREAM/TCP 192.0.2.120 80\n");
441
442 /* Non-IDN CNAME. */
443 check_ai (name: "with.cname.example", ai_flags: 0,
444 expected: "address: STREAM/TCP 192.0.2.119 80\n");
445 check_ai (name: "with.cname.example", AI_IDN,
446 expected: "flags: AI_IDN\n"
447 "address: STREAM/TCP 192.0.2.119 80\n");
448 check_ai (name: "with.cname.example", AI_IDN | AI_CANONNAME | AI_CANONIDN,
449 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
450 "canonname: non-idn-cname.example\n"
451 "address: STREAM/TCP 192.0.2.119 80\n");
452
453 check_ai (name: "with.cname." NAEMCHEN ".example", ai_flags: 0,
454 expected: "error: Name or service not known\n");
455 check_ai (name: "with.cname." NAEMCHEN ".example", AI_IDN,
456 expected: "flags: AI_IDN\n"
457 "address: STREAM/TCP 192.0.2.119 80\n");
458 check_ai (name: "with.cname." NAEMCHEN ".example", AI_IDN | AI_CANONNAME,
459 expected: "flags: AI_CANONNAME AI_IDN\n"
460 "canonname: non-idn-cname.example\n"
461 "address: STREAM/TCP 192.0.2.119 80\n");
462 check_ai (name: "with.cname." NAEMCHEN ".example",
463 AI_IDN | AI_CANONNAME | AI_CANONIDN,
464 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
465 "canonname: non-idn-cname.example\n"
466 "address: STREAM/TCP 192.0.2.119 80\n");
467
468 /* IDN CNAME. */
469 check_ai (name: "With.idn-cname.example", ai_flags: 0,
470 expected: "address: STREAM/TCP 192.0.2.87 80\n");
471 check_ai (name: "With.idn-cname.example", AI_IDN,
472 expected: "flags: AI_IDN\n"
473 "address: STREAM/TCP 192.0.2.87 80\n");
474 check_ai (name: "With.idn-cname.example", AI_IDN | AI_CANONNAME,
475 expected: "flags: AI_CANONNAME AI_IDN\n"
476 "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n"
477 "address: STREAM/TCP 192.0.2.87 80\n");
478 check_ai (name: "With.idn-cname.example",
479 AI_IDN | AI_CANONNAME | AI_CANONIDN,
480 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
481 "canonname: " ANDERES_NAEMCHEN ".example\n"
482 "address: STREAM/TCP 192.0.2.87 80\n");
483
484 check_ai (name: "With.idn-cname." NAEMCHEN ".example", ai_flags: 0,
485 expected: "error: Name or service not known\n");
486 check_ai (name: "With.idn-cname." NAEMCHEN ".example", AI_IDN,
487 expected: "flags: AI_IDN\n"
488 "address: STREAM/TCP 192.0.2.119 80\n");
489 check_ai (name: "With.idn-cname." NAEMCHEN ".example", AI_IDN | AI_CANONNAME,
490 expected: "flags: AI_CANONNAME AI_IDN\n"
491 "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n"
492 "address: STREAM/TCP 192.0.2.119 80\n");
493 check_ai (name: "With.idn-cname." NAEMCHEN ".example",
494 AI_IDN | AI_CANONNAME | AI_CANONIDN,
495 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
496 "canonname: " ANDERES_NAEMCHEN ".example\n"
497 "address: STREAM/TCP 192.0.2.119 80\n");
498
499 /* Non-IDN to IDN CNAME chain. */
500 check_ai (name: "both.cname.idn-cname.example", ai_flags: 0,
501 expected: "address: STREAM/TCP 192.0.2.98 80\n");
502 check_ai (name: "both.cname.idn-cname.example", AI_IDN,
503 expected: "flags: AI_IDN\n"
504 "address: STREAM/TCP 192.0.2.98 80\n");
505 check_ai (name: "both.cname.idn-cname.example", AI_IDN | AI_CANONNAME,
506 expected: "flags: AI_CANONNAME AI_IDN\n"
507 "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n"
508 "address: STREAM/TCP 192.0.2.98 80\n");
509 check_ai (name: "both.cname.idn-cname.example",
510 AI_IDN | AI_CANONNAME | AI_CANONIDN,
511 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
512 "canonname: " ANDERES_NAEMCHEN ".example\n"
513 "address: STREAM/TCP 192.0.2.98 80\n");
514
515 check_ai (name: "both.cname.idn-cname." NAEMCHEN ".example", ai_flags: 0,
516 expected: "error: Name or service not known\n");
517 check_ai (name: "both.cname.idn-cname." NAEMCHEN ".example", AI_IDN,
518 expected: "flags: AI_IDN\n"
519 "address: STREAM/TCP 192.0.2.98 80\n");
520 check_ai (name: "both.cname.idn-cname." NAEMCHEN ".example",
521 AI_IDN | AI_CANONNAME,
522 expected: "flags: AI_CANONNAME AI_IDN\n"
523 "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n"
524 "address: STREAM/TCP 192.0.2.98 80\n");
525 check_ai (name: "both.cname.idn-cname." NAEMCHEN ".example",
526 AI_IDN | AI_CANONNAME | AI_CANONIDN,
527 expected: "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n"
528 "canonname: " ANDERES_NAEMCHEN ".example\n"
529 "address: STREAM/TCP 192.0.2.98 80\n");
530}
531
532/* Tests for getnameinfo which assume a working libidn2 library. */
533__attribute__ ((unused))
534static void
535gni_tests_with_libidn2 (void)
536{
537 gni_test (code: gni_non_idn_name, flags: 0, expected: "non-idn.example");
538 gni_test (code: gni_non_idn_name, NI_IDN, expected: "non-idn.example");
539 gni_test (code: gni_non_idn_name, NI_NUMERICHOST, expected: "192.0.2.0");
540 gni_test (code: gni_non_idn_name, NI_NUMERICHOST | NI_IDN, expected: "192.0.2.0");
541
542 gni_test (code: gni_non_idn_cname_to_non_idn_name, flags: 0, expected: "non-idn-name.example");
543 gni_test (code: gni_non_idn_cname_to_non_idn_name, NI_IDN, expected: "non-idn-name.example");
544
545 gni_test (code: gni_non_idn_cname_to_idn_name, flags: 0, NAEMCHEN_IDNA ".example");
546 gni_test (code: gni_non_idn_cname_to_idn_name, NI_IDN, NAEMCHEN ".example");
547
548 gni_test (code: gni_idn_name, flags: 0, NAEMCHEN_IDNA ".example");
549 gni_test (code: gni_idn_name, NI_IDN, NAEMCHEN ".example");
550 gni_test (code: gni_idn_shem, flags: 0, SHEM_IDNA ".example");
551 gni_test (code: gni_idn_shem1, flags: 0, SHEM1_IDNA ".example");
552#if TEST_USE_UTF8
553 gni_test (gni_idn_shem, NI_IDN, SHEM ".example");
554 gni_test (gni_idn_shem1, NI_IDN, SHEM "1.example");
555#else
556 gni_test (code: gni_idn_shem, NI_IDN, SHEM_IDNA ".example");
557 gni_test (code: gni_idn_shem1, NI_IDN, SHEM1_IDNA ".example");
558#endif
559
560 gni_test (code: gni_idn_cname_to_non_idn_name, flags: 0, expected: "non-idn-name.example");
561 gni_test (code: gni_idn_cname_to_non_idn_name, NI_IDN, expected: "non-idn-name.example");
562
563 gni_test (code: gni_idn_cname_to_idn_name, flags: 0, ANDERES_NAEMCHEN_IDNA ".example");
564 gni_test (code: gni_idn_cname_to_idn_name, NI_IDN, ANDERES_NAEMCHEN ".example");
565
566 /* Test encoding errors. */
567 gni_test (code: gni_invalid_idn_1, flags: 0, expected: "xn---.example");
568 gni_test (code: gni_invalid_idn_1, NI_IDN, expected: "xn---.example");
569 gni_test (code: gni_invalid_idn_2, flags: 0, expected: "xn--x.example");
570 gni_test (code: gni_invalid_idn_2, NI_IDN, expected: "xn--x.example");
571}
572

source code of glibc/resolv/tst-resolv-ai_idn-common.c