DNS :
DNS是一个分层级 (hierarchical ),分布式(decentralized)的网络数据库,完成主机名称和IP地址之间的相互映射。DNS名称空间包含一个树状结构,树根没有命名, 下面是树的最高层为顶级域名, 顶级域名包括: 顶级域名(gTLD),国家代码顶级域名(ccTLD), 国际化国家设施顶级域名(infrastructure TLD), 下面一层是权威域名服务器。其中权威域名服务器对DNS请求进行应答返回IP地址。

DNS协议:
dns协议包含两部分:
1. 对DNS特定名称查询的查询、响应协议
2. 名称服务器用户交换数据库记录的协议(区域传输)
应用访问DNS通过地址解析器(resolver), 通常通过TCP,UDP协议通讯是需要将主机名转换为IPv4, IPv6地址。
gethostbname:
需要socket通过域名方式完成连接 , 可以通过API gethostbyname 函数完成。gethostbyname 函数是 glibc 库中提供一个域名解析的函数。 调用方法也相对简单,存在问题是范围结果是 static 类型变量,存在数据被覆盖的情况。
函数定义:
| |
| |
DEMO程序:
| |
gethostbyname 的glibc2.29版本实现:
下载glibc2.29 版本学习了下gethostbyname 代码:
1. 函数声明
netdb.h
#define DECLARE_NSS_PROTOTYPES(service)
extern enum nss_status _nss_ ## service ## _gethostbyname_r \
(const char *name, struct hostent *host, char *buffer, \
size_t buflen, int *errnop, int *h_errnop);
2. 函数定义:
gethostbyname实现比较特殊 使用 nss/getXXbyYY.c, nss/getXXbyYY_r.c 两个文件, 通过宏定义的方式定义了模板,inet/gethstbynm.c ,inet/gethstbynm_r.c nscd/nscd_gethst_r.c中设置了相关参数信息,与模板组合完成函数定义。
3.函数实现:
getXXbyYY.c :实现函数主题流程
1). 生成锁
2). 申请buffer空间
3). 判断 传入主机名称是否IP地址
4). 调用 INTERNAL,针对gethostbyname内部函数指定为 gethostbyname_r,调用过程中出现ERANGE时, 通过realloc 2倍方式动态扩大内存;
5). 释放锁;
getXXbyYY_r.c : 函数具体实现方法
1). 判断 传入主机名称是否IP地址,并处理
2). 判断是否支持nscd(编译时通过USE_NSCD指定),存在从nscd中获取
3). 初始化处理动作查询表。也是通过宏定义 DB_LOOKUP_FCT,指定第一个处理方法
4). 动态库方法: 通过 DL_CALL_FCT调用方法
静态库方法: 通过function.def定义的DEFINE_GETBY
# define DEFINE_GETBY(h,nm,ky) \
{ #h"_get"#nm"by"#ky"_r", _nss_##h##_get##nm##by##ky##_r },
static struct fct_tbl { const char *fname; void *fp; } *tp, tbl[] =
5). 根据返回结果是否成功,成功 并判断是否需要合并处理,将结果累计存储到mergebuf中,否则进行失败处理。
6). 如果存在多个方法通过__nss_next2 指向一下方法通过4,5调用
4. 域名查询方法初始化与nsswith.conf:
XXX-lookup.c, nss/nsswitch.c: 进行解析式的具体方法列表创建,查找返回
1). 宏定义在nss/XXX-lookup.c nss/hosts-lookup.c完成hosts(域名查询) 方法定义
2). __nss_database_lookup 通过nss_parse_file解析nsswitch.conf文件, 完成 service_user列表初始化,指定开始执行的方法 。
3) .__nss_lookup根据支持的action, 通过动态加载模式,__nss_lookup_function, 找到指定的函数并返回
5. dns,files nscd方式实现:
域名解析顺序可以通过 /etc/nsswitch.conf 文件中的hosts选项进行设置, 先使用 files方式 (/etc/hosts文件中的配置信息),还是使用dns 方式 (通过/etc/resolv.conf 配置域名服务器通过域名解析进行)
dns方式:
resolv/nss_dns/dns-host.c
函数调用链
_nss_dns_gethostbyname3_r ->
gethostbyname3_context->
__res_context_search->
getanswer_r->
files方式:
nss/nss_files/files-host.c
函数调用链:
_nss_files_gethostbyname3_r->
gethostbyname3_multi
nscd
nscd/nscd_gethst_r.c
函数调用链:
__nscd_gethostbyname_r->
nscd_gethst_r
sudo apt update
sudo apt install nscd
跟踪gethostbyname的域名解析过程:
环境:
OS:Ubuntu 17.10 (lsb_release -a) 4.13.0-21-generic (uname -a)
glibc : GNU C Library (Ubuntu GLIBC 2.26-0ubuntu2.1) stable release version 2.26 (libc.so.6 )
gcc: gcc version 7.2.0 (Ubuntu 7.2.0-8ubuntu3.2)
准备:
1)demo编译:
gcc gethostbyname.c -o gethostbyname
2) 配置文件:
/etc/nsswitch.conf 中
hosts: files dns
/etc/resolv.conf
nameserver 223.5.5.5
service nscd status: inactive
strace ./gethostbyname www.baidu.com > gethostbyname.default.log 2>&1
| |
启动 nscd 后(service nscd)
| |
nsswitch.conf merge action:
概述及疑问:
nsswitch.conf 文件大致格式如下:
database1: service1[STATUS=ACTION], service2
…..
可以配置 database , 如hosts ,passwd等,通过调整它们的service 顺序,来设置哪个services先被查询, 如果存在多个services,可以通过service查询结果状态设置不通的action 目前包含 return, continue, merge。
这个验证了下merge action
验证过程:
调整 /etc/nsswitch.conf
hosts: files [SUCCESS=merge] dns
./gethostbyname www.baidu.com
www.baidu.com was not resolved 22 (EINVAL)
问题分析:
1)源码:
在getXXbyYY_r. c 处理逻辑中是有merge 操作的, 调用了
__merge_einval函数, 目前这个函数直接返回 EINVAL。
2) 文档:
merge [SUCCESS=merge] is used between two database entries. When a group is located in the first of the two group entries, processing will continue on to the next one.
| |
nswitch.conf merge目前只支持 group database