diff --git a/dns/dns.go b/dns/dns.go index ad082e6..ce14030 100644 --- a/dns/dns.go +++ b/dns/dns.go @@ -90,7 +90,7 @@ type DNSQuestionSection []DNSQuestion // DNSQuestion 表示DNS查询的问题记录 type DNSQuestion struct { - Name string + Name DNSName Type DNSType Class DNSClass } @@ -122,12 +122,16 @@ type DNSResponseSection []DNSResourceRecord // DNSResourceRecord 表示 DNS 资源记录。 // 设置RDLen为0时,将根据RData的实际大小进行编码。 type DNSResourceRecord struct { - Name string + Name DNSName Type DNSType Class DNSClass TTL uint32 RDLen uint16 RData DNSRRRDATA + + // 静态rdata(设置该值将使得Encode不再实时解码Rdata,而是直接使用该静态值) + IsStatic bool + Static_Rdata []byte } // DNSMessage 相关方法定义 @@ -172,7 +176,7 @@ func (dnsMessage *DNSMessage) Equal(other *DNSMessage) bool { return false } for i, question := range dnsMessage.Question { - if question != other.Question[i] { + if question.Equal(other.Question[i]) != true { return false } } @@ -180,7 +184,7 @@ func (dnsMessage *DNSMessage) Equal(other *DNSMessage) bool { return false } for i, answer := range dnsMessage.Answer { - if answer != other.Answer[i] { + if answer.Equal(other.Answer[i]) != true { return false } } @@ -188,7 +192,7 @@ func (dnsMessage *DNSMessage) Equal(other *DNSMessage) bool { return false } for i, authority := range dnsMessage.Authority { - if authority != other.Authority[i] { + if authority.Equal(other.Authority[i]) != true { return false } } @@ -196,7 +200,7 @@ func (dnsMessage *DNSMessage) Equal(other *DNSMessage) bool { return false } for i, additional := range dnsMessage.Additional { - if additional != other.Additional[i] { + if additional.Equal(other.Additional[i]) != true { return false } } @@ -469,19 +473,30 @@ func (dnsHeader *DNSHeader) DecodeFromBuffer(buffer []byte, offset int) (int, er // Size 返回DNS消息 的 问题部分的大小。 func (dnsQuestion *DNSQuestion) Size() int { - return GetDomainNameWireLen(&dnsQuestion.Name) + 4 + return dnsQuestion.Name.Length() + 4 } - -// String 以“易读的形式”返回DNS消息 的 问题部分的字符串表示。 func (dnsQuestion *DNSQuestion) String() string { return fmt.Sprint( "### DNS Question ###\n", - "Name: ", dnsQuestion.Name, "\n", + "Name: ", dnsQuestion.Name.String(), "\n", "Type: ", dnsQuestion.Type, "\n", "Class: ", dnsQuestion.Class, ) } +func (dnsQuestion *DNSQuestion) Equal(other DNSQuestion) bool { + if !dnsQuestion.Name.Equal(&other.Name) { + return false + } + if dnsQuestion.Type != other.Type { + return false + } + if dnsQuestion.Class != other.Class { + return false + } + return true +} + // Size 返回DNS消息 的 问题部分的大小。 func (section DNSQuestionSection) Size() int { size := 0 @@ -509,7 +524,7 @@ func (section DNSQuestionSection) Equal(other DNSQuestionSection) bool { return false } for i, question := range section { - if question != other[i] { + if !question.Equal(other[i]) { return false } } @@ -554,7 +569,7 @@ func (section DNSQuestionSection) EncodeToBuffer(buffer []byte) (int, error) { func (dnsQuestion *DNSQuestion) DecodeFromBuffer(buffer []byte, offset int) (int, error) { var err error // 解码域名 - dnsQuestion.Name, offset, err = DecodeDomainNameFromBuffer(buffer, offset) + dnsQuestion.Name, offset, err = NewDNSNameFromBuffer(buffer, offset) if err != nil { return -1, fmt.Errorf("method DNSQuestion DecodeFromBuffer failed: decode Name failed.\n%s", err) } @@ -568,7 +583,7 @@ func (dnsQuestion *DNSQuestion) DecodeFromBuffer(buffer []byte, offset int) (int // Encode 将 DNS消息的问题部分 编码到 字节切片 中。 func (dnsQuestion *DNSQuestion) Encode() []byte { buffer := make([]byte, dnsQuestion.Size()) - offset, err := EncodeDomainNameToBuffer(&dnsQuestion.Name, buffer) + offset, err := dnsQuestion.Name.EncodeToBuffer(buffer) if err != nil { panic(fmt.Sprintf("method DNSQuestion Encode failed: encode Question name failed\n%s\n", err)) } @@ -586,7 +601,7 @@ func (dnsQuestion *DNSQuestion) EncodeToBuffer(buffer []byte) (int, error) { if len(buffer) < dqSize { return -1, fmt.Errorf("EncodeToBuffer failed: buffer length %d is less than DNSQuestion size %d", len(buffer), dqSize) } - _, err := EncodeDomainNameToBuffer(&dnsQuestion.Name, buffer) + _, err := dnsQuestion.Name.EncodeToBuffer(buffer) if err != nil { return -1, err } @@ -619,7 +634,7 @@ func (responseSection DNSResponseSection) Equal(other DNSResponseSection) bool { return false } for i, record := range responseSection { - if record != other[i] { + if !record.Equal(other[i]) { return false } } @@ -675,10 +690,35 @@ func (responseSection DNSResponseSection) DecodeFromBuffer(buffer []byte, offset return offset, nil } +// DNSResourceRecord 相关方法定义 + // Size 返回 DNS 资源记录的*准确*大小。 // - RDLength 字段可由用户自行设置一个错误的值。 func (rr *DNSResourceRecord) Size() int { - return GetDomainNameWireLen(&rr.Name) + 10 + rr.RData.Size() + return rr.Name.Length() + 10 + rr.RData.Size() +} + +func (rr *DNSResourceRecord) Equal(other DNSResourceRecord) bool { + if !rr.Name.Equal(&other.Name) { + return false + } + if rr.Type != other.Type { + return false + } + if rr.Class != other.Class { + return false + } + if rr.TTL != other.TTL { + return false + } + if rr.RDLen != other.RDLen { + return false + } + if !rr.RData.Equal(other.RData) { + return false + } + // 其他字段相等 + return true } // String 以*易读的形式*返回 DNS 资源记录的字符串表示。 @@ -686,7 +726,7 @@ func (rr *DNSResourceRecord) Size() int { func (rr *DNSResourceRecord) String() string { return fmt.Sprint( "### DNS Resource Record ###\n", - "Name:", rr.Name, "\n", + "Name:", rr.Name.String(), "\n", "Type:", rr.Type, "\n", "Class:", rr.Class, "\n", "TTL:", rr.TTL, "\n", @@ -695,21 +735,53 @@ func (rr *DNSResourceRecord) String() string { ) } +// EncodeStaticRData 将 DNS 资源记录的 RData 编码为静态数据。 +// - 该方法将 RData 的编码结果存储在 Static_Rdata 字段中。 +// - 同时将 IsStatic 字段设置为 true 并修改 RDLen 字段。 +func (rr *DNSResourceRecord) EncodeStaticRData() { + rr.IsStatic = true + rr.Static_Rdata = rr.RData.Encode() + rr.RDLen = uint16(len(rr.Static_Rdata)) +} + +// DecodeStaticRData 将 DNS 资源记录的静态数据解码为 RData。 +// - 该方法将 Static_Rdata 字段的值解码为 RData。 +// - 同时将 IsStatic 字段设置为 false 并修改 RDLen 字段。 +// - 该方法在调用时,Static_Rdata 字段必须已经被设置为有效的静态数据。 +func (rr *DNSResourceRecord) DecodeStaticRData() { + rr.IsStatic = false + + rr.RData = DNSRRRDATAFactory(rr.Type) + rr.RDLen = uint16(len(rr.Static_Rdata)) + + rr.RData.DecodeFromBuffer(rr.Static_Rdata, 0, int(rr.RDLen)) +} + // Encode 方法编码 DNS 资源记录至返回的字节切片中。 // - 其返回值为 编码后的字节切片 。 func (rr *DNSResourceRecord) Encode() []byte { byteArray := make([]byte, rr.Size()) - offset, err := EncodeDomainNameToBuffer(&rr.Name, byteArray) + offset, err := rr.Name.EncodeToBuffer(byteArray) if err != nil { panic(fmt.Sprintf("method DNSResourceRecord Encode failed: encode Name failed\n%s\n", err)) } binary.BigEndian.PutUint16(byteArray[offset:], uint16(rr.Type)) binary.BigEndian.PutUint16(byteArray[offset+2:], uint16(rr.Class)) binary.BigEndian.PutUint32(byteArray[offset+4:], rr.TTL) - rdLen, err := rr.RData.EncodeToBuffer(byteArray[offset+10:]) - if err != nil { - panic(fmt.Sprintf("method DNSResourceRecord Encode failed: encode RDATA failed\n%s\n", err)) + + rdLen := int(rr.RDLen) + if rr.IsStatic { + rdLen = len(rr.Static_Rdata) + copy(byteArray[offset+10:], rr.Static_Rdata) + } else { + var err error + rdLen, err = rr.RData.EncodeToBuffer(byteArray[offset+10:]) + if err != nil { + panic(fmt.Sprintf("method DNSResourceRecord Encode failed: encode RDATA failed\n%s\n", err)) + } } + + // 如果用户设置了 RDLen,则使用用户设置的值,否则使用编码后的长度。 if rr.RDLen == 0 { binary.BigEndian.PutUint16(byteArray[offset+8:], uint16(rdLen)) } else { @@ -724,7 +796,7 @@ func (rr *DNSResourceRecord) Encode() []byte { // // 如果出现错误,返回 -1 和 相应报错。 func (rr *DNSResourceRecord) EncodeToBuffer(buffer []byte) (int, error) { - offset, err := EncodeDomainNameToBuffer(&rr.Name, buffer) + offset, err := rr.Name.EncodeToBuffer(buffer) if err != nil { return -1, err } @@ -752,11 +824,10 @@ func (rr *DNSResourceRecord) EncodeToBuffer(buffer []byte) (int, error) { func (rr *DNSResourceRecord) DecodeFromBuffer(buffer []byte, offset int) (int, error) { var err error // 解码域名 - name, offset, err := DecodeDomainNameFromBuffer(buffer, offset) + rr.Name, offset, err = NewDNSNameFromBuffer(buffer, offset) if err != nil { return -1, err } - rr.Name = name // 解码类型 rr.Type = DNSType(binary.BigEndian.Uint16(buffer[offset:])) // 解码类 diff --git a/dns/dns_test.go b/dns/dns_test.go index e138bef..f114d12 100644 --- a/dns/dns_test.go +++ b/dns/dns_test.go @@ -105,7 +105,7 @@ func TestDNSHeaderDecodeFromBuffer(t *testing.T) { // 待测试的 DNSQuestion 对象。 var testedDNSQuestion = DNSQuestion{ - Name: "www.example.com", + Name: *NewDNSName("www.example.com"), Type: DNSRRTypeA, Class: DNSClassIN, } @@ -176,7 +176,7 @@ func TestDNSQuestionDecodeFromBuffer(t *testing.T) { t.Errorf(" function DNSQuestionDecodeFromBuffer() failed:\ngot:%d\nexpected: %d", offset, len(testedDNSQuestionEncoded)) } - if decodedDNSQuestion != testedDNSQuestion { + if !decodedDNSQuestion.Equal(testedDNSQuestion) { t.Errorf(" function DNSQuestionDecodeFromBuffer() failed:\ngot:\n%v\nexpected:\n%v", decodedDNSQuestion, testedDNSQuestion) } diff --git a/dns/metarr.go b/dns/metarr.go index a9156ab..d19132f 100644 --- a/dns/metarr.go +++ b/dns/metarr.go @@ -17,7 +17,7 @@ func IsPseudoRR(rr *DNSResourceRecord) bool { // NewDNSRROPT creates a new DNS Resource Record OPT func NewDNSRROPT(udpsize int, ttl int, rdata *DNSRDATAOPT) *DNSResourceRecord { return &DNSResourceRecord{ - Name: ".", + Name: *NewDNSName("."), Type: 41, Class: DNSClass(udpsize), TTL: uint32(ttl), @@ -41,16 +41,17 @@ func NewPseudoRR(rr *DNSResourceRecord) PseudoRR { // DNSRROPT is a DNS Resource Record OPT // See RFC 6891 -// +------------+--------------+------------------------------+ -// | Field Name | Field Type | Description | -// +------------+--------------+------------------------------+ -// | NAME | domain name | MUST be 0 (root domain) | -// | TYPE | u_int16_t | OPT (41) | -// | CLASS | u_int16_t | requestor’s UDP payload size | -// | TTL | u_int32_t | extended RCODE and flags | -// | RDLEN | u_int16_t | length of all RDATA | -// | RDATA | octet stream | {attribute,value} pairs | -// +------------+--------------+------------------------------+ +// +// +------------+--------------+------------------------------+ +// | Field Name | Field Type | Description | +// +------------+--------------+------------------------------+ +// | NAME | domain name | MUST be 0 (root domain) | +// | TYPE | u_int16_t | OPT (41) | +// | CLASS | u_int16_t | requestor’s UDP payload size | +// | TTL | u_int32_t | extended RCODE and flags | +// | RDLEN | u_int16_t | length of all RDATA | +// | RDATA | octet stream | {attribute,value} pairs | +// +------------+--------------+------------------------------+ type DNSRROPT struct { rr *DNSResourceRecord } diff --git a/dns/rdata.go b/dns/rdata.go index 62857db..4777b96 100644 --- a/dns/rdata.go +++ b/dns/rdata.go @@ -45,7 +45,7 @@ type DNSRRRDATA interface { // Equal(DNSRRRDATA) bool - /* TODO: Mais 等到真正需要时再实现吧? + /* TODO: // Masterlize 方法以*Master File中的ASCII表示*返回对应 资源记录 RDATA 部分的 字符串表示。 // - 其返回值为 RDATA 部分的字符串表示。 Masterlize() string diff --git a/dns/standard.go b/dns/standard.go index ce9384e..7c3de28 100644 --- a/dns/standard.go +++ b/dns/standard.go @@ -4,7 +4,14 @@ // 其目前包括 , 的编解码函数。 // 关于 的详细定义 // 请参阅 RFC 1035 3.3节 Standard RRs。 -// +package dns + +import ( + "encoding/binary" + "fmt" + "strings" +) + // # // // 对于 的编码,可接受 绝对域名 及 相对域名, @@ -34,27 +41,104 @@ // - 以指针结尾的标签序列。 // // 详细内容请参阅 RFC 1035 4.1.4. Message compression -// -// # -// -// [ RFC 1035 ] 规定了 DNS 字符串的相关定义。 -// DNS 字符串是一系列字符的序列,其编码格式为:字符串长度 + 字符串内容。 -// 字符串长度为一个字节,表示字符串的长度,字符串内容为字符串的实际内容。 -// 长度字节为0时,表示空字符串,长度最大为255,即 DNS 字符串最大长度为255。 -package dns - -import ( - "encoding/binary" - "fmt" - "strings" +const ( + NamePointerFlag = 0xC0 ) -// GetDomainNameWireLen 返回域名的 编码格式长度。 -// - 其接收参数为 域名字符串 的指针, -// - 返回值为域名的 编码格式长度。 -// -// 可以接收绝对域名及相对域名,所有域名均以绝对域名的长度计算。 +type DNSName struct { + DomainName string + WiredBytes []byte +} + +func (dn *DNSName) InitFromName(name string) { + dn.DomainName = name + dn.WiredBytes = EncodeDomainName(&name) +} + +func (dn *DNSName) InitFromWiredBytes(data []byte) { + dn.DomainName = DecodeDomainName(data) + dn.WiredBytes = data +} + +func (dn *DNSName) InitFromBuffer(data []byte, offset int) (int, error) { + name, nOffset, err := DecodeDomainNameFromBuffer(data, offset) + if err != nil { + return -1, fmt.Errorf("InitFromBuffer error: %s", err) + } + dn.DomainName = name + dn.WiredBytes = data[offset:nOffset] + return nOffset, nil +} + +func NewDNSName(name string) *DNSName { + return &DNSName{ + DomainName: name, + WiredBytes: EncodeDomainName(&name), + } +} + +func NewDNSNameFromBuffer(data []byte, offset int) (DNSName, int, error) { + name, nOffset, err := DecodeDomainNameFromBuffer(data, offset) + if err != nil { + return DNSName{}, -1, fmt.Errorf("NewDNSNameFromBuffer error: %s", err) + } + dn := DNSName{ + DomainName: name, + WiredBytes: data[offset:nOffset], + } + return dn, nOffset, nil +} + +func NewDNSNameFromWiredBytes(data []byte) *DNSName { + name := DecodeDomainName(data) + dn := &DNSName{ + DomainName: name, + WiredBytes: data, + } + return dn +} + +func (dn *DNSName) Length() int { + return len(dn.WiredBytes) +} + +func (dn *DNSName) String() string { + return dn.DomainName +} + +func (dn *DNSName) Equal(other *DNSName) bool { + if dn.DomainName == other.DomainName { + return true + } + return false +} + +func (dn *DNSName) Encode() []byte { + return dn.WiredBytes +} + +func (dn *DNSName) EncodeToBuffer(buffer []byte) (int, error) { + encodedLen := len(dn.WiredBytes) + if len(buffer) < encodedLen { + return -1, fmt.Errorf( + "EncodeToBuffer error: buffer is too small, require %d byte size, but got %d", + encodedLen, len(buffer)) + } + copy(buffer, dn.WiredBytes) + return encodedLen, nil +} + +func (dn *DNSName) DecodeFromBuffer(data []byte, offset int) (int, error) { + name, nOffset, err := DecodeDomainNameFromBuffer(data, offset) + if err != nil { + return -1, fmt.Errorf("DecodeFromBuffer error: %s", err) + } + dn.DomainName = name + dn.WiredBytes = data[offset:nOffset] + return nOffset, nil +} + func GetDomainNameWireLen(name *string) int { nameLength := len(*name) if (*name)[nameLength-1] == '.' { @@ -85,7 +169,7 @@ func GetUpperDomainName(name *string) string { func GetQueryQuestionName(qry DNSMessage) []string { nList := make([]string, len(qry.Question)) for i := 0; i < len(qry.Question); i++ { - name := strings.ToLower(qry.Question[0].Name) + name := strings.ToLower(qry.Question[0].Name.DomainName) nList[i] = name } return nList @@ -164,10 +248,6 @@ func EncodeDomainNameToBuffer(name *string, buffer []byte) (int, error) { return encodedLen, nil } -const ( - NamePointerFlag = 0xC0 -) - // DecodeDomainName 解码域名,其接受字节切片,并返回解码后域名。 // 返回的域名为*相对域名*,即不以'.'结尾。 // 若域名为根域名,则返回"." @@ -187,6 +267,7 @@ func DecodeDomainName(data []byte) string { } } +// DecodeDomainNameFromDNSBuffer 从 DNS 报文中解码域名。 // DecodeDomainNameFromDNSBuffer 从 DNS 报文中解码域名。 // - 其接收参数为 DNS 报文 和 域名的偏移量, // - 返回值为 解码后的域名, 解码后的偏移量 及 报错信息。 @@ -251,6 +332,18 @@ func CountDomainNameLabels(name *string) int { return labelNum + 1 } +// # +// +// [ RFC 1035 ] 规定了 DNS 字符串的相关定义。 +// DNS 字符串是一系列字符的序列,其编码格式为:字符串长度 + 字符串内容。 +// 字符串长度为一个字节,表示字符串的长度,字符串内容为字符串的实际内容。 +// 长度字节为0时,表示空字符串,长度最大为255,即 DNS 字符串最大长度为255。 + +// GetDomainNameWireLen 返回域名的 编码格式长度。 +// - 其接收参数为 域名字符串 的指针, +// - 返回值为域名的 编码格式长度。 +// +// 可以接收绝对域名及相对域名,所有域名均以绝对域名的长度计算。 // GetCharacterStrWireLen 返回字符串的 编码格式长度。 func GetCharacterStrWireLen(cStr *string) int { strLen := len(*cStr) diff --git a/dns/standard_test.go b/dns/standard_test.go index 8062557..6673651 100644 --- a/dns/standard_test.go +++ b/dns/standard_test.go @@ -91,7 +91,7 @@ func TestEncodeDomainNameToBuffer(t *testing.T) { func TestCanonicalSortRRSet(t *testing.T) { rrSet := []DNSResourceRecord{ { - Name: "example.com.", + Name: *NewDNSName("example.com."), Type: DNSRRTypeA, Class: DNSClassIN, TTL: 7200, @@ -100,7 +100,7 @@ func TestCanonicalSortRRSet(t *testing.T) { }, }, { - Name: "example.com.", + Name: *NewDNSName("example.com."), Type: DNSRRTypeA, Class: DNSClassIN, TTL: 7200, @@ -109,7 +109,7 @@ func TestCanonicalSortRRSet(t *testing.T) { }, }, { - Name: "example.com.", + Name: *NewDNSName("example.com."), Type: DNSRRTypeA, Class: DNSClassIN, TTL: 7200, @@ -140,14 +140,14 @@ func TestCompressDNSMessage(t *testing.T) { }, Question: []DNSQuestion{ { - Name: "example.com", + Name: *NewDNSName("example.com."), Type: DNSRRTypeA, Class: DNSClassIN, }, }, Answer: []DNSResourceRecord{ { - Name: "example.com", + Name: *NewDNSName("example.com."), Type: DNSRRTypeA, Class: DNSClassIN, TTL: 7200, @@ -156,7 +156,7 @@ func TestCompressDNSMessage(t *testing.T) { }, }, { - Name: "example.com", + Name: *NewDNSName("example.com."), Type: DNSRRTypeA, Class: DNSClassIN, TTL: 7200, @@ -165,7 +165,7 @@ func TestCompressDNSMessage(t *testing.T) { }, }, { - Name: "example.com", + Name: *NewDNSName("example.com."), Type: DNSRRTypeA, Class: DNSClassIN, TTL: 7200, diff --git a/dns/xperi/dnssec.go b/dns/xperi/dnssec.go index 112dada..e3a0486 100644 --- a/dns/xperi/dnssec.go +++ b/dns/xperi/dnssec.go @@ -82,7 +82,7 @@ func GenerateRRDNSKEY( zName string, algo dns.DNSSECAlgorithm, flag dns.DNSKEYFlag) (dns.DNSResourceRecord, []byte) { rdata, privKey := GenerateRDATADNSKEY(algo, flag) rr := dns.DNSResourceRecord{ - Name: zName, + Name: *dns.NewDNSName(zName), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, @@ -117,7 +117,7 @@ func GenerateRDATARRSIG(rrSet []dns.DNSResourceRecord, algo dns.DNSSECAlgorithm, rrsig := dns.DNSRDATARRSIG{ TypeCovered: rrSet[0].Type, Algorithm: algo, - Labels: uint8(dns.CountDomainNameLabels(&rrSet[0].Name)), + Labels: uint8(dns.CountDomainNameLabels(&rrSet[0].Name.DomainName)), OriginalTTL: rrSet[0].TTL, Expiration: expiration, Inception: inception, @@ -206,7 +206,7 @@ func GenerateRDATADS(oName string, kRDATA dns.DNSRDATADNSKEY, dType dns.DNSSECDi // 2. 构建明文 pText := make([]byte, dns.GetDomainNameWireLen(&oName)+kRDATA.Size()) - offset, err := dns.EncodeDomainNameToBuffer(&oName, pText) + offset, err := dns.NewDNSName(oName).EncodeToBuffer(pText) if err != nil { panic(fmt.Sprintf("failed to write domain name: %s", err)) } @@ -252,7 +252,7 @@ func GenerateRDATADS(oName string, kRDATA dns.DNSRDATADNSKEY, dType dns.DNSSECDi func GenerateRRDS(oName string, kRDATA dns.DNSRDATADNSKEY, dType dns.DNSSECDigestType) dns.DNSResourceRecord { rdata := GenerateRDATADS(oName, kRDATA, dType) rr := dns.DNSResourceRecord{ - Name: oName, + Name: *dns.NewDNSName(oName), Type: dns.DNSRRTypeDS, Class: dns.DNSClassIN, TTL: 86400, @@ -398,7 +398,7 @@ func GenerateRandomRDATARRSIG(rrSet []dns.DNSResourceRecord, algo dns.DNSSECAlgo return dns.DNSRDATARRSIG{ TypeCovered: rrSet[0].Type, Algorithm: algo, - Labels: uint8(dns.CountDomainNameLabels(&rrSet[0].Name)), + Labels: uint8(dns.CountDomainNameLabels(&rrSet[0].Name.DomainName)), OriginalTTL: 8, Expiration: expiration, Inception: inception, @@ -462,7 +462,7 @@ func GenerateRandomRDATADS(oName string, keytag int, algo dns.DNSSECAlgorithm, d func GenerateRandomRRDS(oName string, keytag int, algo dns.DNSSECAlgorithm, dType dns.DNSSECDigestType) dns.DNSResourceRecord { rdata := GenerateRandomRDATADS(oName, keytag, algo, dType) rr := dns.DNSResourceRecord{ - Name: oName, + Name: *dns.NewDNSName(oName), Type: dns.DNSRRTypeDS, Class: dns.DNSClassIN, TTL: 86400, diff --git a/dns/xperi/dnssec_test.go b/dns/xperi/dnssec_test.go index b8b03ee..34036b0 100644 --- a/dns/xperi/dnssec_test.go +++ b/dns/xperi/dnssec_test.go @@ -74,7 +74,7 @@ func TestGenenrateDNSKEYWithTag(t *testing.T) { func TestGenerateRandomRRSIG(t *testing.T) { rrSet := []dns.DNSResourceRecord{ { - Name: "example.com.", + Name: *dns.NewDNSName("example.com."), Type: dns.DNSRRTypeA, Class: dns.DNSClassIN, TTL: 7200, @@ -123,7 +123,7 @@ func TestCalculateKeyTag(t *testing.T) { func TestGenerateRRSIG(t *testing.T) { rrSet := []dns.DNSResourceRecord{ { - Name: "example.com.", + Name: *dns.NewDNSName("example.com."), Type: dns.DNSRRTypeA, Class: dns.DNSClassIN, TTL: 7200, diff --git a/example/retrap/main.go b/example/retrap/main.go index a0f5325..df3f45f 100644 --- a/example/retrap/main.go +++ b/example/retrap/main.go @@ -67,7 +67,7 @@ var ExperiVec = AttackVector{ // CNAMETrap CNAMEChainNum: 0, // ReferrerTrap - NSRRNum: 5, + NSRRNum: 0, // NSECTrap IsNSEC: true, @@ -200,16 +200,16 @@ func (m *KeyTrapManager) SignSection(section []dns.DNSResourceRecord) []dns.DNSR if rr.Type == dns.DNSRRTypeRRSIG { continue } - rid := rr.Name + rr.Type.String() + rr.Class.String() + rid := rr.Name.DomainName + rr.Type.String() + rr.Class.String() rMap[rid] = append(rMap[rid], rr) } for _, rrset := range rMap { // SigJam攻击向量:CollidedSigNum // 生成 错误RRSIG 记录 - uName := dns.GetUpperDomainName(&rrset[0].Name) + uName := dns.GetUpperDomainName(&rrset[0].Name.DomainName) dMat := m.GetDNSSECMaterial(uName) - if len(strings.Split(rrset[0].Name, ".")) == 3 && rrset[0].Name[0:1] == "w" { + if len(strings.Split(rrset[0].Name.DomainName, ".")) == 3 && rrset[0].Name.DomainName[0:1] == "w" { for i := 0; i < m.AttackVec.CollidedSigNum+m.AttackVec.CollidedSigForRR; i++ { wRRSIG := xperi.GenerateRandomRRRRSIG( rrset, @@ -252,7 +252,7 @@ func (m *KeyTrapManager) SignSection(section []dns.DNSResourceRecord) []dns.DNSR } } - for i := 1; i <= m.AttackVec.Invalid_SIG_ZSK_PairNum-m.AttackVec.SIGPairDecreaseFactor*len(strings.Split(rrset[0].Name, ".")); i++ { + for i := 1; i <= m.AttackVec.Invalid_SIG_ZSK_PairNum-m.AttackVec.SIGPairDecreaseFactor*len(strings.Split(rrset[0].Name.DomainName, ".")); i++ { keytag := dMat.ZSKTag - i for j := 0; j < m.AttackVec.InvalidCollidedSigNum; j++ { wRRSIG := xperi.GenerateRandomRRRRSIG( @@ -278,16 +278,16 @@ func (m *KeyTrapManager) SignSection(section []dns.DNSResourceRecord) []dns.DNSR // - rrset []dns.DNSResourceRecord,RR 集合 func (m *KeyTrapManager) SignRRSet(rrset []dns.DNSResourceRecord) dns.DNSResourceRecord { var uName string - if len(strings.Split(rrset[0].Name, ".")) == 2 { + if len(strings.Split(rrset[0].Name.DomainName, ".")) == 2 { if rrset[0].Type == dns.DNSRRTypeNSEC || rrset[0].Type == dns.DNSRRTypeNS || rrset[0].Type == dns.DNSRRTypeNSEC3 { - uName = rrset[0].Name + uName = rrset[0].Name.DomainName } else { - uName = dns.GetUpperDomainName(&rrset[0].Name) + uName = dns.GetUpperDomainName(&rrset[0].Name.DomainName) } } else { - uName = dns.GetUpperDomainName(&rrset[0].Name) + uName = dns.GetUpperDomainName(&rrset[0].Name.DomainName) } dMat := m.GetDNSSECMaterial(uName) @@ -366,8 +366,6 @@ func (m *KeyTrapManager) CreateDNSSECMaterial(zName string) DNSSECMaterial { kskRecord, kskPriv := xperi.GenerateRRDNSKEY(zName, m.DNSSECConf.Algo, dns.DNSKEYFlagSecureEntryPoint) kskTag := xperi.CalculateKeyTag(*kskRecord.RData.(*dns.DNSRDATADNSKEY)) - kskRecord, kskPriv = xperi.GenerateRRDNSKEY(zName, m.DNSSECConf.Algo, dns.DNSKEYFlagSecureEntryPoint) - kskTag = xperi.CalculateKeyTag(*kskRecord.RData.(*dns.DNSRDATADNSKEY)) return DNSSECMaterial{ ZSKTag: int(zskTag), @@ -405,7 +403,7 @@ func (m *KeyTrapManager) GetDNSSECMaterial(zName string) DNSSECMaterial { func (m *KeyTrapManager) EstablishToC(qry dns.DNSMessage, resp *dns.DNSMessage) error { // 提取查询类型和查询名称 qType := qry.Question[0].Type - qName := strings.ToLower(qry.Question[0].Name) + qName := strings.ToLower(qry.Question[0].Name.DomainName) dMat := m.GetDNSSECMaterial(qName) if qType == dns.DNSRRTypeDNSKEY { @@ -419,7 +417,7 @@ func (m *KeyTrapManager) EstablishToC(qry dns.DNSMessage, resp *dns.DNSMessage) *dMat.ZSKRecord.RData.(*dns.DNSRDATADNSKEY), ) rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, @@ -448,7 +446,7 @@ func (m *KeyTrapManager) EstablishToC(qry dns.DNSMessage, resp *dns.DNSMessage) i, ) rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, @@ -476,7 +474,7 @@ func (m *KeyTrapManager) EstablishToC(qry dns.DNSMessage, resp *dns.DNSMessage) *dMat.KSKRecord.RData.(*dns.DNSRDATADNSKEY), ) rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, @@ -493,7 +491,7 @@ func (m *KeyTrapManager) EstablishToC(qry dns.DNSMessage, resp *dns.DNSMessage) *dMat.KSKRecord.RData.(*dns.DNSRDATADNSKEY), ) rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, @@ -530,7 +528,7 @@ func (m *KeyTrapManager) EstablishToC(qry dns.DNSMessage, resp *dns.DNSMessage) offset := rTag - tTag wKSK := xperi.GenerateDNSKEYWithTag(rKSK, int(offset)) rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, @@ -553,7 +551,7 @@ func (m *KeyTrapManager) EstablishToC(qry dns.DNSMessage, resp *dns.DNSMessage) ) rkey.Flags = m.AttackVec.RandomDNSKEYFlag rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, @@ -731,7 +729,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error } // 将可能启用0x20混淆的查询名称转换为小写 - qName := strings.ToLower(qry.Question[0].Name) + qName := strings.ToLower(qry.Question[0].Name.DomainName) qType := qry.Question[0].Type qClass := qry.Question[0].Class @@ -752,7 +750,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error // NS Amplification攻击向量:NSRRNum for i := 1; i <= r.AttackVector.NSRRNum; i++ { rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeNS, Class: dns.DNSClassIN, TTL: 86400, @@ -761,7 +759,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error } resp.Authority = append(resp.Authority, rr) rra := dns.DNSResourceRecord{ - Name: fmt.Sprintf("ns%d.%s", i, qName), + Name: *dns.NewDNSName(fmt.Sprintf("ns%d.%s", i, qName)), Type: dns.DNSRRTypeA, Class: dns.DNSClassIN, TTL: 86400, @@ -776,7 +774,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error resp.Additional = r.DNSSECManager.SignSection(resp.Additional) SOARDATA.MName = "ns1." + qName soa := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeSOA, Class: dns.DNSClassIN, TTL: 86400, @@ -802,7 +800,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error } } else if len(qLables) == 3 { rra := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeA, Class: dns.DNSClassIN, TTL: 86400, @@ -851,7 +849,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error } rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeCNAME, Class: dns.DNSClassIN, TTL: 86400, @@ -881,7 +879,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error TypeBitMaps: []dns.DNSType{dns.DNSRRTypeA}, } rr := dns.DNSResourceRecord{ - Name: fmt.Sprintf("0%d.", randInt+i-1) + upperName, + Name: *dns.NewDNSName(fmt.Sprintf("0%d.", randInt+i-1) + upperName), Type: dns.DNSRRTypeNSEC, Class: dns.DNSClassIN, TTL: 86400, @@ -895,7 +893,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error TypeBitMaps: []dns.DNSType{dns.DNSRRTypeA}, } rr := dns.DNSResourceRecord{ - Name: fmt.Sprintf("0%d.", randInt+r.AttackVector.NSECRRNum) + upperName, + Name: *dns.NewDNSName(fmt.Sprintf("0%d.", randInt+r.AttackVector.NSECRRNum) + upperName), Type: dns.DNSRRTypeNSEC, Class: dns.DNSClassIN, TTL: 86400, @@ -910,7 +908,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error return []byte{}, err } rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeA, Class: dns.DNSClassIN, TTL: 86400, @@ -920,7 +918,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error resp.Answer = append(resp.Answer, rr) } else { rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeA, Class: dns.DNSClassIN, TTL: 86400, @@ -934,7 +932,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error case dns.DNSRRTypeNS: // 生成 NS 记录 rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeNS, Class: dns.DNSClassIN, TTL: 86400, @@ -943,7 +941,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error } resp.Answer = append(resp.Answer, rr) rra := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeA, Class: dns.DNSClassIN, TTL: 86400, @@ -964,7 +962,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error TXT: string(rRDATA), } rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeTXT, Class: dns.DNSClassIN, TTL: 86400, @@ -980,7 +978,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error TXT: r.AttackVector.RandomString, } rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeTXT, Class: dns.DNSClassIN, TTL: 86400, @@ -1000,7 +998,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error Minimum: 86400, } soa := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeSOA, Class: dns.DNSClassIN, TTL: 86400, @@ -1022,7 +1020,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error TXT: txt, } rr := dns.DNSResourceRecord{ - Name: fmt.Sprintf("txt%d.", i) + upperName, + Name: *dns.NewDNSName(fmt.Sprintf("txt%d.", i) + upperName), Type: dns.DNSRRTypeTXT, Class: dns.DNSClassIN, TTL: 86400, @@ -1049,7 +1047,7 @@ func (r *KeyTrapResponser) Response(connInfo xdns.ConnectionInfo) ([]byte, error TypeBitMaps: []dns.DNSType{dns.DNSRRTypeA}, } rr = dns.DNSResourceRecord{ - Name: upperName, + Name: *dns.NewDNSName(upperName), Type: dns.DNSRRTypeNSEC, Class: dns.DNSClassIN, TTL: 86400, @@ -1166,7 +1164,7 @@ func InitMaterial(name string, algo dns.DNSSECAlgorithm, kskPublic, kskPriv []by } zskRR := dns.DNSResourceRecord{ - Name: name, + Name: *dns.NewDNSName(name), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, @@ -1189,7 +1187,7 @@ func InitMaterial(name string, algo dns.DNSSECAlgorithm, kskPublic, kskPriv []by } kskRR := dns.DNSResourceRecord{ - Name: name, + Name: *dns.NewDNSName(name), Type: dns.DNSRRTypeDNSKEY, Class: dns.DNSClassIN, TTL: 86400, diff --git a/responser.go b/responser.go index 82c30ef..ba66352 100644 --- a/responser.go +++ b/responser.go @@ -46,13 +46,13 @@ func (d *DullResponser) Response(connInfo ConnectionInfo) ([]byte, error) { resp := InitNXDOMAIN(qry) // 将可能启用0x20混淆的查询名称转换为小写 - qName := strings.ToLower(qry.Question[0].Name) + qName := strings.ToLower(qry.Question[0].Name.DomainName) // 如果查询类型为 A,则回复 A 记录 if qry.Question[0].Type == dns.DNSRRTypeA { resp.Answer = []dns.DNSResourceRecord{ { - Name: qName, + Name: *dns.NewDNSName(qName), Type: qry.Question[0].Type, Class: qry.Question[0].Class, TTL: 3600, @@ -190,11 +190,11 @@ func (d *DNSSECResponser) Response(connInfo ConnectionInfo) (dns.DNSMessage, err // 如果查询类型为 A,则回复 A 记录 if qType == dns.DNSRRTypeA { // 将可能启用0x20混淆的查询名称转换为小写 - qName := strings.ToLower(qry.Question[0].Name) + qName := strings.ToLower(qry.Question[0].Name.DomainName) // 生成 A 记录 rr := dns.DNSResourceRecord{ - Name: qName, + Name: *dns.NewDNSName(qName), Type: dns.DNSRRTypeA, Class: dns.DNSClassIN, TTL: 86400, @@ -280,7 +280,7 @@ type CryptoMaterial struct { // 目前尚未实现 规范化排序 功能,需要确保传入回复信息中的记录已经按照规范化排序, // 否则会导致签名失败。 func EnableDNSSEC(qry dns.DNSMessage, resp *dns.DNSMessage, dConf DNSSECConfig, dMap *sync.Map) { - qName := strings.ToLower(qry.Question[0].Name) + qName := strings.ToLower(qry.Question[0].Name.DomainName) upperName := dns.GetUpperDomainName(&qName) // 获取 DNSSEC 材料 dMat := GetDNSSECMaterial(upperName, dMap, dConf) @@ -321,7 +321,7 @@ func SignSection(section dns.DNSResponseSection, crypto CryptoMaterial) []dns.DN if rr.Type == dns.DNSRRTypeRRSIG { continue } - rid := rr.Name + rr.Type.String() + rr.Class.String() + rid := rr.Name.DomainName + rr.Type.String() + rr.Class.String() rMap[rid] = append(rMap[rid], rr) } for _, rrset := range rMap { @@ -400,7 +400,7 @@ func GetDNSSECMaterial(zName string, dMap *sync.Map, dConf DNSSECConfig) DNSSECM func EstablishCoT(qry dns.DNSMessage, resp *dns.DNSMessage, dConf DNSSECConfig, dMap *sync.Map) error { // 提取查询类型和查询名称 qType := qry.Question[0].Type - qName := strings.ToLower(qry.Question[0].Name) + qName := strings.ToLower(qry.Question[0].Name.DomainName) rrset := []dns.DNSResourceRecord{} if qType == dns.DNSRRTypeDNSKEY {