android上libevent dns解析的一個bug修複

來源:互聯網
上載者:User

標籤:android   style   blog   http   io   ar   os   使用   sp   

在測試我們開發的一個 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) 

android上libevent dns解析的一個bug修複

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.