From 85cfe508568530eed2d9cfd34110c21721d1f99e Mon Sep 17 00:00:00 2001 From: Florian Weimer Date: Wed, 6 Sep 2017 13:43:01 +0200 Subject: [PATCH 28] tst-res_use_inet6: Enhance test to cover IPv4-to-IPv6 address mapping This requires more control over the response data, so it is now determined by flags embedded in the query name. (cherry picked from commit 5e9c4d17feb9910f489ad2915d0b6e00597a0f11) --- ChangeLog | 12 +++ resolv/tst-res_use_inet6.c | 231 ++++++++++++++++++++++++++++++++++++--------- 2 files changed, 198 insertions(+), 45 deletions(-) diff --git a/ChangeLog b/ChangeLog index 3e32d14dbf..dd71f6c427 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2017-09-06 Florian Weimer + + Enhance tst-res_use_inet6 to test IPv4-to-IPv6 address mapping. + * resolv/tst-res_use_inet6.c (response): Process flags embedded in + the QNAME. + (test_gai): Adjust query names. Add additional tests. + (test_get2_any, test_get2_no_inet6, test_get2_inet6): Split from + test_get2. Adjust query names. Add additional tests. + (test_no_inet6): New function, extracted from threadfunc. + (threadfunc): Call test_get2_any, test_get2_inet6, test_no_inet6. + Add additional tests. + 2017-09-01 Florian Weimer [BZ #21915] diff --git a/resolv/tst-res_use_inet6.c b/resolv/tst-res_use_inet6.c index 6f3db08892..1522d5c5f5 100644 --- a/resolv/tst-res_use_inet6.c +++ b/resolv/tst-res_use_inet6.c @@ -19,18 +19,44 @@ #include #include #include +#include #include #include #include +/* Produce a response based on QNAME: Certain characters in the first + label of QNAME trigger the inclusion of resource records: + + 'a' A record (IPv4 address) + 'q' AAAA record (quad A record, IPv6 address) + 'm' record type must match QTYPE (no additional records) + + QTYPE is ignored for record type selection if 'm' is not + specified. */ static void response (const struct resolv_response_context *ctx, struct resolv_response_builder *b, const char *qname, uint16_t qclass, uint16_t qtype) { - bool include_both = strcmp (qname, "both.example") == 0; - bool include_a = qtype == T_A || include_both; - bool include_aaaa = qtype == T_AAAA || include_both; + bool include_a = false; + bool include_aaaa = false; + bool include_match = false; + for (const char *p = qname; *p != '.' && *p != '\0'; ++p) + { + if (*p == 'a') + include_a = true; + else if (*p == 'q') + include_aaaa = true; + else if (*p == 'm') + include_match = true; + } + if (include_match) + { + if (qtype == T_A) + include_aaaa = false; + else if (qtype == T_AAAA) + include_a = false; + } resolv_response_init (b, (struct resolv_response_flags) {}); resolv_response_add_question (b, qname, qclass, qtype); @@ -64,16 +90,21 @@ test_gai (void) .ai_protocol = IPPROTO_TCP, }; struct addrinfo *ai; - int ret = getaddrinfo ("www1.example", "80", &hints, &ai); - check_addrinfo ("getaddrinfo AF_UNSPEC www1.example", ai, ret, + int ret = getaddrinfo ("qam.example", "80", &hints, &ai); + check_addrinfo ("getaddrinfo AF_UNSPEC qam.example", ai, ret, "address: STREAM/TCP 192.0.2.17 80\n" "address: STREAM/TCP 2001:db8::1 80\n"); if (ret == 0) freeaddrinfo (ai); - ret = getaddrinfo ("both.example", "80", &hints, &ai); + ret = getaddrinfo ("am.example", "80", &hints, &ai); + check_addrinfo ("getaddrinfo AF_UNSPEC am.example", ai, ret, + "address: STREAM/TCP 192.0.2.17 80\n"); + if (ret == 0) + freeaddrinfo (ai); + ret = getaddrinfo ("qa.example", "80", &hints, &ai); /* Combined A/AAAA responses currently result in address duplication. */ - check_addrinfo ("getaddrinfo AF_UNSPEC both.example", ai, ret, + check_addrinfo ("getaddrinfo AF_UNSPEC qa.example", ai, ret, "address: STREAM/TCP 192.0.2.17 80\n" "address: STREAM/TCP 192.0.2.17 80\n" "address: STREAM/TCP 2001:db8::1 80\n" @@ -89,13 +120,18 @@ test_gai (void) .ai_protocol = IPPROTO_TCP, }; struct addrinfo *ai; - int ret = getaddrinfo ("www1.example", "80", &hints, &ai); - check_addrinfo ("getaddrinfo AF_INET www1.example", ai, ret, + int ret = getaddrinfo ("qam.example", "80", &hints, &ai); + check_addrinfo ("getaddrinfo AF_INET qam.example", ai, ret, + "address: STREAM/TCP 192.0.2.17 80\n"); + if (ret == 0) + freeaddrinfo (ai); + ret = getaddrinfo ("am.example", "80", &hints, &ai); + check_addrinfo ("getaddrinfo AF_INET am.example", ai, ret, "address: STREAM/TCP 192.0.2.17 80\n"); if (ret == 0) freeaddrinfo (ai); - ret = getaddrinfo ("both.example", "80", &hints, &ai); - check_addrinfo ("getaddrinfo AF_INET both.example", ai, ret, + ret = getaddrinfo ("qa.example", "80", &hints, &ai); + check_addrinfo ("getaddrinfo AF_INET qa.example", ai, ret, "address: STREAM/TCP 192.0.2.17 80\n"); if (ret == 0) freeaddrinfo (ai); @@ -108,40 +144,131 @@ test_gai (void) .ai_protocol = IPPROTO_TCP, }; struct addrinfo *ai; - int ret = getaddrinfo ("www1.example", "80", &hints, &ai); + int ret = getaddrinfo ("qa.example", "80", &hints, &ai); check_addrinfo ("getaddrinfo (AF_INET6)", ai, ret, "address: STREAM/TCP 2001:db8::1 80\n"); if (ret == 0) freeaddrinfo (ai); - ret = getaddrinfo ("both.example", "80", &hints, &ai); - check_addrinfo ("getaddrinfo AF_INET6 both.example", ai, ret, + ret = getaddrinfo ("am.example", "80", &hints, &ai); + check_addrinfo ("getaddrinfo AF_INET6 am.example", ai, ret, + "error: No address associated with hostname\n"); + if (ret == 0) + freeaddrinfo (ai); + ret = getaddrinfo ("qam.example", "80", &hints, &ai); + check_addrinfo ("getaddrinfo AF_INET6 qam.example", ai, ret, "address: STREAM/TCP 2001:db8::1 80\n"); if (ret == 0) freeaddrinfo (ai); } } -/* Test that gethostbyname2 is not influenced by RES_USE_INET6. */ +/* Test that gethostbyname2 is mostly not influenced by + RES_USE_INET6. */ static void -test_get2 (void) +test_get2_any (void) { - check_hostent ("gethostbyname2 AF_INET www1.example", - gethostbyname2 ("www1.example", AF_INET), - "name: www1.example\n" + check_hostent ("gethostbyname2 AF_INET am.example", + gethostbyname2 ("am.example", AF_INET), + "name: am.example\n" "address: 192.0.2.17\n"); - check_hostent ("gethostbyname2 AF_INET both.example", - gethostbyname2 ("both.example", AF_INET), - "name: both.example\n" + check_hostent ("gethostbyname2 AF_INET a.example", + gethostbyname2 ("a.example", AF_INET), + "name: a.example\n" + "address: 192.0.2.17\n"); + check_hostent ("gethostbyname2 AF_INET qm.example", + gethostbyname2 ("qm.example", AF_INET), + "error: NO_ADDRESS\n"); + check_hostent ("gethostbyname2 AF_INET q.example", + gethostbyname2 ("q.example", AF_INET), + "error: NO_RECOVERY\n"); + check_hostent ("gethostbyname2 AF_INET qam.example", + gethostbyname2 ("qam.example", AF_INET), + "name: qam.example\n" + "address: 192.0.2.17\n"); + check_hostent ("gethostbyname2 AF_INET qa.example", + gethostbyname2 ("qa.example", AF_INET), + "name: qa.example\n" "address: 192.0.2.17\n"); - check_hostent ("gethostbyname2 AF_INET6 www1.example", - gethostbyname2 ("www1.example", AF_INET6), - "name: www1.example\n" + check_hostent ("gethostbyname2 AF_INET6 qm.example", + gethostbyname2 ("qm.example", AF_INET6), + "name: qm.example\n" + "address: 2001:db8::1\n"); + check_hostent ("gethostbyname2 AF_INET6 q.example", + gethostbyname2 ("q.example", AF_INET6), + "name: q.example\n" "address: 2001:db8::1\n"); - check_hostent ("gethostbyname2 AF_INET6 both.example", - gethostbyname2 ("both.example", AF_INET6), - "name: both.example\n" + check_hostent ("gethostbyname2 AF_INET6 qam.example", + gethostbyname2 ("qam.example", AF_INET6), + "name: qam.example\n" "address: 2001:db8::1\n"); + check_hostent ("gethostbyname2 AF_INET6 qa.example", + gethostbyname2 ("qa.example", AF_INET6), + "name: qa.example\n" + "address: 2001:db8::1\n"); + /* Additional AF_INET6 tests depend on RES_USE_INET6; see below. */ +} + +/* gethostbyname2 tests with RES_USE_INET6 disabled. */ +static void +test_get2_no_inet6 (void) +{ + test_get2_any (); + + check_hostent ("gethostbyname2 AF_INET6 am.example", + gethostbyname2 ("am.example", AF_INET6), + "error: NO_ADDRESS\n"); + check_hostent ("gethostbyname2 AF_INET6 a.example", + gethostbyname2 ("a.example", AF_INET6), + "error: NO_RECOVERY\n"); +} + +/* gethostbyname2 tests with RES_USE_INET6 enabled. */ +static void +test_get2_inet6 (void) +{ + test_get2_any (); + + check_hostent ("gethostbyname2 AF_INET6 am.example", + gethostbyname2 ("am.example", AF_INET6), + "name: am.example\n" + "address: ::ffff:192.0.2.17\n"); + check_hostent ("gethostbyname2 AF_INET6 a.example", + gethostbyname2 ("a.example", AF_INET6), + "error: NO_RECOVERY\n"); +} + +/* Collection of tests which assume no RES_USE_INET6 flag. */ +static void +test_no_inet6 (void) +{ + check_hostent ("gethostbyname (\"a.example\")", + gethostbyname ("a.example"), + "name: a.example\n" + "address: 192.0.2.17\n"); + check_hostent ("gethostbyname (\"qa.example\")", + gethostbyname ("qa.example"), + "name: qa.example\n" + "address: 192.0.2.17\n"); + check_hostent ("gethostbyname (\"am.example\")", + gethostbyname ("am.example"), + "name: am.example\n" + "address: 192.0.2.17\n"); + check_hostent ("gethostbyname (\"qam.example\")", + gethostbyname ("qam.example"), + "name: qam.example\n" + "address: 192.0.2.17\n"); + check_hostent ("gethostbyname (\"q.example\")", + gethostbyname ("q.example"), + "error: NO_RECOVERY\n"); + check_hostent ("gethostbyname (\"qm.example\")", + gethostbyname ("qm.example"), + "error: NO_ADDRESS\n"); + test_get2_no_inet6 (); + test_get2_no_inet6 (); + test_gai (); + test_get2_no_inet6 (); + test_get2_no_inet6 (); } static void * @@ -153,28 +280,42 @@ threadfunc (void *ignored) .response_callback = response }); - check_hostent ("gethostbyname (\"www1.example\")", - gethostbyname ("www1.example"), - "name: www1.example\n" - "address: 192.0.2.17\n"); - check_hostent ("gethostbyname (\"both.example\")", - gethostbyname ("both.example"), - "name: both.example\n" - "address: 192.0.2.17\n"); - test_get2 (); - test_gai (); + TEST_VERIFY ((_res.options & RES_USE_INET6) == 0); + test_no_inet6 (); _res.options |= RES_USE_INET6; - check_hostent ("gethostbyname (\"www1.example\")", - gethostbyname ("www1.example"), - "name: www1.example\n" + check_hostent ("gethostbyname (\"a.inet6.example\")", + gethostbyname ("a.inet6.example"), + "error: NO_RECOVERY\n"); + check_hostent ("gethostbyname (\"am.inet6.example\")", + gethostbyname ("am.inet6.example"), + "name: am.inet6.example\n" + "address: ::ffff:192.0.2.17\n"); + check_hostent ("gethostbyname (\"qa.inet6.example\")", + gethostbyname ("qa.inet6.example"), + "name: qa.inet6.example\n" + "address: 2001:db8::1\n"); + check_hostent ("gethostbyname (\"qam.inet6.example\")", + gethostbyname ("qam.inet6.example"), + "name: qam.inet6.example\n" "address: 2001:db8::1\n"); - check_hostent ("gethostbyname (\"both.example\")", - gethostbyname ("both.example"), - "name: both.example\n" + check_hostent ("gethostbyname (\"q.inet6.example\")", + gethostbyname ("q.inet6.example"), + "name: q.inet6.example\n" "address: 2001:db8::1\n"); - test_get2 (); + check_hostent ("gethostbyname (\"qm.inet6.example\")", + gethostbyname ("qm.inet6.example"), + "name: qm.inet6.example\n" + "address: 2001:db8::1\n"); + test_get2_inet6 (); + test_get2_inet6 (); test_gai (); + test_get2_inet6 (); + test_get2_inet6 (); + + TEST_VERIFY (_res.options & RES_USE_INET6); + _res.options &= ~RES_USE_INET6; + test_no_inet6 (); resolv_test_end (obj);