android上libevent dns解析的一个bug修复

在测试我们开发的一个 APK(使用了 libevent-2.1.3-alpha 作为网络库) 时发现一个奇怪的问题,域名解析有时报错 Non-recoverable name resolution failure 。在公司偶尔报错,后来程序改动了一下,出错时重试几次,问题没再出现,以为好了。昨天换了个网络环境,结果报错几率变得非常大。

互联网搜索到这个错误的一个处理办法,说在使用 getnameinfo() 函数时需要显式指定其第二个参数 salen 为 sizeof(struct sockaddr_in) 或者 sizeof(struct sockaddr_in6) ,说是 Solaris 和 Android 上的 getnameinfo() 实现不会查看 saddr 中的 sin_family 来计算出真正 salen 。我尝试了一下,没有解决问题,后来想想, libevent 根本就没有使用系统的域名解析函数,完全是自己实现的,于是只好自己跟代码了。

由于远程调试的环境没有搭建起来,只能不断地添加日志,反复查看,非常耗时。最后还真给我找到了问题所在。

libevent 的 dns 解析实现就在 evdns.c 这个文件中,不过如果不懂得 DNS 协议,代码看起来可能比较难懂,我重温了 DNS 协议,然后开始跟代码。

libevent 在处理 DNS 解析时,针对域名引入了一个随机大小写的概念,在 evdns_base_new() 中把 global_randomize_case 默认设置为 1 ,然后在读取域名服务器配置文件时根据里面的 options 来修改。安卓上没有 resolv.conf ,这些选项就没有修正的机会,于是最终 global_randomize_case 还是 1。

在 libevent 构造 DNS 请求( request_new() 函数)时,会根据 global_randomize_case 来决定是否对发起 dns 请求时传入的域名进行大小写随机转换,代码如下:

[cpp] view plaincopy

  1. if (base->global_randomize_case) {
  2. unsigned i;
  3. char randbits[(sizeof(namebuf)+7)/8];
  4. strlcpy(namebuf, name, sizeof(namebuf));
  5. evutil_secure_rng_get_bytes(randbits, (name_len+7)/8);
  6. for (i = 0; i < name_len; ++i) {
  7. if (EVUTIL_ISALPHA_(namebuf[i])) {
  8. if ((randbits[i >> 3] & (1<<(i & 7))))
  9. namebuf[i] |= 0x20;
  10. else
  11. namebuf[i] &= ~0x20;
  12. }
  13. }
  14. name = namebuf;
  15. }

然后在处理 DNS 服务器返回的结果时,从 DNS 请求列表中根据 trans_id 找到对应的 request ,拿 DNS 结果中解析出来的名字和 request 中的名字比较,如果不一致,就认为出错了。详情参考 reply_parse() 函数,其中 TESTNAME 宏实现名字比对,原始代码如下:

[cpp] view plaincopy

  1. #define TEST_NAME    \
  2. do { tmp_name[0] = ‘\0‘;    \
  3. cmp_name[0] = ‘\0‘;    \
  4. k = j;     \
  5. if (name_parse(packet, length, &j, tmp_name,   \
  6. sizeof(tmp_name))<0)   \
  7. goto err;     \
  8. if (name_parse(req->request, req->request_len, &k,  \
  9. cmp_name, sizeof(cmp_name))<0)     \
  10. goto err;     \
  11. if (base->global_randomize_case) {  \
  12. if (strcmp(tmp_name, cmp_name) == 0)  \
  13. name_matches = 1;    \
  14. } else {   \
  15. if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0) \
  16. name_matches = 1;    \
  17. }  \
  18. } while (0)

这段代码是有问题的,global_randomize_case 标记和字符串比较函数没有匹配上,颠倒了。所以比对就出了问题,有时候正确,有时候不正确。修改成下面的代码就好了:

[cpp] view plaincopy

  1. #define TEST_NAME                           \
  2. do { tmp_name[0] = ‘\0‘;                    \
  3. cmp_name[0] = ‘\0‘;                 \
  4. k = j;                          \
  5. if (name_parse(packet, length, &j, tmp_name,        \
  6. sizeof(tmp_name))<0)             \
  7. goto err;                   \
  8. if (name_parse(req->request, req->request_len, &k,    \
  9. cmp_name, sizeof(cmp_name))<0)           \
  10. goto err;                   \
  11. if (base->global_randomize_case) {           \
  12. if (evutil_ascii_strcasecmp(tmp_name, cmp_name) == 0)       \
  13. name_matches = 1;           \
  14. } else {                        \
  15. if (strcmp(tmp_name, cmp_name) == 0) \
  16. name_matches = 1;           \
  17. }                           \
  18. } while (0)
时间: 2024-10-07 06:37:45

android上libevent dns解析的一个bug修复的相关文章

在CentOS 5.5上使用sed遇到的一个bug

在 CentOS 5.5 上使用 sed 遇到一个bug $ echo AAA > config $ ln -s config cfg $ sed -i 's/AAA/aaa/' cfg sed: ck_follow_symlink: couldn't lstat c/config: No such file or directory 这个bug发生在 sed -i do_sth symbolic_links_without_slash 时 下载它的源代码 https://google-sear

xUtils - android工具库,大量更新:bug修复,缓存优化,GET请求加入lru缓存。

感谢大家最近一段时间对xUtils的关注,和给我bug反馈,这也使我在xUtils的开发上更有热情. 昨天晚上熬夜到5点多,完成了缓存模块的整理和结构优化,今天在此基础上有完成了给http模块添加GET请求文本内容时实现LRU缓存的工作,现在可设置缓存默认过期时间和针对当前请求的过期时间. 最新的源码从这里获取:https://github.com/wyouflf/xUtils 标签: xUtils afinal [1].[代码] GET请求缓存使用示例: 跳至 [1] ? 1 2 3 4 5

C++ 写类中的一个bug修复

 #include"wz.h"  #include"sts.h" class _string {     friend std::istream& operator>>(std::istream& is, _string& a);//bug 1 2     friend std::ostream& operator<<(std::ostream& os,_string& a);       pu

jquery-perfect-scoller.js的一个bug修复

现象描述: 座滚动条的左侧上下滚动,类似后台管理那养的,滚动使用了这插件,结果当滚动后松开鼠标滑动滚动条还能上下跟着鼠标走. 为了查看这个问题,我看了源码重点bindScollerY对象发现他绑定的是document,按理说是应该绑定滚动条对象才对,就修改了下,结果还是有点问题,引文鼠标放在滚动条上就还是能出现描述的问题.后来一同事说,再使用mouseLeave绑定结果大功告成,为此事折腾了一天.

最近很火的微信牛牛棋牌房卡搭建的源码的一个BUG修复

最新版修复所有bug出租微信牛牛棋牌房卡搭建(h5.fanshubbs.com)扣扣1687054422 BUG说明:当后台设定某个玩家的控制赢率后.10局20局的就没有问题.当是大于20,就会出现玩到最后打到超过20局时,就会出现卡死,不发牌不准备也不结算.其实就是因为大番薯微信H5棋牌开发搭建每个作弊的玩家是都先设定好了牌的点数写到数据库里,发牌时先读取数据里设定的点数来发牌.因为原版的程序,只是能最多加到20局的牌做好.超过20局就没数据了,就出错了.但是没有写作弊的是完全没问题的. 附件

Microsoft Windows DNS解析远程代码执行漏洞(MS11-030)

此次扫描检测到目标主机尚未安装MS11-030/KB2509553漏洞相应的HotFix,也未安装可以修正该漏洞的Service Pack,这意味着目标主机可能存在MS11-030/KB2509553漏洞. Microsoft Windows是微软发布的非常流行的操作系统. Microsoft Windows在实现上存在DNS解析远程代码执行漏洞,远程攻击者可利用此漏洞以NetworkService账户执行任意代码,造成完全控制受影响计算机. DNS客户端服务处理特制的LLMNR请求时存在一个远

【转】一个域名是用哪里的DNS来解析的,电脑怎么知道找哪一个DNS呢? 我注册域名的时候会在服务商那里配置DNS解析,一般需要24小时后才能访问,我想知道,解析后的这个数据是不是会同步到世界上所有的DNS服务器呢!如果不是,当我访问我的这个域名的时候,电脑怎么知道去找到我注册的这一家的DNS服务器呢,谁告诉他的呢?

看看DNS一些基础知识,你就了解了.1.DNS就是域名服务器,他的任务就是确定域名的解析,比如A记录MX记录等等. 2.任何域名都至少有一个DNS,一般是2个.为什么要2个以上呢?因为DNS可以轮回处理,第一个解析失败可以找第二个.这样只要有一个DNS解析正常,就不会影响域名的正常使用. 3.如何确定域名的DNS?很简单到http://www.internic.net/whois.html输入你要查询的域名就可以看到了.这个是国际域名管理中心.唯一的权威.只要这里能查到某个域名,就表示域名是生效

使用libevent异步解析dns

libevent 自带 dns 解析库,支持同步.异步两种方式解析域名.因 libevent 本身是异步事件驱动型类库,我们在基于它做应用时,也多数是使用异步模型,因此这里介绍一下如何使用 libevent 异步解析域名. libevent 官网有文章专门介绍 DNS 功能,请参考<Using DNS with Libevent>. 我这里的例子和官网稍有不同,主要体现在对 DNS 服务器的配置上,区分了多平台.因为我发现在 Android (安卓)平台上, libevent 在获取 DNS

Android上解析Json格式数据

package com.practice.json; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import android.app.Activity; import android.os.Bundle; import android.util.Log; public class JsonDemo extends Activity { /*http://www.hui