From 2ef016e1f09e54ff47b700f733d0ccd7e444e1a4 Mon Sep 17 00:00:00 2001 From: TochusC <205329624@qq.com> Date: Sat, 9 Nov 2024 16:49:11 +0800 Subject: [PATCH] =?UTF-8?q?[1.2.0=E6=9B=B4=E6=96=B0]=20=E9=87=8D=E5=86=99?= =?UTF-8?q?=E6=96=87=E6=A1=A3=E5=8F=8AREADME=EF=BC=8C=E4=BF=AE=E5=A4=8DRes?= =?UTF-8?q?ponser=E9=94=99=E8=AF=AF=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 170 +++++++++++++++++++++---------- dns/doc.go | 18 +++- dns/xperi/dnssec.go | 5 +- doc.go | 241 +++++++++++++++++++++++++++++++++----------- docs/en/README.md | 174 +++++++++++++++++++++----------- netter.go | 8 +- responser.go | 95 +++++++++++++---- 7 files changed, 511 insertions(+), 200 deletions(-) diff --git a/README.md b/README.md index 63fc20f..6ea7ece 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,6 @@ GoDNS 是一个快速、灵活的**实验用** DNS 服务器,旨在帮助开 ## 目录 -- [概述](#概述) - [GoDNSServer](#godnsserver) - [示例](#示例) - [构造和生成 DNS 回复](#构造和生成-dns-回复) @@ -20,30 +19,68 @@ GoDNS 是一个快速、灵活的**实验用** DNS 服务器,旨在帮助开 - [xlayers 子包](#xlayers-子包) - [xperi 子包](#xperi-子包) -## 概述 +## GoDNSServer -GoDNSServer 由三部分组成: +`GoDNSServer` 是对 DNS 服务器的最顶层封装, 其由三部分组成: -1. **ServerConfig**: DNS 服务器的配置。 -2. **Netterr**: 网络处理器,用于监听数据包,发送DNS回复。 -3. **Responser**: 数据包处理器,负责处理 DNS 请求并生成响应。 +1. **ServerConfig**: DNS 服务器配置。 +2. **Netter**: 数据包处理器:接收、解析、发送数据包,并维护连接状态。 +3. **Responser**: DNS回复器:响应、解析、构造DNS回复 -## GoDNSServer +```go +type GoDNSServer struct { + ServerConfig DNSServerConfig + Netter Netter + Responer Responser +} + +// GoDNSServer 启动! +func (s *GoDNSServer) Start() +``` + +### Netter + +*`Netter` 数据包监听器:接收、解析、发送数据包,并维护连接状态。* + +```go +type Netter struct { // size=16 (0x10) + Config NetterConfig +} -`GoDNSServer` 是对 DNS 服务器的最顶层封装,提供了灵活的接口和功能。 +// Send 函数用于发送数据包 +func (n *Netter) Send(connInfo ConnectionInfo, data []byte) -### Sniffer +// Sniff 函数用于监听指定端口,并返回链接信息通道 +func (n *Netter) Sniff() chan ConnectionInfo -`Netter` 用于监听指定的协议和端口,嗅探 DNS 请求。 +// handleListener 函数用于处理 TCP 链接 +func (n *Netter) handleListener(lstr net.Listener, connChan chan +ConnectionInfo) -### Handler +// handlePktConn 函数用于处理 数据包 链接 +func (n *Netter) handlePktConn(pktConn net.PacketConn, connChan chan +ConnectionInfo) -`Handler` 负责处理 DNS 请求并生成回复,内部包含以下四部分: +// handleStreamConn 函数用于处理 流式链接 +func (n *Netter) handleStreamConn(conn net.Conn, connChan chan ConnectionInfo) +``` +### Responser -- **Parser**: 解析 DNS 请求。 -- **Responser**: 生成 DNS 回复。 -- **Sender**: 发送 DNS 回复。 -- **DNSServerConfig**: 记录 DNS 服务器的配置。 +*`Responser` DNS回复器:响应、解析、构造DNS回复。* + +`Responser`是一个接口。 实现该接口的结构体将根据 DNS 查询信息生成 DNS 回复信息。 +```go +type Responser interface { // size=16 (0x10) + // Response 根据 DNS 查询信息生成 DNS 回复信息。 + // 其参数为: + // - qInfo QueryInfo,DNS 查询信息 + // 返回值为: + // - ResponseInfo,DNS 回复信息 + // - error,错误信息 + Response(ConnectionInfo) (dns.DNSMessage, error) +} + +``` ## 示例 @@ -51,67 +88,94 @@ GoDNSServer 由三部分组成: ```go // 创建一个 DNS 服务器 -server := &GoDNSServer{ - ServerConfig: serverConf, - Sniffer: []*Sniffer{ - NewSniffer(SnifferConfig{ - Device: serverConf.NetworkDevice, - Port: serverConf.Port, - PktMax: 65535, - Protocol: ProtocolUDP, - }), +server := godns.GoDNSServer{ + ServerConfig: sConf, + Netter: godns.Netter{ + Config: godns.NetterConfig{ + Port: sConf.Port, + MTU: sConf.MTU, + }, + }, + Responer: &DullResponser{ + ServerConf: sConf, }, - Handler: NewHandler(serverConf, &DullResponser{}), } server.Start() ``` ## 构造和生成 DNS 回复 -`Handler` 用于响应、处理 DNS 请求并回复。实现 `Responser` 接口,可以自定义 DNS 回复的生成方式。 +通过实现 `Responser` 接口,可以自定义 DNS 回复的生成方式。 -`responser.go` 文件中提供了若干的 `Responser` 实现示例,以供参考。 +`responser.go` 文件中提供了若干的 `Responser` 实现示例及许多辅助函数,以供参考。 ## dns 包 -`dns` 包使用 Go 的内置函数提供对 DNS 消息的编解码实现。 +`dns` 包使用Go的内置实现,提供了 DNS消息 的编解码功能,可以用于任意构造和解析 DNS消息。 -### DNSMessage +`DNSMessage`表示 DNS协议 的消息结构。 +```go +type DNSMessage struct { + // DNS消息头部 + Header DNSHeader // DNS 头部(Header) + // DNS消息的各个部分(Section) + Question DNSQuestionSection // DNS 查询部分(Questions Section) + Answer DNSResponseSection // DNS 回答部分(Answers Section) + Authority DNSResponseSection // DNS 权威部分(Authority Section) + Additional DNSResponseSection // DNS 附加部分(Additional Section) +} +``` -`DNSMessage` 结构表示 DNS 协议的消息,包括: +`dns`包中的每个结构体基本都实现了以下方法: +```go +// 从缓冲区中自解码 +func (s *struct) DecodeFromBuffer(buffer []byte, offset int) (int, error) -- **Header**: DNS 头部。 -- **Question**: DNS 查询部分。 -- **Answer**: DNS 回答部分。 -- **Authority**: 权威部分。 -- **Additional**: 附加部分。 +// 编码为字节流 +func (s *struct) Encode() []byte -dns包支持对未知类型的资源记录进行编解码,灵活满足实验需求。 +// 编码到缓冲区 +func (s *struct) EncodeToBuffer(buffer []byte) (int, error) -## xlayers 子包 +// 获取结构体的*实际*大小 +func (s *struct) Size() int -`xlayers` 包提供了实现 `gopacket.Layer` 接口的 DNS 封装结构,可用于替换 `gopacket.Layer` 中原有的 DNS 实现。 +// 获取结构体的字符串表示 +func (s *struct) String() string -```go -// DNS 结构体可用于替换 gopacket.Layer 中原有的 DNS 实现 -type DNS struct { - layers.BaseLayer - DNSMessage dns.DNSMessage -} +// [部分实现]判断两个结构体是否相等 +func (s *struct) Equal(other *struct) bool ``` +这些方法使得可以方便地对 DNS 消息进行编解码。 + +`dns`包对 DNS 消息的格式没有强制限制,并且支持对 未知类型的资源记录 进行编解码, +这使得其可以随意构造和解析 DNS 消息,来满足实验需求。 ## xperi 子包 `xperi` 包实现了一些实验用函数,特别是 DNSSEC 相关的辅助函数,包括: -- `ParseKeyBase64`: 解析 Base64 编码的 DNSKEY。 -- `CalculateKeyTag`: 计算 DNSKEY 的 Key Tag。 -- `GenerateDNSKEY`: 生成 DNSKEY RDATA。 -- `GenerateRRSIG`: 对 RRSET 进行签名生成 RRSIG RDATA。 -- `GenerateDS`: 生成 DNSKEY 的 DS RDATA。 -- `GenRandomRRSIG`: 生成随机的 RRSIG RDATA。 -- `GenWrongKeyWithTag`: 生成错误的 DNSKEY RDATA,带有指定 KeyTag。 -- `GenKeyWithTag`: 生成具有指定 KeyTag 的 DNSKEY(此函数较耗时)。 + - `ParseKeyBase64` 用于解析 Base64 编码的 DNSKEY 为字节形式。 + + - `CalculateKeyTag` 用于计算 DNSKEY 的 Key Tag。 + + - `GenerateRDATADNSKEY` 根据参数生成 DNSKEY RDATA。 + + - `GenerateRDATARRSIG` 根据参数对RRSET进行签名,生成 RRSIG RDATA。 + + - `GenerateRDATADS` 根据参数生成 DNSKEY 的 DS RDATA。 + + - `GenerateRRDNSKEY` 根据参数生成 DNSKEY RR。 + + - `GenerateRRRRSIG` 根据参数对RRSET进行签名,生成 RRSIG RR。 + + - `GenerateRRDS` 根据参数生成 DNSKEY 的 DS RR。 + + - `GenRandomRRSIG` 用于生成一个随机的 RRSIG RDATA。 + + - `GenWrongKeyWithTag` 用于生成错误的,但具有指定 KeyTag 的 DNSKEY RDATA。 + + - `GenKeyWithTag` **[该函数十分耗时]** 用于生成一个具有指定 KeyTag 的 DNSKEY。 ## 许可证 diff --git a/dns/doc.go b/dns/doc.go index 059f62a..a90bb8c 100644 --- a/dns/doc.go +++ b/dns/doc.go @@ -3,10 +3,10 @@ /* dns 使用Go的内置实现,提供了 DNS消息 的编解码功能,可以用于任意构造和解析 DNS消息。 -// DNSMessage 表示 DNS协议 的消息结构。 +[DNSMessage] 表示 DNS协议 的消息结构。 type DNSMessage struct { - // DNS消息 头部 + // DNS消息 头 Header DNSHeader // DNS 头部(Header) // DNS消息的各个部分(Section) Question DNSQuestionSection // DNS 查询部分(Questions Section) @@ -15,9 +15,17 @@ dns 使用Go的内置实现,提供了 DNS消息 的编解码功能,可以用 Additional DNSResponseSection // DNS 附加部分(Additional Section) } -子模块dns/xlayers则提供了实现gopacket接口的DNS封装结构, +dns包中的每个结构体基本都实现了以下方法: + - func (s *struct) DecodeFromBuffer(buffer []byte, offset int) (int, error) + - func (s *struct) Encode() []byte + - func (s *struct) EncodeToBuffer(buffer []byte) (int, error) + - func (s *struct) Size() int + - func (s *struct) String() string + - [少部分实现]func (s *struct) Equal(other *struct) bool -可以把dns包看作是 gopacket 中 DNS 相关部分的重新实现,目的是使其更加易用。 -也可以将其单独作为一个独立的DNS消息编解码库来使用。 +这些方法使得可以方便地对 DNS 消息进行编解码。 + +dns包对 DNS 消息的格式没有强制限制,并且支持对 未知类型的资源记录 进行编解码, +这使得其可以随意构造和解析 DNS 消息,来满足实验需求。 */ package dns diff --git a/dns/xperi/dnssec.go b/dns/xperi/dnssec.go index c69f60c..5db2304 100644 --- a/dns/xperi/dnssec.go +++ b/dns/xperi/dnssec.go @@ -76,10 +76,11 @@ func GenerateRDATADNSKEY(algo dns.DNSSECAlgorithm, flag dns.DNSKEYFlag) (dns.DNS // 返回值: // - DNSKEY RR // - 私钥字节 -func GenerateRRDNSKEY(algo dns.DNSSECAlgorithm, flag dns.DNSKEYFlag) (dns.DNSResourceRecord, []byte) { +func GenerateRRDNSKEY( + zName string, algo dns.DNSSECAlgorithm, flag dns.DNSKEYFlag) (dns.DNSResourceRecord, []byte) { rdata, privKey := GenerateRDATADNSKEY(algo, flag) rr := dns.DNSResourceRecord{ - Name: "example.com.", + Name: zName, Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, diff --git a/doc.go b/doc.go index 66766d8..063e325 100644 --- a/doc.go +++ b/doc.go @@ -1,60 +1,69 @@ // Copyright 2024 TochusC AOSP Lab. All rights reserved. +// # 简体中文 +// // GoDNS 是一个快速、灵活的实验用 DNS 服务器,旨在帮助开发者和研究人员探索和实验 DNS 协议的各种特性。 // // # GoDNSServer // -// GoDNSServer 是对 DNS 服务器的最顶层封装。 +// [GoDNSServer] 是对 DNS 服务器的最顶层封装。 // // GoDNSServer 包含以下三部分: // - ServerConfig: DNS 服务器配置 -// - Sniffer: 数据包嗅探器 -// - Handler: 数据包处理器 -// } -// -// Sniffer 用于监听指定的网络设备和端口,嗅探 DNS 请求。 -// Handler 用于处理 DNS 请求,并生成回复。 -// -// ## 示例 -// -// 通过下述几行代码,可以一键启动一个基础的 GoDNS 服务器: -// // 创建一个 DNS 服务器 -// server := &GoDNSServer{ -// ServerConfig: serverConf, -// Sniffer: []*Sniffer{ -// NewSniffer(SnifferConfig{ -// Device: serverConf.NetworkDevice, -// Port: serverConf.Port, -// PktMax: 65535, -// Protocol: ProtocolUDP, -// }), -// }, -// Handler: NewHandler(serverConf, &DullResponser{}), -// } -// server.Start() +// - Netter: 数据包处理器 +// - Responser: DNS回复器 +// +// [Netter] 接收、解析、发送数据包,并维护连接状态。 +// +// [Responser] 响应、解析、构造DNS回复。 // -// ## 构造、生成 DNS 回复 +// 示例 // -// Handler用于响应、处理 DNS 请求并回复 -// 其包含以下四部分: -// - Parser 解析DNS请求 [parser.go] -// - Responser 生成DNS回复 [responser.go] -// - Sender 发送DNS回复 [sender.go] -// - DNSServerConfig 记录DNS服务器配置 +// 通过下述几行代码,可以一键启动一个基础的 GoDNS 服务器: +// +// server := godns.GoDNSServer{ +// ServerConfig: sConf, +// Netter: godns.Netter{ +// Config: godns.NetterConfig{ +// Port: sConf.Port, +// MTU: sConf.MTU, +// }, +// }, +// Responer: &DullResponser{ +// ServerConf: sConf, +// }, +// } +// server.Start() +// +// # 构造、生成 DNS 回复 +// +// [Responser]用于响应、解析、构造 DNS 回复 +// +// // Responser 是一个 DNS 回复器接口。 +// // 实现该接口的结构体将根据 DNS 查询信息生成 DNS 回复信息。 +// type Responser interface { +// // Response 根据 DNS 查询信息生成 DNS 回复信息。 +// // 其参数为: +// // - qInfo QueryInfo,DNS 查询信息 +// // 返回值为: +// // - ResponseInfo,DNS 回复信息 +// // - error,错误信息 +// Response(ConnectionInfo) (dns.DNSMessage, error) +// } // -// Responser 接口的 Response 方法用于生成 DNS 回复。 // 通过实现 Responser 接口,可以自定义 DNS 回复的生成方式。 // [responser.go]文件中提供了若干的 Responser 实现示例, -// 可以参考它们的实现方式来实现自定义的 Responser, -// 从而随意构造 DNS 回复。 +// 及许多辅助函数,如 “笨笨”处理器、[DNSSECResponser]、 +// [ParseQueryInfo]、[ParseResponseInfo] 等。 // -// # dns包 +// 可以参考它们的实现方式来实现自定义的 Responser, +// 从而随意构造 DNS 回复,实现更加复杂的回复逻辑。 // -// dns包使用go的内置函数提供了对 DNS 消息的编解码实现。 +// # dns 包 // -// DNSMessage 是表示 DNS消息 的最顶层封装。 +// dns 使用Go的内置实现,提供了 DNS消息 的编解码功能,可以用于任意构造和解析 DNS消息。 // -// // DNSMessage 表示 DNS协议 的消息结构。 +// [dns.DNSMessage] 表示 DNS协议 的消息结构。 // // type DNSMessage struct { // // DNS消息 头部 @@ -66,34 +75,152 @@ // Additional DNSResponseSection // DNS 附加部分(Additional Section) // } // -// dns 包对 DNS 消息的格式没有强制限制, -// 并且支持对 未知类型的资源记录 进行编解码, -// 这使得其可以随意构造和解析 DNS 消息,来满足实验需求。 -// -// ## xlayers 子包 +// dns包中的每个结构体基本都实现了以下方法: +// - func (s *struct) DecodeFromBuffer(buffer []byte, offset int) (int, error) +// - func (s *struct) Encode() []byte +// - func (s *struct) EncodeToBuffer(buffer []byte) (int, error) +// - func (s *struct) Size() int +// - func (s *struct) String() string +// - [少部分实现]func (s *struct) Equal(other *struct) bool // -// xlayers 包提供了实现 gopacket.Layer 接口的 DNS 封装结构。 +// 这些方法使得可以方便地对 DNS 消息进行编解码。 // -// [xlayers.go]文件提供的 DNS 结构体可用于替换 gopacket.Layer 中原有的 DNS 结构体, -// 使 gopacket 使用dns包中的实现进行 DNS 消息的编解码。 -// -// // DNS 结构体用于替换 gopacket.Layer 中原有的 DNS 结构体, -// type DNS struct { -// layers.BaseLayer -// DNSMessage dns.DNSMessage -// } +// dns包对 DNS 消息的格式没有强制限制,并且支持对 未知类型的资源记录 进行编解码, +// 这使得其可以随意构造和解析 DNS 消息,来满足实验需求。 // -// ## xperi 子包 +// # xperi 子包 // // xperi 包实现了一些实验用函数。 // // 其中 dnssec.go 文件提供了一系列 DNSSEC 相关实验辅助函数。 +// // - ParseKeyBase64 用于解析 Base64 编码的 DNSKEY 为字节形式。 +// // - CalculateKeyTag 用于计算 DNSKEY 的 Key Tag。 -// - GenerateDNSKEY 根据参数生成 DNSKEY RDATA。 -// - GenerateRRSIG 根据参数对RRSET进行签名,生成 RRSIG RDATA。 -// - GenerateDS 根据参数生成 DNSKEY 的 DS RDATA。 +// +// - GenerateRDATADNSKEY 根据参数生成 DNSKEY RDATA。 +// +// - GenerateRDATARRSIG 根据参数对RRSET进行签名,生成 RRSIG RDATA。 +// +// - GenerateRDATADS 根据参数生成 DNSKEY 的 DS RDATA。 +// +// - GenerateRRDNSKEY 根据参数生成 DNSKEY RR。 +// +// - GenerateRRRRSIG 根据参数对RRSET进行签名,生成 RRSIG RR。 +// +// - GenerateRRDS 根据参数生成 DNSKEY 的 DS RR。 +// // - GenRandomRRSIG 用于生成一个随机的 RRSIG RDATA。 +// // - GenWrongKeyWithTag 用于生成错误的,但具有指定 KeyTag 的 DNSKEY RDATA。 +// // - GenKeyWithTag [该函数十分耗时] 用于生成一个具有指定 KeyTag 的 DNSKEY。 +// +// # English +// +// GoDNS is a fast and flexible experimental DNS server designed to help developers and researchers explore and experiment with various features of the DNS protocol. +// +// # GoDNSServer +// +// GoDNSServer is the top-level abstraction for a DNS server. +// +// GoDNSServer consists of the following three components: +// - ServerConfig: DNS server configuration +// - Netter: Packet handler +// - Responser: DNS responder +// +// [Netter] receives, parses, and sends packets while maintaining connection states. +// +// [Responser] responds to, parses, and constructs DNS replies. +// +// # Example +// +// You can quickly start a basic GoDNS server with the following lines of code: +// +// server := godns.GoDNSServer{ +// ServerConfig: sConf, +// Netter: godns.Netter{ +// Config: godns.NetterConfig{ +// Port: sConf.Port, +// MTU: sConf.MTU, +// }, +// }, +// Responser: &DullResponser{ +// ServerConf: sConf, +// }, +// } +// server.Start() +// +// # Constructing and Generating DNS Responses +// +// [Responser] is responsible for responding to, parsing, and constructing DNS replies. +// +// // Responser is a DNS responder interface. +// // Structures implementing this interface generate DNS responses based on DNS query information. +// type Responser interface { +// // Response generates a DNS response based on the DNS query information. +// // The parameter is: +// // - qInfo QueryInfo, DNS query information +// // The return value is: +// // - ResponseInfo, DNS response information +// // - error, an error if occurred +// Response(ConnectionInfo) (dns.DNSMessage, error) +// } +// +// By implementing the Responser interface, you can customize how DNS responses are generated. +// The responser.go file provides several examples of Responser implementations, +// as well as many utility functions like [ParseQueryInfo], [ParseResponseInfo], etc. +// +// You can refer to these implementations to create your own custom Responser, +// allowing you to construct DNS responses in any way you choose, and implement more complex reply logic. +// +// # dns package +// +// The dns package uses Go's built-in functions to provide DNS message encoding and decoding support. +// +// [dns.DNSMessage] is the top-level abstraction for a DNS message structure. +// +// // DNSMessage represents a DNS protocol message structure. +// +// type DNSMessage struct { +// // DNS message header +// Header DNSHeader // DNS header (Header) +// // Sections of the DNS message +// Question DNSQuestionSection // DNS query section (Questions Section) +// Answer DNSResponseSection // DNS answer section (Answers Section) +// Authority DNSResponseSection // DNS authority section (Authority Section) +// Additional DNSResponseSection // DNS additional section (Additional Section) +// } +// +// The dns package does not impose strict limitations on the DNS message format, +// and it supports encoding and decoding of unknown resource record types, +// allowing you to construct and parse DNS messages freely to meet experimental needs. +// +// # xperi subpackage +// +// The xperi package implements several experimental utility functions. +// +// The dnssec.go file provides a series of experimental functions related to DNSSEC. +// +// - ParseKeyBase64: Parses a Base64 encoded DNSKEY into a byte array. +// +// - CalculateKeyTag: Calculates the Key Tag for a DNSKEY. +// +// - GenerateRDATADNSKEY: Generates the DNSKEY RDATA based on parameters. +// +// - GenerateRDATARRSIG: Signs the RRSET and generates RRSIG RDATA. +// +// - GenerateRDATADS: Generates the DS RDATA for a DNSKEY. +// +// - GenerateRRDNSKEY: Generates a DNSKEY RR based on parameters. +// +// - GenerateRRRRSIG: Signs the RRSET and generates RRSIG RR. +// +// - GenerateRRDS: Generates the DS RR for a DNSKEY. +// +// - GenRandomRRSIG: Generates a random RRSIG RDATA. +// +// - GenWrongKeyWithTag: Generates an incorrect DNSKEY with a specified KeyTag. +// +// - GenKeyWithTag [This function is resource-intensive]: Generates a DNSKEY with a specified KeyTag. package godns diff --git a/docs/en/README.md b/docs/en/README.md index 249d3f6..a7fb483 100644 --- a/docs/en/README.md +++ b/docs/en/README.md @@ -8,109 +8,165 @@ [简体中文](../../README.md) | [English](README.md) -GoDNS is a fast and flexible **experimental** DNS server designed to help developers and researchers explore and experiment with various features of the DNS protocol. +GoDNS is a fast, flexible **experimental** DNS server designed to help developers and researchers explore and experiment with various features of the DNS protocol. ## Table of Contents -- [Overview](#overview) -- [GoDNSServer](#gondnserver) -- [Example](#example) -- [Constructing and Generating DNS Responses](#constructing-and-generating-dns-responses) +- [GoDNSServer](#godnsserver) +- [Examples](#examples) +- [Constructing and Generating DNS Replies](#constructing-and-generating-dns-replies) - [dns Package](#dns-package) +- [xlayers Subpackage](#xlayers-subpackage) - [xperi Subpackage](#xperi-subpackage) -## Overview +## GoDNSServer -`GoDNSServer` consists of three main components: +`GoDNSServer` is a top-level wrapper for the DNS server, consisting of three parts: 1. **ServerConfig**: Configuration for the DNS server. -2. **Sniffer**: A packet sniffer that listens on specified network devices and ports. -3. **Handler**: A packet handler responsible for processing DNS requests and generating responses. +2. **Netter**: Packet handler that receives, parses, and sends packets while maintaining connection state. +3. **Responser**: DNS responder that responds, parses, and constructs DNS replies. -## GoDNSServer +```go +type GoDNSServer struct { + ServerConfig DNSServerConfig + Netter Netter + Responer Responser +} -`GoDNSServer` is a top-level encapsulation of the DNS server, providing flexible interfaces and functionalities. +// Start the GoDNS server! +func (s *GoDNSServer) Start() +``` -### Sniffer +### Netter -`Sniffer` listens on specified network devices and ports to sniff DNS requests. +*`Netter` Packet Listener: Receives, parses, sends packets, and maintains connection state.* -### Handler +```go +type Netter struct { // size=16 (0x10) + Config NetterConfig +} -`Handler` is responsible for processing DNS requests and generating replies, consisting of the following four parts: +// Send function is used to send packets +func (n *Netter) Send(connInfo ConnectionInfo, data []byte) -- **Parser**: Parses DNS requests. -- **Responser**: Generates DNS replies. -- **Sender**: Sends DNS replies. -- **DNSServerConfig**: Records the configuration of the DNS server. +// Sniff function listens on a specified port and returns a channel of connection information +func (n *Netter) Sniff() chan ConnectionInfo -## Example +// handleListener function handles TCP connections +func (n *Netter) handleListener(lstr net.Listener, connChan chan ConnectionInfo) -You can start a basic GoDNS server with just a few lines of code: +// handlePktConn function handles packet connections +func (n *Netter) handlePktConn(pktConn net.PacketConn, connChan chan ConnectionInfo) + +// handleStreamConn function handles stream connections +func (n *Netter) handleStreamConn(conn net.Conn, connChan chan ConnectionInfo) +``` + +### Responser + +*`Responser` DNS Responder: Responds to DNS queries, parses, and constructs DNS replies.* + +`Responser` is an interface. The struct implementing this interface will generate DNS reply information based on DNS query information. + +```go +type Responser interface { // size=16 (0x10) + // Response generates DNS reply information based on DNS query data. + // Its argument is: + // - qInfo QueryInfo, DNS query information + // It returns: + // - ResponseInfo, DNS reply information + // - error, error information + Response(ConnectionInfo) (dns.DNSMessage, error) +} +``` + +## Examples + +With just a few lines of code, you can start a basic GoDNS server: ```go // Create a DNS server -server := &GoDNSServer{ - ServerConfig: serverConf, - Sniffer: []*Sniffer{ - NewSniffer(SnifferConfig{ - Device: serverConf.NetworkDevice, - Port: serverConf.Port, - PktMax: 65535, - Protocol: ProtocolUDP, - }), +server := godns.GoDNSServer{ + ServerConfig: sConf, + Netter: godns.Netter{ + Config: godns.NetterConfig{ + Port: sConf.Port, + MTU: sConf.MTU, + }, + }, + Responer: &DullResponser{ + ServerConf: sConf, }, - Handler: NewHandler(serverConf, &DullResponser{}), } server.Start() ``` -## Constructing and Generating DNS Responses +## Constructing and Generating DNS Replies -`Handler` is used to respond to and process DNS requests. By implementing the `Responser` interface, you can customize the generation of DNS replies. +You can customize how DNS replies are generated by implementing the `Responser` interface. -The `responser.go` file contains Serveral examples of `Responser` implementations for reference. +The `responser.go` file provides several `Responser` implementations and many auxiliary functions for reference. ## dns Package -The `dns` package uses Go's built-in functions to provide encoding and decoding implementations for DNS messages. +The `dns` package uses Go's built-in implementation to provide DNS message encoding and decoding capabilities, which can be used for constructing and parsing DNS messages. + +`DNSMessage` represents the structure of a DNS protocol message. + +```go +type DNSMessage struct { + // DNS message header + Header DNSHeader // DNS header + // Sections of the DNS message + Question DNSQuestionSection // Question section + Answer DNSResponseSection // Answer section + Authority DNSResponseSection // Authority section + Additional DNSResponseSection // Additional section +} +``` -### DNSMessage +Each structure in the `dns` package generally implements the following methods: -The `DNSMessage` structure represents the message of the DNS protocol, including: +```go +// Decode from buffer +func (s *struct) DecodeFromBuffer(buffer []byte, offset int) (int, error) -- **Header**: The DNS header. -- **Question**: The DNS query section. -- **Answer**: The DNS answer section. -- **Authority**: The authority section. -- **Additional**: The additional section. +// Encode to byte stream +func (s *struct) Encode() []byte -The `dns` package supports encoding and decoding of resource records of unknown types, providing flexibility to meet experimental needs. +// Encode to buffer +func (s *struct) EncodeToBuffer(buffer []byte) (int, error) -## xlayers Subpackage +// Get the actual size of the structure +func (s *struct) Size() int -The `xlayers` package provides DNS encapsulation structures that implement the `gopacket.Layer` interface, allowing replacement of the original DNS implementation in `gopacket.Layer`. +// Get the string representation of the structure +func (s *struct) String() string -```go -// DNS structure can be used to replace the original DNS implementation in gopacket.Layer -type DNS struct { - layers.BaseLayer - DNSMessage dns.DNSMessage -} +// [Partially implemented] Check if two structures are equal +func (s *struct) Equal(other *struct) bool ``` +These methods make it easy to encode and decode DNS messages. + +The `dns` package has no strict format constraints and supports encoding/decoding of unknown types of resource records, allowing it to construct and parse DNS messages as needed for experimentation. + ## xperi Subpackage -The `xperi` package implements various experimental functions, particularly auxiliary functions related to DNSSEC, including: +The `xperi` package implements some experimental functions, especially those related to DNSSEC, including: -- `ParseKeyBase64`: Parses Base64-encoded DNSKEY. +- `ParseKeyBase64`: Parses Base64-encoded DNSKEY into byte format. - `CalculateKeyTag`: Calculates the Key Tag of a DNSKEY. -- `GenerateDNSKEY`: Generates DNSKEY RDATA. -- `GenerateRRSIG`: Signs an RRSET to generate RRSIG RDATA. -- `GenerateDS`: Generates DS RDATA for a DNSKEY. -- `GenRandomRRSIG`: Generates random RRSIG RDATA. -- `GenWrongKeyWithTag`: Generates an incorrect DNSKEY RDATA with a specified Key Tag. -- `GenKeyWithTag`: Generates a DNSKEY with a specified Key Tag (this function is time-consuming). +- `GenerateRDATADNSKEY`: Generates DNSKEY RDATA based on parameters. +- `GenerateRDATARRSIG`: Signs an RRSET and generates RRSIG RDATA. +- `GenerateRDATADS`: Generates DS RDATA for a DNSKEY. +- `GenerateRRDNSKEY`: Generates a DNSKEY RR. +- `GenerateRRRRSIG`: Signs an RRSET and generates RRSIG RR. +- `GenerateRRDS`: Generates DS RR for a DNSKEY. +- `GenRandomRRSIG`: Generates a random RRSIG RDATA. +- `GenWrongKeyWithTag`: Generates a DNSKEY RDATA with a specified incorrect KeyTag. +- `GenKeyWithTag`: **[This function is resource-intensive]** Generates a DNSKEY with a specified KeyTag. ## License diff --git a/netter.go b/netter.go index 5142df7..3672959 100644 --- a/netter.go +++ b/netter.go @@ -12,7 +12,7 @@ type NetterConfig struct { MTU int } -// Netter 结构体用于表示网络监听器 +// Netter 数据包监听器:接收、解析、发送数据包,并维护连接状态。 type Netter struct { Config NetterConfig } @@ -56,7 +56,7 @@ func (n *Netter) handleListener(lstr net.Listener, connChan chan ConnectionInfo) } } -// handlePktConn 函数用于处理 数据包链接 +// handlePktConn 函数用于处理 数据包 链接 // 其接收参数为: // - pktConn: net.PacketConn,数据包链接 // - connChan: chan ConnectionInfo,链接信息通道 @@ -143,10 +143,10 @@ const ( ProtocolTCP Protocol = "tcp" ) -// Send 函数用于发送数据 +// Send 函数用于发送数据包 // 其接收参数为: // - connInfo: ConnectionInfo,链接信息 -// - data: []byte,数据 +// - data: []byte,数据包 func (n *Netter) Send(connInfo ConnectionInfo, data []byte) { if connInfo.Protocol == ProtocolUDP { _, err := connInfo.PacketConn.WriteTo(data, connInfo.Address) diff --git a/responser.go b/responser.go index 07b6aeb..fbb6645 100644 --- a/responser.go +++ b/responser.go @@ -14,7 +14,7 @@ import ( "github.com/tochusc/godns/dns/xperi" ) -// Responser 是一个 DNS 回复器接口。 +// Responser 是一个 DNS 回复器 接口。 // 实现该接口的结构体将根据 DNS 查询信息生成 DNS 回复信息。 type Responser interface { // Response 根据 DNS 查询信息生成 DNS 回复信息。 @@ -169,8 +169,8 @@ func FixCount(resp *dns.DNSMessage) { // 它会回复启用DNSSEC签名后的A记录信息, // 基本上是开启DNSSEC后的 “笨笨回复器”。 type DNSSECResponser struct { - sConf DNSServerConfig - dManager DNSSECManager + ServerConf DNSServerConfig + DNSSECManager DNSSECManager } // Response 根据 DNS 查询信息生成 DNS 回复信息。 @@ -198,13 +198,13 @@ func (d *DNSSECResponser) Response(connInfo ConnectionInfo) (dns.DNSMessage, err Class: dns.DNSClassIN, TTL: 86400, RDLen: 0, - RData: &dns.DNSRDATAA{Address: d.sConf.IP}, + RData: &dns.DNSRDATAA{Address: d.ServerConf.IP}, } resp.Answer = append(resp.Answer, rr) } // 为回复信息添加 DNSSEC 记录 - d.dManager.EnableDNSSEC(qry, &resp) + d.DNSSECManager.EnableDNSSEC(qry, &resp) // 设置RCODE,修正计数字段,返回回复信息 resp.Header.RCode = dns.DNSResponseCodeNoErr @@ -264,36 +264,36 @@ func (d *DNSSECManager) EnableDNSSEC(qry dns.DNSMessage, resp *dns.DNSMessage) { nMap[rr.Name] = append(nMap[rr.Name], rr) } for _, rrset := range nMap { + uName := dns.GetUpperDomainName(&rrset[0].Name) + dMat := GetDNSSECMaterial(d.DNSSECConf, d.DNSSECMap, uName) sig := xperi.GenerateRRRRSIG( rrset, d.DNSSECConf.DAlgo, uint32(time.Now().UTC().Unix()+86400-3600), uint32(time.Now().UTC().Unix()-3600), - uint16(d.DNSSECMap[rrset[0].Name].ZSKTag), - rrset[0].Name, - d.DNSSECMap[rrset[0].Name].PrivateZSK, + uint16(dMat.ZSKTag), + uName, + dMat.PrivateZSK, ) resp.Answer = append(resp.Answer, sig) } - for _, rr := range resp.Authority { - nMap[rr.Name] = append(nMap[rr.Name], rr) - } - // 签名权威部分 nMap = make(map[string][]dns.DNSResourceRecord) for _, rr := range resp.Authority { nMap[rr.Name] = append(nMap[rr.Name], rr) } for _, rrset := range nMap { + uName := dns.GetUpperDomainName(&rrset[0].Name) + dMat := GetDNSSECMaterial(d.DNSSECConf, d.DNSSECMap, uName) sig := xperi.GenerateRRRRSIG( rrset, d.DNSSECConf.DAlgo, uint32(time.Now().UTC().Unix()+86400-3600), uint32(time.Now().UTC().Unix()-3600), - uint16(d.DNSSECMap[rrset[0].Name].ZSKTag), - rrset[0].Name, - d.DNSSECMap[rrset[0].Name].PrivateZSK, + uint16(dMat.ZSKTag), + uName, + dMat.PrivateZSK, ) resp.Authority = append(resp.Authority, sig) } @@ -304,14 +304,16 @@ func (d *DNSSECManager) EnableDNSSEC(qry dns.DNSMessage, resp *dns.DNSMessage) { nMap[rr.Name] = append(nMap[rr.Name], rr) } for _, rrset := range nMap { + uName := dns.GetUpperDomainName(&rrset[0].Name) + dMat := GetDNSSECMaterial(d.DNSSECConf, d.DNSSECMap, uName) sig := xperi.GenerateRRRRSIG( rrset, d.DNSSECConf.DAlgo, uint32(time.Now().UTC().Unix()+86400-3600), uint32(time.Now().UTC().Unix()-3600), - uint16(d.DNSSECMap[rrset[0].Name].ZSKTag), - rrset[0].Name, - d.DNSSECMap[rrset[0].Name].PrivateZSK, + uint16(dMat.ZSKTag), + uName, + dMat.PrivateZSK, ) resp.Additional = append(resp.Additional, sig) } @@ -330,8 +332,8 @@ func (d *DNSSECManager) EnableDNSSEC(qry dns.DNSMessage, resp *dns.DNSMessage) { // // 该函数会为指定区域生成一个 KSK 和一个 ZSK,并生成一个 DNSKEY 记录和一个 RRSIG 记录。 func CreateDNSSECMaterial(dConf DNSSECConfig, zName string) DNSSECMaterial { - pubKSK, privKSKBytes := xperi.GenerateRRDNSKEY(dConf.DAlgo, dns.DNSKEYFlagSecureEntryPoint) - pubZSK, privZSKBytes := xperi.GenerateRRDNSKEY(dConf.DAlgo, dns.DNSKEYFlagZoneKey) + pubKSK, privKSKBytes := xperi.GenerateRRDNSKEY(zName, dConf.DAlgo, dns.DNSKEYFlagSecureEntryPoint) + pubZSK, privZSKBytes := xperi.GenerateRRDNSKEY(zName, dConf.DAlgo, dns.DNSKEYFlagZoneKey) kSKTag := xperi.CalculateKeyTag(*pubKSK.RData.(*dns.DNSRDATADNSKEY)) zSKTag := xperi.CalculateKeyTag(*pubZSK.RData.(*dns.DNSRDATADNSKEY)) // 生成密钥集签名 @@ -417,3 +419,56 @@ func EstablishToC(qry dns.DNSMessage, dConf DNSSECConfig, dMap map[string]DNSSEC FixCount(resp) return nil } + +// InitTrustAnchor 根据 DNSSEC 配置生成指定区域的信任锚点 +// 其接受参数为: +// - zName string,区域名 +// - dConf DNSSECConfig,DNSSEC 配置 +// - kBytes []byte,KSK 公钥 +// - pkBytes []byte,KSK 私钥 +// +// 返回值为: +// - map[string]DNSSECMaterial,生成的信任锚点 +func InitTrustAnchor(zName string, dConf DNSSECConfig, + kBytes, pkBytes []byte) map[string]DNSSECMaterial { + kRDATA := dns.DNSRDATADNSKEY{ + Flags: dns.DNSKEYFlagSecureEntryPoint, + Protocol: dns.DNSKEYProtocolValue, + Algorithm: dConf.DAlgo, + PublicKey: kBytes, + } + zRR, pzBytes := xperi.GenerateRRDNSKEY(zName, dConf.DAlgo, dns.DNSKEYFlagZoneKey) + zRDATA := zRR.RData.(*dns.DNSRDATADNSKEY) + + kTag := xperi.CalculateKeyTag(kRDATA) + zTag := xperi.CalculateKeyTag(*zRDATA) + + kRR := dns.DNSResourceRecord{ + Name: zName, + Type: dns.DNSRRTypeDNSKEY, + Class: dns.DNSClassIN, + TTL: 86400, + RDLen: uint16(kRDATA.Size()), + RData: &kRDATA, + } + + kSig := xperi.GenerateRRRRSIG( + []dns.DNSResourceRecord{zRR, kRR}, + dConf.DAlgo, + uint32(time.Now().UTC().Unix()+86400-3600), + uint32(time.Now().UTC().Unix()-3600), + uint16(kTag), + zName, + pkBytes, + ) + + return map[string]DNSSECMaterial{ + zName: { + KSKTag: int(kTag), + ZSKTag: int(zTag), + PrivateKSK: pkBytes, + PrivateZSK: pzBytes, + DNSKEYRespSec: []dns.DNSResourceRecord{zRR, kRR, kSig}, + }, + } +}