#dns #domain-name #query #query-response #dns-server #questions #others

bin+lib crabby_dns

一个旨在为我自己和作为教授他人更多 DNS 知识的辅助工具的 DNS 服务器系统

1 个不稳定版本

0.1.0-alpha.52021年1月28日

#6 in #others

MIT 许可证

44KB
853

Crabby DNS

一个简单的 Rust DNS 服务器,有助于加深我团队办公时间讨论的理解。

在构建此项目时,我参考了以下项目或文档:

如何构建

  • 使用 rustup 在本地机器上安装 Rust 工具链。
  • 导航到您的已检出存储库,并运行 cargo build

如何熟悉 crate

  • 使用 cargo doc --open 生成 crate 文档并查看。

如何运行它

  • 可以使用 cargo test 运行单元测试套件。
  • 为了实际运行它,请查看 cargo run -- --help 以及下面的部分。

DNS Stub 解析器

目前,Crabby DNS Stub 解析器实现了 IETF RFC 1035 中一些最基本的相关部分,可能甚至还不够正确。目前仅支持类 INA RRs。

通过 CLI 指定查询域名,可选地指定查询类型和查询类。Stub 解析器将把 UDP 套接字的接口地址绑定和端口选择委托给操作系统。您的查询将被序列化为具有头部和问题部分的查询类型 DNS 协议消息,并发送到配置的 DNS 服务器。然后监听响应(阻塞)并将其反序列化为响应类型的 DNS 协议消息,其中包含服务器响应的任何部分和数据。

  • 通过 cargo run -- stub --help 调用特定子命令的帮助

示例

$ cargo run -- stub -@ 8.8.8.8 -d google.com
Connected to 8.8.8.8:53 from 10.0.2.15:43506
Working on the DNS transaction now...

#################################################
#               DNS QUESTION MESSAGE            #
#################################################
Header {
    id: 0,
    message_type: Query,
    op_code: Query,
    authoritative_answer: false,
    truncation: false,
    recursion_desired: true,
    recursion_available: false,
    authentic_data: false,
    checking_disabled: false,
    response_code: NoError,
    question_count: 1,
    answer_count: 0,
    authority_count: 0,
    additional_count: 0,
}
Question {
    domain_name: DomainName(
        "google.com",
    ),
    qtype: RRType(
        A,
    ),
    qclass: RRClass(
        IN,
    ),
}

#################################################
#               DNS RESPONSE MESSAGE            #
#################################################
Header {
    id: 0,
    message_type: Response,
    op_code: Query,
    authoritative_answer: false,
    truncation: false,
    recursion_desired: true,
    recursion_available: true,
    authentic_data: false,
    checking_disabled: false,
    response_code: NoError,
    question_count: 1,
    answer_count: 1,
    authority_count: 0,
    additional_count: 0,
}
Question {
    domain_name: DomainName(
        "google.com",
    ),
    qtype: RRType(
        A,
    ),
    qclass: RRClass(
        IN,
    ),
}
ResourceRecord {
    domain_name: DomainName(
        "google.com",
    ),
    rrtype: A,
    rrclass: IN,
    ttl: 102,
    rrdata_len: 4,
    rrdata: A(
        172.217.3.110,
    ),
}

DNS数据报反序列化器

  • 通过以下命令调用特定子命令的帮助:cargo run -- deserialize --help
  • 您需要一个DNS数据报来输入到程序中。在/data文件夹中提供了原始形式的查询及其响应的示例。
  • 您可以通过使用netcat监听没有DNS服务器监听的端口,然后在该端口上使用dig来生成自己的查询。
    • 在一个终端中运行以下命令:nc -u -l 1053 > query.pkt
    • 在另一个终端中运行以下命令:dig +retry=0 -p 1053 @127.0.0.1 +noedns google.com
  • 您可以通过使用netcat将查询UDP数据报作为输入重定向到DNS解析器(如Google的8.8.8.8)并将响应重定向到捕获文件来生成此查询的响应。
    • nc-u8.8.8.8 53 <query.pkt>response.pkt
  • 如果需要,您可以将数据包捕获以十六进制形式查看
    • hexdump-C响应.pkt
  • 将所有这些结合起来,您就可以调用Crabby DNS了
    • cargorun --deserialize -f ./response.pkt

示例

$ nc -u -l 1053 > query.pkt &
[2] 28112

$ dig +retry=0 -p 1053 @127.0.0.1 +noedns google.com

; <<>> DiG 9.16.1-Ubuntu <<>> +retry -p 1053 @127.0.0.1 +noedns google.com
; (1 server found)
;; global options: +cmd
;; connection timed out; no servers could be reached


$ kill 28112
[2]-  Terminated              nc -u -l 1053 > query.pkt

$ nc -u 8.8.8.8 53 < query.pkt > response.pkt
^C

$ hexdump -C response.pkt
00000000  6e 04 81 80 00 01 00 01  00 00 00 00 06 67 6f 6f  |n............goo|
00000010  67 6c 65 03 63 6f 6d 00  00 01 00 01 c0 0c 00 01  |gle.com.........|
00000020  00 01 00 00 00 15 00 04  ac d9 0c ae              |............|
0000002c

$ cargo run -- deserialize -f ./response.pkt
#########################################
#		DNS MESSAGE		#
#########################################
Header {
    id: 28164,
    message_type: Response,
    op_code: Query,
    authoritative_answer: false,
    truncation: false,
    recursion_desired: true,
    recursion_available: true,
    authentic_data: false,
    checking_disabled: false,
    response_code: NoError,
    question_count: 1,
    answer_count: 1,
    authority_count: 0,
    additional_count: 0,
}
Question {
    domain_name: DomainName(
        "google.com",
    ),
    qtype: RRType(
        A,
    ),
    qclass: RRClass(
        IN,
    ),
}
ResourceRecord {
    domain_name: DomainName(
        "google.com",
    ),
    rrtype: A,
    rrclass: IN,
    ttl: 21,
    rrdata_len: 4,
    rrdata: A(
        172.217.12.174,
    ),
}

依赖项

~1MB
~11K SLoC