]>
Commit | Line | Data |
---|---|---|
7f9f1ecb | 1 | /* Common code for AI_IDN/NI_IDN tests. |
04277e02 | 2 | Copyright (C) 2018-2019 Free Software Foundation, Inc. |
7f9f1ecb FW |
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 | <http://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. */ | |
73 | enum 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. */ | |
89 | static void | |
90 | response_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, qname, C_IN, T_PTR, 0); | |
102 | resolv_response_add_name (b, "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, qname, C_IN, T_CNAME, 0); | |
107 | next_name = "non-idn-cname.example"; | |
108 | resolv_response_add_name (b, next_name); | |
109 | resolv_response_close_record (b); | |
110 | resolv_response_open_record (b, next_name, C_IN, T_PTR, 0); | |
111 | resolv_response_add_name (b, "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, qname, C_IN, T_CNAME, 0); | |
116 | next_name = "non-idn-cname.example"; | |
117 | resolv_response_add_name (b, next_name); | |
118 | resolv_response_close_record (b); | |
119 | resolv_response_open_record (b, next_name, C_IN, T_PTR, 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, qname, C_IN, T_PTR, 0); | |
127 | resolv_response_add_name (b, "xn--nmchen-bua.example"); | |
128 | resolv_response_close_record (b); | |
129 | return; | |
130 | case gni_idn_shem: | |
131 | resolv_response_open_record (b, qname, C_IN, T_PTR, 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, qname, C_IN, T_PTR, 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, qname, C_IN, T_CNAME, 0); | |
142 | next_name = NAEMCHEN_IDNA ".example"; | |
143 | resolv_response_add_name (b, next_name); | |
144 | resolv_response_close_record (b); | |
145 | resolv_response_open_record (b, next_name, C_IN, T_PTR, 0); | |
146 | resolv_response_add_name (b, "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, qname, C_IN, T_CNAME, 0); | |
151 | next_name = NAEMCHEN_IDNA ".example"; | |
152 | resolv_response_add_name (b, next_name); | |
153 | resolv_response_close_record (b); | |
154 | resolv_response_open_record (b, next_name, C_IN, T_PTR, 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, qname, C_IN, T_PTR, 0); | |
162 | resolv_response_add_name (b, "xn---.example"); | |
163 | resolv_response_close_record (b); | |
164 | return; | |
165 | case gni_invalid_idn_2: | |
166 | resolv_response_open_record (b, qname, C_IN, T_PTR, 0); | |
167 | resolv_response_add_name (b, "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. */ | |
178 | static void | |
179 | response (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, qname, qclass, qtype); | |
195 | return; | |
196 | } | |
197 | ||
198 | struct resolv_response_flags flags = { 0 }; | |
199 | resolv_response_init (b, flags); | |
200 | resolv_response_add_question (b, qname, qclass, 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 (qname, ".cname.") != NULL; | |
210 | bool with_idn_cname = strstr (qname, ".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, qname, C_IN, T_CNAME, 0); | |
217 | resolv_response_add_name (b, next_name); | |
218 | resolv_response_close_record (b); | |
219 | } | |
220 | if (with_idn_cname) | |
221 | { | |
222 | next_name = ANDERES_NAEMCHEN_IDNA ".example"; | |
223 | resolv_response_open_record (b, qname, C_IN, T_CNAME, 0); | |
224 | resolv_response_add_name (b, next_name); | |
225 | resolv_response_close_record (b); | |
226 | } | |
227 | ||
228 | resolv_response_open_record (b, next_name, C_IN, qtype, 0); | |
229 | switch (qtype) | |
230 | { | |
231 | case T_A: | |
232 | { | |
233 | char addr[4] = { 192, 0, 2, qname[0] }; | |
234 | resolv_response_add_data (b, &addr, sizeof (addr)); | |
235 | } | |
236 | break; | |
237 | case T_AAAA: | |
238 | { | |
239 | char addr[16] | |
240 | = { 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | |
241 | qname[0] }; | |
242 | resolv_response_add_data (b, &addr, sizeof (addr)); | |
243 | } | |
5494af04 | 244 | break; |
7f9f1ecb FW |
245 | default: |
246 | FAIL_EXIT1 ("invalid qtype: %d", qtype); | |
247 | } | |
248 | resolv_response_close_record (b); | |
249 | } | |
250 | ||
251 | /* Check the result of a getaddrinfo call. */ | |
252 | static void | |
253 | check_ai (const char *name, int ai_flags, const char *expected) | |
254 | { | |
255 | struct addrinfo hints = | |
256 | { | |
257 | .ai_flags = ai_flags, | |
258 | .ai_family = AF_INET, | |
259 | .ai_socktype = SOCK_STREAM, | |
260 | }; | |
261 | struct addrinfo *ai; | |
262 | char *query = xasprintf ("%s:80 AF_INET/0x%x", name, ai_flags); | |
263 | int ret = getaddrinfo (name, "80", &hints, &ai); | |
264 | check_addrinfo (query, ai, ret, expected); | |
265 | if (ret == 0) | |
266 | freeaddrinfo (ai); | |
267 | free (query); | |
268 | } | |
269 | ||
270 | /* Run one getnameinfo test. FLAGS is automatically augmented with | |
271 | NI_NUMERICSERV. */ | |
272 | static void | |
273 | gni_test (enum gni_test code, unsigned int flags, const char *expected) | |
274 | { | |
275 | struct sockaddr_in sin = | |
276 | { | |
277 | .sin_family = AF_INET, | |
278 | .sin_port = htons (80), | |
279 | .sin_addr = { htonl (0xc0000200 | code) }, /* 192.0.2.0/24 network. */ | |
280 | }; | |
281 | char host[1024]; | |
282 | char service[1024]; | |
283 | int ret = getnameinfo ((const struct sockaddr *) &sin, sizeof (sin), | |
284 | host, sizeof (host), service, sizeof (service), | |
285 | flags| NI_NUMERICSERV); | |
286 | if (ret != 0) | |
287 | { | |
288 | if (expected == NULL) | |
289 | TEST_COMPARE (ret, EAI_IDN_ENCODE); | |
290 | else | |
291 | { | |
292 | support_record_failure (); | |
293 | printf ("error: getnameinfo failed (code %d, flags 0x%x): %s (%d)\n", | |
294 | (int) code, flags, gai_strerror (ret), ret); | |
295 | } | |
296 | } | |
297 | else if (ret == 0 && expected == NULL) | |
298 | { | |
299 | support_record_failure (); | |
300 | printf ("error: getnameinfo unexpected success (code %d, flags 0x%x)\n", | |
301 | (int) code, flags); | |
302 | } | |
303 | else if (strcmp (host, expected) != 0 || strcmp (service, "80") != 0) | |
304 | { | |
305 | support_record_failure (); | |
306 | printf ("error: getnameinfo test failure (code %d, flags 0x%x)\n" | |
307 | " expected host: \"%s\"\n" | |
308 | " expected service: \"80\"\n" | |
309 | " actual host: \"%s\"\n" | |
310 | " actual service: \"%s\"\n", | |
311 | (int) code, flags, expected, host, service); | |
312 | } | |
313 | } | |
314 | ||
315 | /* Tests for getaddrinfo which assume a working libidn2 library. */ | |
316 | __attribute__ ((unused)) | |
317 | static void | |
318 | gai_tests_with_libidn2 (void) | |
319 | { | |
320 | /* No CNAME. */ | |
321 | check_ai ("non-idn.example", 0, | |
322 | "address: STREAM/TCP 192.0.2.110 80\n"); | |
323 | check_ai ("non-idn.example", AI_IDN, | |
324 | "flags: AI_IDN\n" | |
325 | "address: STREAM/TCP 192.0.2.110 80\n"); | |
326 | check_ai ("non-idn.example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
327 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
328 | "canonname: non-idn.example\n" | |
329 | "address: STREAM/TCP 192.0.2.110 80\n"); | |
330 | ||
331 | check_ai (NAEMCHEN ".example", 0, | |
332 | "error: Name or service not known\n"); | |
333 | check_ai (NAEMCHEN ".example", AI_IDN, | |
334 | "flags: AI_IDN\n" | |
335 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
336 | check_ai (NAEMCHEN ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
337 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
338 | "canonname: " NAEMCHEN ".example\n" | |
339 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
340 | ||
341 | #if TEST_USE_UTF8 | |
342 | check_ai (SHEM ".example", 0, | |
343 | "error: Name or service not known\n"); | |
344 | check_ai (SHEM ".example", AI_IDN, | |
345 | "flags: AI_IDN\n" | |
346 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
347 | check_ai (SHEM ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
348 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
349 | "canonname: " SHEM ".example\n" | |
350 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
351 | check_ai (SHEM ".example", AI_IDN | AI_CANONNAME, | |
352 | "flags: AI_CANONNAME AI_IDN\n" | |
353 | "canonname: " SHEM_IDNA ".example\n" | |
354 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
355 | check_ai (SHEM "1.example", AI_IDN, | |
356 | "flags: AI_IDN\n" | |
357 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
358 | check_ai (SHEM "1.example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
359 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
360 | "canonname: " SHEM "1.example\n" | |
361 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
362 | check_ai (SHEM "1.example", AI_IDN | AI_CANONNAME, | |
363 | "flags: AI_CANONNAME AI_IDN\n" | |
364 | "canonname: " SHEM1_IDNA ".example\n" | |
365 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
366 | #endif | |
367 | ||
368 | /* Check that non-transitional mode is active. German sharp S | |
369 | should not turn into SS. */ | |
370 | check_ai (BUSSE ".example", 0, | |
371 | "error: Name or service not known\n"); | |
372 | check_ai (BUSSE ".example", AI_IDN, | |
373 | "flags: AI_IDN\n" | |
374 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
375 | check_ai (BUSSE ".example", AI_IDN | AI_CANONNAME, | |
376 | "flags: AI_CANONNAME AI_IDN\n" | |
377 | "canonname: " BUSSE_IDNA ".example\n" | |
378 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
379 | check_ai (BUSSE ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
380 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
381 | "canonname: " BUSSE ".example\n" | |
382 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
383 | ||
384 | /* Check that Unicode TR 46 mode is active. Underscores should be | |
385 | permitted in IDNA components. */ | |
386 | check_ai (NAEMCHEN "_zwo.example", 0, | |
387 | "error: Name or service not known\n"); | |
388 | check_ai (NAEMCHEN "_zwo.example", AI_IDN, | |
389 | "flags: AI_IDN\n" | |
390 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
391 | check_ai (NAEMCHEN "_zwo.example", AI_IDN | AI_CANONNAME, | |
392 | "flags: AI_CANONNAME AI_IDN\n" | |
393 | "canonname: " NAEMCHEN_ZWO_IDNA ".example\n" | |
394 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
395 | check_ai (NAEMCHEN "_zwo.example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
396 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
397 | "canonname: " NAEMCHEN "_zwo.example\n" | |
398 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
399 | ||
400 | /* No CNAME, but already IDN-encoded. */ | |
401 | check_ai (NAEMCHEN_IDNA ".example", 0, | |
402 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
403 | check_ai (NAEMCHEN_IDNA ".example", AI_IDN, | |
404 | "flags: AI_IDN\n" | |
405 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
406 | check_ai (NAEMCHEN_IDNA ".example", AI_IDN | AI_CANONNAME, | |
407 | "flags: AI_CANONNAME AI_IDN\n" | |
408 | "canonname: " NAEMCHEN_IDNA ".example\n" | |
409 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
410 | check_ai (NAEMCHEN_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
411 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
412 | "canonname: " NAEMCHEN ".example\n" | |
413 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
414 | check_ai (SHEM_IDNA ".example", 0, | |
415 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
416 | check_ai (SHEM_IDNA ".example", AI_IDN, | |
417 | "flags: AI_IDN\n" | |
418 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
419 | check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME, | |
420 | "flags: AI_CANONNAME AI_IDN\n" | |
421 | "canonname: " SHEM_IDNA ".example\n" | |
422 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
423 | #if TEST_USE_UTF8 | |
424 | check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
425 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
426 | "canonname: " SHEM ".example\n" | |
427 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
428 | #else | |
429 | check_ai (SHEM_IDNA ".example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
430 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
431 | "canonname: " SHEM_IDNA ".example\n" | |
432 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
433 | #endif | |
434 | ||
435 | /* Invalid IDNA canonical name is returned as-is. */ | |
436 | check_ai ("xn---.example", AI_CANONNAME | AI_CANONIDN, | |
437 | "flags: AI_CANONNAME AI_CANONIDN\n" | |
438 | "canonname: xn---.example\n" | |
439 | "address: STREAM/TCP 192.0.2.120 80\n"); | |
440 | ||
441 | /* Non-IDN CNAME. */ | |
442 | check_ai ("with.cname.example", 0, | |
443 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
444 | check_ai ("with.cname.example", AI_IDN, | |
445 | "flags: AI_IDN\n" | |
446 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
447 | check_ai ("with.cname.example", AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
448 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
449 | "canonname: non-idn-cname.example\n" | |
450 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
451 | ||
452 | check_ai ("with.cname." NAEMCHEN ".example", 0, | |
453 | "error: Name or service not known\n"); | |
454 | check_ai ("with.cname." NAEMCHEN ".example", AI_IDN, | |
455 | "flags: AI_IDN\n" | |
456 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
457 | check_ai ("with.cname." NAEMCHEN ".example", AI_IDN | AI_CANONNAME, | |
458 | "flags: AI_CANONNAME AI_IDN\n" | |
459 | "canonname: non-idn-cname.example\n" | |
460 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
461 | check_ai ("with.cname." NAEMCHEN ".example", | |
462 | AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
463 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
464 | "canonname: non-idn-cname.example\n" | |
465 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
466 | ||
467 | /* IDN CNAME. */ | |
468 | check_ai ("With.idn-cname.example", 0, | |
469 | "address: STREAM/TCP 192.0.2.87 80\n"); | |
470 | check_ai ("With.idn-cname.example", AI_IDN, | |
471 | "flags: AI_IDN\n" | |
472 | "address: STREAM/TCP 192.0.2.87 80\n"); | |
473 | check_ai ("With.idn-cname.example", AI_IDN | AI_CANONNAME, | |
474 | "flags: AI_CANONNAME AI_IDN\n" | |
475 | "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n" | |
476 | "address: STREAM/TCP 192.0.2.87 80\n"); | |
477 | check_ai ("With.idn-cname.example", | |
478 | AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
479 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
480 | "canonname: " ANDERES_NAEMCHEN ".example\n" | |
481 | "address: STREAM/TCP 192.0.2.87 80\n"); | |
482 | ||
483 | check_ai ("With.idn-cname." NAEMCHEN ".example", 0, | |
484 | "error: Name or service not known\n"); | |
485 | check_ai ("With.idn-cname." NAEMCHEN ".example", AI_IDN, | |
486 | "flags: AI_IDN\n" | |
487 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
488 | check_ai ("With.idn-cname." NAEMCHEN ".example", AI_IDN | AI_CANONNAME, | |
489 | "flags: AI_CANONNAME AI_IDN\n" | |
490 | "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n" | |
491 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
492 | check_ai ("With.idn-cname." NAEMCHEN ".example", | |
493 | AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
494 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
495 | "canonname: " ANDERES_NAEMCHEN ".example\n" | |
496 | "address: STREAM/TCP 192.0.2.119 80\n"); | |
497 | ||
498 | /* Non-IDN to IDN CNAME chain. */ | |
499 | check_ai ("both.cname.idn-cname.example", 0, | |
500 | "address: STREAM/TCP 192.0.2.98 80\n"); | |
501 | check_ai ("both.cname.idn-cname.example", AI_IDN, | |
502 | "flags: AI_IDN\n" | |
503 | "address: STREAM/TCP 192.0.2.98 80\n"); | |
504 | check_ai ("both.cname.idn-cname.example", AI_IDN | AI_CANONNAME, | |
505 | "flags: AI_CANONNAME AI_IDN\n" | |
506 | "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n" | |
507 | "address: STREAM/TCP 192.0.2.98 80\n"); | |
508 | check_ai ("both.cname.idn-cname.example", | |
509 | AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
510 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
511 | "canonname: " ANDERES_NAEMCHEN ".example\n" | |
512 | "address: STREAM/TCP 192.0.2.98 80\n"); | |
513 | ||
514 | check_ai ("both.cname.idn-cname." NAEMCHEN ".example", 0, | |
515 | "error: Name or service not known\n"); | |
516 | check_ai ("both.cname.idn-cname." NAEMCHEN ".example", AI_IDN, | |
517 | "flags: AI_IDN\n" | |
518 | "address: STREAM/TCP 192.0.2.98 80\n"); | |
519 | check_ai ("both.cname.idn-cname." NAEMCHEN ".example", | |
520 | AI_IDN | AI_CANONNAME, | |
521 | "flags: AI_CANONNAME AI_IDN\n" | |
522 | "canonname: " ANDERES_NAEMCHEN_IDNA ".example\n" | |
523 | "address: STREAM/TCP 192.0.2.98 80\n"); | |
524 | check_ai ("both.cname.idn-cname." NAEMCHEN ".example", | |
525 | AI_IDN | AI_CANONNAME | AI_CANONIDN, | |
526 | "flags: AI_CANONNAME AI_IDN AI_CANONIDN\n" | |
527 | "canonname: " ANDERES_NAEMCHEN ".example\n" | |
528 | "address: STREAM/TCP 192.0.2.98 80\n"); | |
529 | } | |
530 | ||
531 | /* Tests for getnameinfo which assume a working libidn2 library. */ | |
532 | __attribute__ ((unused)) | |
533 | static void | |
534 | gni_tests_with_libidn2 (void) | |
535 | { | |
536 | gni_test (gni_non_idn_name, 0, "non-idn.example"); | |
537 | gni_test (gni_non_idn_name, NI_IDN, "non-idn.example"); | |
538 | gni_test (gni_non_idn_name, NI_NUMERICHOST, "192.0.2.0"); | |
539 | gni_test (gni_non_idn_name, NI_NUMERICHOST | NI_IDN, "192.0.2.0"); | |
540 | ||
541 | gni_test (gni_non_idn_cname_to_non_idn_name, 0, "non-idn-name.example"); | |
542 | gni_test (gni_non_idn_cname_to_non_idn_name, NI_IDN, "non-idn-name.example"); | |
543 | ||
544 | gni_test (gni_non_idn_cname_to_idn_name, 0, NAEMCHEN_IDNA ".example"); | |
545 | gni_test (gni_non_idn_cname_to_idn_name, NI_IDN, NAEMCHEN ".example"); | |
546 | ||
547 | gni_test (gni_idn_name, 0, NAEMCHEN_IDNA ".example"); | |
548 | gni_test (gni_idn_name, NI_IDN, NAEMCHEN ".example"); | |
549 | gni_test (gni_idn_shem, 0, SHEM_IDNA ".example"); | |
550 | gni_test (gni_idn_shem1, 0, SHEM1_IDNA ".example"); | |
551 | #if TEST_USE_UTF8 | |
552 | gni_test (gni_idn_shem, NI_IDN, SHEM ".example"); | |
553 | gni_test (gni_idn_shem1, NI_IDN, SHEM "1.example"); | |
554 | #else | |
555 | gni_test (gni_idn_shem, NI_IDN, SHEM_IDNA ".example"); | |
556 | gni_test (gni_idn_shem1, NI_IDN, SHEM1_IDNA ".example"); | |
557 | #endif | |
558 | ||
559 | gni_test (gni_idn_cname_to_non_idn_name, 0, "non-idn-name.example"); | |
560 | gni_test (gni_idn_cname_to_non_idn_name, NI_IDN, "non-idn-name.example"); | |
561 | ||
562 | gni_test (gni_idn_cname_to_idn_name, 0, ANDERES_NAEMCHEN_IDNA ".example"); | |
563 | gni_test (gni_idn_cname_to_idn_name, NI_IDN, ANDERES_NAEMCHEN ".example"); | |
564 | ||
565 | /* Test encoding errors. */ | |
566 | gni_test (gni_invalid_idn_1, 0, "xn---.example"); | |
567 | gni_test (gni_invalid_idn_1, NI_IDN, "xn---.example"); | |
568 | gni_test (gni_invalid_idn_2, 0, "xn--x.example"); | |
569 | gni_test (gni_invalid_idn_2, NI_IDN, "xn--x.example"); | |
570 | } |