unit1607.c (6989B)
1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at https://curl.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 * SPDX-License-Identifier: curl 22 * 23 ***************************************************************************/ 24 #include "unitcheck.h" 25 26 #include "urldata.h" 27 #include "connect.h" 28 #include "share.h" 29 30 #include "memdebug.h" /* LAST include file */ 31 32 static CURLcode t1607_setup(void) 33 { 34 CURLcode res = CURLE_OK; 35 global_init(CURL_GLOBAL_ALL); 36 return res; 37 } 38 39 static CURLcode test_unit1607(char *arg) 40 { 41 /* In builds without IPv6 support CURLOPT_RESOLVE should skip over those 42 addresses, so we have to do that as well. */ 43 static const char skip = 0; 44 #ifdef USE_IPV6 45 #define IPV6ONLY(x) x 46 #else 47 #define IPV6ONLY(x) &skip 48 #endif 49 50 UNITTEST_BEGIN(t1607_setup()) 51 52 struct testcase { 53 /* host:port:address[,address]... */ 54 const char *optval; 55 56 /* lowercase host and port to retrieve the addresses from hostcache */ 57 const char *host; 58 int port; 59 60 /* whether we expect a permanent or non-permanent cache entry */ 61 bool permanent; 62 63 /* 0 to 9 addresses expected from hostcache */ 64 const char *address[10]; 65 }; 66 67 /* CURLOPT_RESOLVE address parsing tests */ 68 static const struct testcase tests[] = { 69 /* spaces aren't allowed, for now */ 70 { "test.com:80:127.0.0.1, 127.0.0.2", 71 "test.com", 80, TRUE, { NULL, } 72 }, 73 { "TEST.com:80:,,127.0.0.1,,,127.0.0.2,,,,::1,,,", 74 "test.com", 80, TRUE, { "127.0.0.1", "127.0.0.2", IPV6ONLY("::1"), } 75 }, 76 { "test.com:80:::1,127.0.0.1", 77 "test.com", 80, TRUE, { IPV6ONLY("::1"), "127.0.0.1", } 78 }, 79 { "test.com:80:[::1],127.0.0.1", 80 "test.com", 80, TRUE, { IPV6ONLY("::1"), "127.0.0.1", } 81 }, 82 { "test.com:80:::1", 83 "test.com", 80, TRUE, { IPV6ONLY("::1"), } 84 }, 85 { "test.com:80:[::1]", 86 "test.com", 80, TRUE, { IPV6ONLY("::1"), } 87 }, 88 { "test.com:80:127.0.0.1", 89 "test.com", 80, TRUE, { "127.0.0.1", } 90 }, 91 { "test.com:80:,127.0.0.1", 92 "test.com", 80, TRUE, { "127.0.0.1", } 93 }, 94 { "test.com:80:127.0.0.1,", 95 "test.com", 80, TRUE, { "127.0.0.1", } 96 }, 97 { "test.com:0:127.0.0.1", 98 "test.com", 0, TRUE, { "127.0.0.1", } 99 }, 100 { "+test.com:80:127.0.0.1,", 101 "test.com", 80, FALSE, { "127.0.0.1", } 102 }, 103 }; 104 105 int i; 106 struct Curl_multi *multi = NULL; 107 struct Curl_easy *easy = NULL; 108 struct curl_slist *list = NULL; 109 110 for(i = 0; i < (int)CURL_ARRAYSIZE(tests); ++i) { 111 int j; 112 int addressnum = CURL_ARRAYSIZE(tests[i].address); 113 struct Curl_addrinfo *addr; 114 struct Curl_dns_entry *dns; 115 void *entry_id; 116 bool problem = false; 117 easy = curl_easy_init(); 118 if(!easy) 119 goto error; 120 121 /* create a multi handle and add the easy handle to it so that the 122 hostcache is setup */ 123 multi = curl_multi_init(); 124 curl_multi_add_handle(multi, easy); 125 126 list = curl_slist_append(NULL, tests[i].optval); 127 if(!list) 128 goto error; 129 curl_easy_setopt(easy, CURLOPT_RESOLVE, list); 130 131 Curl_loadhostpairs(easy); 132 133 entry_id = (void *)curl_maprintf("%s:%d", tests[i].host, tests[i].port); 134 if(!entry_id) 135 goto error; 136 dns = Curl_hash_pick(&multi->dnscache.entries, 137 entry_id, strlen(entry_id) + 1); 138 free(entry_id); 139 entry_id = NULL; 140 141 addr = dns ? dns->addr : NULL; 142 143 for(j = 0; j < addressnum; ++j) { 144 int port = 0; 145 char ipaddress[MAX_IPADR_LEN] = {0}; 146 147 if(!addr && !tests[i].address[j]) 148 break; 149 150 if(tests[i].address[j] == &skip) 151 continue; 152 153 if(addr && !Curl_addr2string(addr->ai_addr, addr->ai_addrlen, 154 ipaddress, &port)) { 155 curl_mfprintf(stderr, "%s:%d tests[%d] failed. " 156 "getaddressinfo failed.\n", 157 __FILE__, __LINE__, i); 158 problem = true; 159 break; 160 } 161 162 if(addr && !tests[i].address[j]) { 163 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " 164 "is %s but tests[%d].address[%d] is NULL.\n", 165 __FILE__, __LINE__, i, ipaddress, i, j); 166 problem = true; 167 break; 168 } 169 170 if(!addr && tests[i].address[j]) { 171 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " 172 "is NULL but tests[%d].address[%d] is %s.\n", 173 __FILE__, __LINE__, i, i, j, tests[i].address[j]); 174 problem = true; 175 break; 176 } 177 178 if(!curl_strequal(ipaddress, tests[i].address[j])) { 179 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved addr " 180 "%s is not equal to tests[%d].address[%d] %s.\n", 181 __FILE__, __LINE__, i, ipaddress, i, j, 182 tests[i].address[j]); 183 problem = true; 184 break; 185 } 186 187 if(port != tests[i].port) { 188 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the retrieved port " 189 "for tests[%d].address[%d] is %d " 190 "but tests[%d].port is %d.\n", 191 __FILE__, __LINE__, i, i, j, port, i, tests[i].port); 192 problem = true; 193 break; 194 } 195 196 if(dns->timestamp && tests[i].permanent) { 197 curl_mfprintf(stderr, 198 "%s:%d tests[%d] failed. the timestamp is not zero " 199 "but tests[%d].permanent is TRUE\n", 200 __FILE__, __LINE__, i, i); 201 problem = true; 202 break; 203 } 204 205 if(dns->timestamp == 0 && !tests[i].permanent) { 206 curl_mfprintf(stderr, "%s:%d tests[%d] failed. the timestamp is zero " 207 "but tests[%d].permanent is FALSE\n", 208 __FILE__, __LINE__, i, i); 209 problem = true; 210 break; 211 } 212 213 addr = addr->ai_next; 214 } 215 216 curl_easy_cleanup(easy); 217 easy = NULL; 218 curl_multi_cleanup(multi); 219 multi = NULL; 220 curl_slist_free_all(list); 221 list = NULL; 222 223 if(problem) { 224 unitfail++; 225 continue; 226 } 227 } 228 error: 229 curl_easy_cleanup(easy); 230 curl_multi_cleanup(multi); 231 curl_slist_free_all(list); 232 233 UNITTEST_END(curl_global_cleanup()) 234 }