源码分析
初始化核心流程
| main---------------------------------------unbound.c run_daemon-----------------------------unbound.c daemon_open_shared_ports-------unbound.c daemon_fork------------------------daemon.c daemon_create_workers----------daemon.c worker_create--------------worker.c worker_init--------------------worker.c worker_start_accept--------worker.c worker_handle_request------worker.c tube_setup_bg_listen-------util/tube.c daemon_start_others(daemon)---------daemon.c thread_start--------------------daemon.c worker_work(worker)---------wroker.c worker_work(daemon->workers[0])-----worker.c
|
工作线程循环处理事件
1 2 3 4 5 6 7 8
| main---------daemon/unbound.c run_daemon---------daemon/unbound.c daemon_fork --------------daemon/daemon.c worker_work-----worker.c comm_base_dispatch----------util/netevent.c ub_event_base_dispatch-------util/ub_event.c // 事件封装 event_base_dispatch------util/mini_event.c // 进入while事件循环处理过程 《事件处理可替换为libevent》 handle_select--------util/mini_event.c // 调用selec阻塞等待事件并回调处理函数
|
开启端口监听过程
1 2 3 4 5 6 7 8
| main---------------------------------------unbound.c // 程序入口 run_daemon-----------------------------unbound.c // 启动守护服务 daemon_open_shared_ports-------unbound.c // 打开监听端口 listening_ports_open-------services/listen_dnsport.c //开启端口监听 ports_create_if--------services/listen_dnsport.c 。。。。--------services/listen_dnsport.c make_sock--------services/listen_dnsport.c //创建tcp和udp端口监听句柄到 port_insert--------services/listen_dnsport.c //将创建的端口监听对象加入到daemon->ports中,在《tcp 及udp事件处理回调函数的设置》中将ports加入到事件循环中
|
tcp 及udp事件处理回调函数的设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| worker_init-------------------------------daemon/worker.c listen_create(ports, worker_handle_request)-------------------------services/listen_dnsport.c comm_point_create_udp_ancil-------util/netevent.c c->callback = callback; c->ev->ev = ub_event_new(xxx, comm_point_udp_ancil_callback) // 创建事件管理对象,和c关联, 在 comm_point_udp_ancil_callback 中回调到c->callback函数 worker_handle_request ub_event_add() -------------util/netevent.c event_add---------------util/mini_event.c comm_point_create_udp-------------util/netevent.c c->callback = callback; c->ev->ev = ub_event_new(xxx, comm_point_udp_callback) // 创建事件管理对象,和c关联, comm_point_udp_callback中会回调到c->callback函数 ub_event_add() -------------util/netevent.c event_add---------------util/mini_event.c
comm_point_create_tcp---------------util/netevent.c c->ev->ev = = ub_event_new(comm_point_tcp_accept_callback) ub_event_add()------------util/netevent.c .....
|
module创建及调用过程
module创建及初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| daemon_fork--------------------------------------------daemon/daemon.c daemon_setup_modules------------------------------daemon/daemon.c modstack_setup---------------------------------services/modstack.c modstack_config module_factory // module创建工厂,创建所有module module_funcs_avail //创建所有module列表 dns64_get_funcblock // subnetmod_get_funcblock // 创建edns-subnet 模块 respip_get_funcblock val_get_funcblock iter_get_funcblock // 创建iterator for(i=0; i<stack->num; i++) { if(!(*stack->mod[i]->init)(env, i)) { // 调用各个module的init函数 }
|
module执行
1 2 3 4 5 6 7
| mesh_run------------------------------------services/mesh.c while(mstate) { fptr_ok(fptr_whitelist_mod_operate( mesh->mods.mod[mstate->s.curmod]->operate)); (*mesh->mods.mod[mstate->s.curmod]->operate) (&mstate->s, ev, mstate->s.curmod, e); }
|
客户端udp请求处理过程
1 2 3 4 5
| worker_handle_request-------daemon/worker.c mesh_new_client-------------services/mesh.c mesh_run()--------------services/mesh.c (*mesh->mods.mod[mstate->s.curmod]->operate)(&mstate->s, ev, mstate->s.curmod, e);
|
iterator 处理过程
1 2 3
| iter_operate ----------------------iterator/iterator.c process_request-----------------iterator/iterator.c iter_handle-----------------iterator/iterator.c
|
iterator查询结果缓存过程
1 2 3 4 5
| mesh_run()--------------services/mesh.c iter_operate--------------------iterator/iterator.c iter_dns_store----------------iterator/iter_util.c dns_cache_store-----------services/cache/dns.c dns_cache_store_msg---services/cache/dns.c
|
remote 远程请求accept设置过程
只有线程序号为0的主线程进行accept请求处理,其他未业务请求
1 2 3
| worker_start_accept--------worker.c // 启动监听并accept daemon_remote_start_accept--------daemon/remote.c // 根据配置的地址列表进行监听处理 comm_point_start_listening------util/netevent.c //
|
remote control 服务端启动流程
1 2 3 4 5
| worker_init--------------------------------worker.c // 工作线程初始化,worker_start_accept, worker_start_accept--------------------worker.c // 启动监听并accept daemon_remote_start_accept-------daemon/remote.c // 在线程0中启动 remote_control 相关监听 handle_req------------------daemon/remote.c // 启动处理请求处理过程 execute_cmd ------------daemon/remote.c // 处理具体的请求
|
耗时相关代码
1 2 3 4 5 6 7 8 9 10
| daemon_fork daemon/daemon.c daemon_setup_modules daemon/daemon.c modstack_setup services/modstack.c modstack_desetup fptr_whitelist_mod_deinit (*stack->mod[i]->deinit)(env, i); subnetmod_deinit edns-subnet/subnetmod.c slabhash_delete util/storage/slabhash.c // 此函数修改为自定义的qy_slabhash_delete函数, 实际耗时可能在此处 lruhash_delete util/storage/lruhash.c bin_delete util/storage/lruhash.c
|
重要概念
module(即插件)
unbound 中的 module
即模块(插件)。支持以下模块
模块名 |
作用 |
其他 |
validator |
用于验证DNSSEC签名有效性,确保DNS解析查询结果的完整性和不可篡改性 |
|
respip |
允许使用ACL(访问控制列表)限制哪些IP地址可以访问特定的域名 或 基于IP修改响应结果 |
|
pythonmod |
允许以Python脚本的形式扩展Unbound功能,可以实现自定义的DNS处理逻辑 |
|
iterator |
实现Unbound的迭代DNS解析查询功能,向远端DNS服务器递归查询所需DNS记录 |
|
subnet |
用于配置Unbound服务器的子网访问控制策略,允许或禁止指定子网的访问 |
|
subnetcache |
实现了支持不同子网对 DNS 解析结果进行缓存的功能。当一个请求来自于一个特定的子网时,subnetcache 模块会将 DNS 解析结果缓存下来,以便以后在该子网中的相同请求中能够快速响应 |
编译支持ECS时默认开启此模块 |
subnetcachedb |
支持对存储数据进行加密,保护缓存数据的隐私和安全。可以与 subnetcache 模块结合使用,以提供更高效的DNS解析缓存策略 |
|
dns64 |
实现DNS64代理,将IPv4 DNS请求转换为IPv6地址并返回响应 |
|
rpz |
实现RPZ(Responsibility Provenance Zone)功能,支持自定义DNS黑名单和白名单 |
|
prefetch |
提前查询DNS记录,以缩短DNS响应时间,提高用户的访问速度 |
|
这些模块可以通过配置文件中的 module-config
选项进行加载和配置,以实现各种不同的功能。同时,Unbound还支持许多其他模块,如dnstap模块、subnetcachedb模块、python_certgen模块等,可以根据需要选择适当的模块来实现自己的需求。
- 1.6.7版 编译加–enable-subnet后默认将启动三个插件,按执行顺序分别是subnetcache,validator,iterator,所以mesh_run的执行顺序是按照这个插件顺序执行的。