指定libcurl域名解析(dns)服务器

因某些运营商会恶意锁死竞争对手的dns,如某动的光猫,直接把电信的114给墙了,导致系统无法通过114这个域名服务器解析域名
这里说明下如何设置libcurl下使用的dns服务器

一 分析

1 下载libcurl包

wget https://curl.haxx.se/download/curl-7.53.0.tar.bz2
tar xjf curl-7.53.0.tar.bz2
cd curl-7.53.0

2 libcurl设置DNS解析服务器

通过如下函数可以设置指定dns域名服务器
curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, “xxx.xxx.xxx.xxx”);

3 libcurl dns部分源码分析

[jenkins@localhost lib]$ grep -r CURLOPT_DNS_SERVERS *
url.c: case CURLOPT_DNS_SERVERS:
进入url.c中,找到CURLOPT_DNS_SERVERS关键字,发现调用Curl_set_dns_servers函数

case CURLOPT_DNS_SERVERS:                                                                                         
    result = Curl_set_dns_servers(data, va_arg(param, char *));
    break;

在当前目录下索索Curl_set_dns_servers函数

[jenkins@localhost lib]$ grep -r Curl_set_dns_servers *
asyn-ares.c:CURLcode Curl_set_dns_servers(struct Curl_easy *data,
asyn-thread.c:CURLcode Curl_set_dns_servers(struct Curl_easy *data,
hostip.h:CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers);
hostsyn.c:CURLcode Curl_set_dns_servers(struct Curl_easy *data,
url.c:    result = Curl_set_dns_servers(data, va_arg(param, char *));

发现有三处函数定义asyn-ares.c,asyn-thread.c,hostsyn.c
asyn-thread.c和hostsyn.c中函数原型如下,可以看到在函数中并没有对两个传入参数做任何引用,直接就返回了。

CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers)
{
  (void)data;
  (void)servers;
  return CURLE_NOT_BUILT_IN;
} 

asyn-ares.c 函数原型如下,可以看到当c-ares version >= 0x010704 时候,会将data和servers两个参数传入ares_set_servers_csv函数中,这个函数应该就是ares中设置dns服务器的接口

CURLcode Curl_set_dns_servers(struct Curl_easy *data, char *servers)
{
  CURLcode result = CURLE_NOT_BUILT_IN;
  int ares_result;

  /* If server is NULL or empty, this would purge all DNS servers
   * from ares library, which will cause any and all queries to fail.
   * So, just return OK if none are configured and don't actually make
   * any changes to c-ares.  This lets c-ares use it's defaults, which
   * it gets from the OS (for instance from /etc/resolv.conf on Linux).
   */
  if(!(servers && servers[0]))
    return CURLE_OK;

#if (ARES_VERSION >= 0x010704)
  ares_result = ares_set_servers_csv(data->state.resolver, servers);
  switch(ares_result) {
  case ARES_SUCCESS:
    result = CURLE_OK;
    break;
  case ARES_ENOMEM:
    result = CURLE_OUT_OF_MEMORY;
    break;
  case ARES_ENOTINITIALIZED:
  case ARES_ENODATA:
  case ARES_EBADSTR:
  default:
    result = CURLE_BAD_FUNCTION_ARGUMENT;
    break;
  }
#else /* too old c-ares version! */
  (void)data;
  (void)(ares_result);
#endif
  return result;
}

经过测试发现,curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, “xxx.xxx.xxx.xxx”);函数并没有走asyn-ares.c 中的Curl_set_dns_servers,在libcurl的编译配置文件(arm的buildroot系统),有c-ares的条件编译,发现没有吧c-ares加进去,加进去后测试,发现libcurl使用asyn-ares.c中的函数了

ifeq ($(BR2_PACKAGE_C_ARES),y)                                                                                                                  
LIBCURL_DEPENDENCIES += c-ares
LIBCURL_CONF_OPTS += --enable-ares
else
LIBCURL_CONF_OPTS += --disable-ares
endifest_libcurl 

二 测试

为模拟运营商封掉某些域名服务器,可以通过设置iptable 禁用ip
要封停一个IP,使用下面这条命令:
iptables -I INPUT -s ... -j DROP
要解封一个IP,使用下面这条命令:
iptables -D INPUT -s ... -j DROP
禁用114dns服务器
iptables -I INPUT -s 114.114.114.114 -j DROP
禁用可以ping下验证,应该是ping不通的

测试代码见结尾,使用方法
./test_libcurl dns url
第一个参数为要设置的dns, 如114.114.114.114
第二个参数为要访问的url,如www.baidu.com 这里设置比较简单,建议使用baidu,163等,chnshp.lenovo.com.cn 有特殊的设置,这里只验证使用这种方式更改dns是生效的

1 使用114作为dns服务器解析www.baidu.com

这里iptable是没有被禁用的,可以ping通
ping 114.114.114.114
./test_libcurl 114.114.114.114 www.baidu.com
这里写图片描述

2 禁用114 IP,再次测试

发现ping不通,然后按照设置10秒后超时
iptables -I INPUT -s 114.114.114.114 -j DROP
ping 114.114.114.114
./test_libcurl 114.114.114.114 www.baidu.com
这里写图片描述

扫描二维码关注公众号,回复: 2495513 查看本文章

3 在114被禁用掉的基础上,使用其他dns服务器解析baidu

使用202和路由器dns都是可以的成功的
./test_libcurl 192.168.0.1 www.baidu.com
./test_libcurl 202.106.0.20 www.baidu.com
这里写图片描述

4 在禁用114的基础上,测试设置使用多个dns服务器

./test_libcurl 202.106.0.20,114.114.114.114 www.baidu.com 这里使用114和202,中间以逗号隔开即可,可以成功解析
这里写图片描述

5 在此基础上打开114禁用,测试,通过

iptables -D INPUT -s 114.114.114.114 -j DROP
./test_libcurl 114.114.114.114 www.baidu.com
这里写图片描述

三 结论

综上,在增加c-ares之后,curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, “xx.xx.xx.xx”);这个函数可以设置dns服务器(可以设置多个dns服务器,亲测10个以上都有效),由此可以解决用户因为运营商封IP导致的应用程序升级程序中curl域名解析失败的问题。

四 测试代码test_libcurl.c

#include <stdio.h>
#include <curl/curl.h>
#include <curl/easy.h>

int test(char *URL, char * host) {
    CURLcode res;
    CURL *curl;

    if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) {
        printf("curl_global_init() failed\n");
        return -1; 

    curl = curl_easy_init();
    if (!curl) {
        printf("curl_easy_init() failed\n");
        curl_global_cleanup();
        return 1;
    }   

    curl_easy_setopt(curl, CURLOPT_URL, URL);
    curl_easy_setopt(curl, CURLOPT_DNS_SERVERS, host);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
    curl_easy_setopt(curl, CURLOPT_FILETIME, 1L);
    curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

    res = curl_easy_perform(curl);

test_cleanup:

    curl_easy_cleanup(curl);
    curl_global_cleanup();

    return (int)res;
}

int main(int argc, char *argv[]) {
    test(argv[2], argv[1]);
    return 0;
}    

猜你喜欢

转载自blog.csdn.net/wq3028/article/details/80756039