In testing one of our developed APK (using Libevent-2.1.3-alpha as the network library) when found a strange problem, domain name resolution has the Times wrong non-recoverable name resolution failure. In the company occasionally error, then the program changed a bit, when the error occurred several times, the problem did not appear again, thought good. Yesterday changed a network environment, the result of error is very large.
The internet has found a way to deal with this error, saying that it is necessary to explicitly specify its second parameter salen as sizeof (struct sockaddr_in) or sizeof (struct sockaddr_in6) when using the Getnameinfo () function. It is said that the getnameinfo () implementation on Solaris and Android does not look at the sin_family in saddr to calculate the true Salen. I tried, did not solve the problem, and then think about it, Libevent simply did not use the system's domain name resolution function, completely their own implementation, so had to themselves with the code.
Because the remote debugging environment is not set up, can only continue to add logs, repeated review, very time-consuming. Finally, I found the problem.
Libevent DNS resolution implementation is in the EVDNS.C this file, but if you do not understand the DNS protocol, the code may seem difficult to understand, I revisit the DNS protocol, and then start with the code.
Libevent introduces a random case concept for domain names when dealing with DNS resolution, setting Global_randomize_case to 1 by default in Evdns_base_new (), and then reading the name server configuration file according to the options To modify. There is no resolv.conf on Android, these options have no chance of being corrected, so the final global_randomize_case is still 1.
When libevent constructs a DNS request (Request_new () function), it determines, based on the global_randomize_case, whether to convert the domain name that was passed in when the DNS request was initiated, with the following code:
[CPP]View Plaincopy
- 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;
- Else
- Namebuf[i] &= ~0x20;
- }
- }
- name = Namebuf;
- }
Then, when processing the results returned by the DNS server, find the corresponding request from the DNS request list according to trans_id, and compare the names parsed in the DNS results with the names in the request, and if they are inconsistent, it is considered an error. For details, refer to the Reply_parse () function, where the TESTNAME macro implements the name comparison and the original code is as follows:
[CPP]View Plaincopy
- #define TEST_NAME \
- Do {tmp_name[0] = ' + '; \
- Cmp_name[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)
This code is problematic, the global_randomize_case tag and the string comparison function do not match up, upside down. So there is a problem with the right, sometimes right, sometimes not right. Just modify it to the following code:
[CPP]View Plaincopy
- #define TEST_NAME \
- Do {tmp_name[0] = ' + '; \
- Cmp_name[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)
A bug fix for Libevent DNS resolution on Android