A strange problem found when testing an APK we developed (using a libevent-2.1.3-alpha as a network library) that sometimes reported a Non-recoverable name resolution failure error. Occasionally reported an error in the company. Later, the program was changed and the error was retried several times. The problem did not appear again, so I thought it was okay. Yesterday, I changed my network environment, and the probability of an error was very high.
A solution to this error is found on the Internet. When using the getnameinfo () function, you must explicitly specify the second parameter salen as sizeof (struct sockaddr_in) or sizeof (struct sockaddr_in6 ), the getnameinfo () Implementation on Solaris and Android does not view sin_family in saddr to calculate the real salen. I tried it and didn't solve the problem. Later I Thought About It. libevent didn't use the system's domain name resolution function at all, and it was completely implemented by myself, so I had to follow the code myself.
Because the remote debugging environment is not set up, you can only add logs and view the logs repeatedly, which is very time-consuming. Finally, I found the problem.
The dns resolution Implementation of libevent is in the evdns. c file. However, if you do not know the DNS protocol, the Code may seem hard to understand. I reviewed the DNS protocol and started to follow the code.
When handling DNS resolution, libevent introduces a random case sensitivity concept for domain names. In evdns_base_new (), global_randomize_case is set to 1 by default, then, when reading the configuration file of the Domain Name Server, modify it according to the options in it. If there is no resolv. conf on Android, there is no chance to correct these options. Therefore, global_randomize_case is still 1.
When libevent constructs a DNS request (request_new () function), it determines whether to perform random case conversion for the domain name passed in when initiating a dns request based on global_randomize_case. The Code is as follows:
if (base->global_randomize_case) {unsigned i;char randbits[(sizeof(namebuf)+7)/8];strlcpy(namebuf, name, sizeof(namebuf));evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);for (i = 0; i < name_len; ++i) {if (EVUTIL_ISALPHA_(namebuf[i])) {if ((randbits[i >> 3] & (1<<(i & 7))))namebuf[i] |= 0x20;elsenamebuf[i] &= ~0x20;}}name = namebuf;}
Then, when processing the results returned by the DNS server, find the corresponding request based on trans_id In the DNS request list, and compare the Resolved Name in the DNS results with the name in the request. If they are different, the error occurs. For details, refer to the reply_parse () function. The TESTNAME macro is used to compare the current name. The original code is as follows:
#define TEST_NAME \ do { tmp_name[0] = '\0'; \ cmp_name[0] = '\0'; \ k = j; \ if (name_parse(packet, length, &j, tmp_name, \ sizeof(tmp_name))<0) \ goto err; \ if (name_parse(req->request, req->request_len, &k,\ cmp_name, sizeof(cmp_name))<0) \ goto err; \ if (base->global_randomize_case) { \ if (strcmp(tmp_name, cmp_name) == 0) \ name_matches = 1; \ } else { \ if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) \ name_matches = 1; \ } \ } while (0)
There is a problem with this Code. The global_randomize_case mark and the string comparison function do not match and are reversed. So there is a problem with the comparison, sometimes correct, sometimes incorrect. Modify the following code:
#define TEST_NAME\do { tmp_name[0] = '\0';\cmp_name[0] = '\0';\k = j;\if (name_parse(packet, length, &j, tmp_name,\sizeof(tmp_name))<0)\goto err;\if (name_parse(req->request, req->request_len, &k,\cmp_name, sizeof(cmp_name))<0)\goto err;\if (base->global_randomize_case) {\ if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0)\name_matches = 1;\} else {\ if (strcmp(tmp_name, cmp_name) == 0) \name_matches = 1;\}\} while (0)
I spent more than four hours with this problem, and finally solved it. I finally put down my mind (the repair methods I tried before failed and tried again are always unreliable ).