结解析器:如何在正确的时间观察和修改已解决的答案

时间:2016-04-25 17:46:20

标签: dns

目标

我想在C或CGO中缝合GNU GPL许可的Knot Resolver模块,该模块将检查客户端的查询和相应的已解决答案,目的是查询提供恶意软件感染主机名的知识库的外部API和IP地址(例如GNU AGPL v3 IntelMQ)。

如果与已解析的A(AAAA)的IP地址匹配,则应记录它,同样应记录与查询的主机名的匹配或(可选)它可能导致向客户端发送一个下沉的IP地址而不是已解决的那个。

平均值

我研究了the layers,我得出结论,我感兴趣的阶段是consume。我不想影响解决过程,我只是想在最后一刻介入并检查结果并可能修改它们。

我冒昧地注册了一个consume功能 与

static knot_layer_api_t _layer = {
    .consume = &consume,
};

但我不确定这是否适合做这件事。

此外,我还研究了模块hints.c,特别是它的query方法 和模块stats.c用于其_to_wire函数用法。

问题(S)

阶段(层?)

何时是在发送给客户端之前介入并读取/写入查询的答案的正确时间?我在消费层中的正确位置吗?

回答部分

如果以下尝试获取已解析的IP地址,则会为我提供名称服务器的地址:

char addr_str[INET6_ADDRSTRLEN];
memset(addr_str, 0, sizeof(addr_str));
const struct sockaddr *src = &(req->answer->sections);
inet_ntop(qry->ns.addr[0].ip.sa_family, kr_inaddr(src), addr_str, sizeof(addr_str));
DEBUG_MSG(NULL, "ADDR: %s\n", addr_str);

如何获取查询主机名的已解析(A,AAAA)IP地址?我想在答案中迭代A / AAAA IP地址和CNAME,并查看它们被解析的IP地址。

修改答案

如果模块设置需要它,我希望能够“抛弃”已解决的答案,并提供一个新的,包括指向下沉的A记录。

如何准备记录,以便在正确的阶段将记录从char*转换为Knot的有线格式以及正确的上下文中的正确结构?

我想它可能会出现knot_rrset_initknot_rrset_add_rdata这样的功能,但我无法获得任何成功的结果。

指示和建议的THX。

1 个答案:

答案 0 :(得分:3)

如果您想在最后确定响应但尚未发送给请求者的最后时刻,那么正确的位置是finish。您也可以在consume中执行此操作,但是您将在此处覆盖权威服务器的响应,而不是对请求者的汇总响应(这意味着DNSSEC验证程序可能会停止您的重写答案)。

免责声明:Go界面粗糙,需要大量CGO代码才能访问内部结构。您可能更适合LuaJIT模块,您可以将另一个模块doing something similar作为示例,它还具有用于从文本等创建记录的包装器。如果您仍想要这样做,欢迎阅读Go界面的精彩和改进。

您需要做的大致是this(作为CGO)。 这将引导您完成数据包中的RR集(C.knot_rrset_t), 您可以在其中匹配类型(rr.type)和内容(rr.rdata)。 内容以DNS有线格式存储,对于地址记录,它是网络字节顺序的地址,例如, {0x7f, 0, 0, 1}。 您必须将其与您在C代码中寻找的地址/子网进行比较 - example

当您找到匹配项时,您希望清除整个数据包并插入sinkhole记录(您无法有选择地删除记录,因为该数据包仅出于性能原因而附加。)这相对容易,因为a helper就是这样。来自policy模块的code in LuaJIT,您必须使用上面提到的所有函数并使用A / AAAA sinkhole记录而不是SOA来在Go中重写它。祝你好运!