Knot DNS的查询处理流程可以根据配置文件进行动态定义。整个查询流程由几个步骤组成,每个步骤都是由多个模块以list方式组成的query plan,这些步骤分为几个阶段。
例如,处理class-IN查询需要查找answer,基于之前的状态,他可以添加附加的SOA权威记录,这个动作就是上面提到的步骤
Knot DNS以mod-name作为全局唯一标识,将配置文件语句与代码定义的控制块关联起来,根据配置文件的定义动态加载初始化模块,并在查询处理流程中被执行。
在加载模块的时候,Knot DNS解析配置文件中的模块名以及模块ID,根据模块名查找代码中定义的控制块,经过多重检查后,调用之前定义的load函数进行模块初始化并将process-hook函数追加到mod->plan->stage[knotd_stage_t]这个list-array的尾端,mod数据块根据其作用域不同分别挂到conf()->query_modules 或者 zone->query_modules中。
在处理查询的主要流程中遍历依次执行之前注册的process-hook函数。不同锚点以stage下标区分
/* Resolve PREANSWER. */
if (plan != NULL) {
WALK_LIST(step, plan->stage[KNOTD_STAGE_PREANSWER]) {
SOLVE_STEP(step->process, state, step->ctx);
}
}
Knot DNS提供了两种注册方式,一种是提供KNOTD_MOD_API()宏,构建全局结构体;一种是提供全局数组STATIC_MODULES[]
/*! Module API instance initialization helper macro. */
#define KNOTD_MOD_API(mod_name, mod_flags, mod_load, mod_unload, mod_conf, mod_conf_check) \
__attribute__((visibility("default"))) \
const knotd_mod_api_t KNOTD_MOD_API_NAME(mod_name) = { \
.version = KNOTD_MOD_ABI_VERSION, \
.name = KNOTD_MOD_NAME_PREFIX #mod_name, \
.flags = mod_flags, \
.load = mod_load, \
.unload = mod_unload, \
.config = mod_conf, \
.config_check = mod_conf_check, \
}
该结构块使用knotd_mod_api_##mod_name,所以编码必须保证模块名的全局唯一性
标志位,表示该模块的作用域,常用三种值
KNOTD_MOD_FLAG_SCOPE_GLOBAL /* global module. */
KNOTD_MOD_FLAG_SCOPE_ZONE /* zone module. */
KNOTD_MOD_FLAG_SCOPE_ANY /* global and zone module */
原型 typedef int (*knotd_mod_load_f)(knotd_mod_t *mod); 模块加载时被 conf_activate_modules() 调用以进行模块初始化与注册hook-process回掉
原型 typedef void (*knotd_mod_unload_f)(knotd_mod_t *mod); 模块去初始化阶段被调用,主要用来释放内存,socket等系统资源
用来注册指定配置文件语法与默认值
原型 typedef int (*knotd_conf_check_f)(knotd_conf_check_args_t *args); 模块加载时被用来检查模块配置
初始化函数:模块相关配置的初始化,系统资源的初始化,业务入口函数的注册
使用 _public_ knotd_conf_t knotd_conf_mod(knotd_mod_t *mod, const yp_name_t *item_name) 获取模块配置
使用_public_ int knotd_mod_hook(knotd_mod_t *mod, knotd_stage_t stage, knotd_mod_hook_f hook) 注册业务入口函数
系统资源,包括内存池、队列、socket、描述符、后台线程等的初始化
去初始化函数:主要是释放在初始化阶段申请的系统资源
查询处理入口函数 :业务处理流程的不同阶段,进行当前模块功能的执行
typedef knotd_state_t (*knotd_mod_hook_f) (knotd_state_t state, knot_pkt_t *pkt, knotd_qdata_t *qdata, knotd_mod_t *mod);
knotd_state_t state 查询流程的当前状态,枚举类型
knot_pkt_t *pkt 解析后的报文结构
knotd_qdata_t *qdata 本次查询处理的上下文
knotd_mod_t *mod 当前模块的控制块
使用 _public_ knotd_conf_t knotd_conf_check_item(knotd_conf_check_args_t *args, const yp_name_t *item_name) 获取配置项并检查合法性
使用 const yp_item_t xxx[] = {...} 定义配置语法
将新模块的.c和.h文件添加到Knot.files文件
修改configure.ac文件,添加条件编译相关代码
修改 src/knot/Makefile.inc 将模块makefile文件包含进去
新增src/knot/modules/mode-name/Makefile.inc,编写模块编译指令
将源代码文件放到src/knot/modules/mode-name/ 里面
新增src/knot/modules/mode-name/xxx.rst,编写使用说明